From 2d33681a0b39c5571ffeb390f3ff26f51aac6704 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 2 Aug 2023 20:28:30 +0530 Subject: [PATCH 001/196] add collections to config file --- app/config/collections.php | 606 +++++++++++++++++++++++++++++++++++++ composer.lock | 22 +- 2 files changed, 617 insertions(+), 11 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 6a608fe5f5..e769464734 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -3664,6 +3664,612 @@ $collections = [ ], ], ], + + 'providers' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('providers'), + 'name' => 'Providers', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('name'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('provider'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('type'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('credentials'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => ['json', 'encrypt'], + ] + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_provider'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['provider'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_name'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['name'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ] + ], + ], + 'messages' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('messages'), + 'name' => 'Messages', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('type'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('data'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['json'], + ], + [ + '$id' => ID::custom('to'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16834, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('deliveryTime'), + 'type' => Database::VAR_DATETIME, + 'format' => '', + 'size' => 0, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['datetime'], + ], + [ + '$id' => ID::custom('deliveryError'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('deliveredTo'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('delivered'), + 'type' => Database::VAR_BOOLEAN, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => true, + 'default' => false, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerInternalId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_search'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['search'], + 'lengths' => [], + 'orders' => [], + ], + ], + ], + 'topics' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('topics'), + 'name' => 'Topics', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('name'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('description'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerInternalId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_name'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['name'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_description'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['description'], + 'lengths' => [], + 'orders' => [], + ], + ], + ], + 'subscribers' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('subscribers'), + 'name' => 'Subscribers', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('targetId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('targetInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('topicId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('topicInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userInternalId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_targetId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['targetId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_targetInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['targetInternalId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_topicId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['topicId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_topicInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['topicInternalId'], + 'lengths' => [], + 'orders' => [], + ] + ], + ], + 'targets' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('targets'), + 'name' => 'Targets', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerType'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('identifier'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userInternalId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_providerInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerInternalId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_providerType'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerType'], + 'lengths' => [], + 'orders' => [], + ], + ], + ] ]; return $collections; diff --git a/composer.lock b/composer.lock index b01599337a..772b188da7 100644 --- a/composer.lock +++ b/composer.lock @@ -994,16 +994,16 @@ }, { "name": "matomo/device-detector", - "version": "6.1.3", + "version": "6.1.4", "source": { "type": "git", "url": "https://github.com/matomo-org/device-detector.git", - "reference": "3e0fac7e77f3faadc3858fea9f5fa7efeb9cf239" + "reference": "74f6c4f6732b3ad6cdf25560746841d522969112" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/3e0fac7e77f3faadc3858fea9f5fa7efeb9cf239", - "reference": "3e0fac7e77f3faadc3858fea9f5fa7efeb9cf239", + "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/74f6c4f6732b3ad6cdf25560746841d522969112", + "reference": "74f6c4f6732b3ad6cdf25560746841d522969112", "shasum": "" }, "require": { @@ -1059,7 +1059,7 @@ "source": "https://github.com/matomo-org/matomo", "wiki": "https://dev.matomo.org/" }, - "time": "2023-06-06T11:58:07+00:00" + "time": "2023-08-02T08:48:53+00:00" }, { "name": "mongodb/mongodb", @@ -4758,16 +4758,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { @@ -4810,7 +4810,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" }, "funding": [ { @@ -4818,7 +4818,7 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2023-08-02T09:26:13+00:00" }, { "name": "sebastian/lines-of-code", From 13e73d85583b96005a4f59cd8e8154f22c77b5c4 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 4 Aug 2023 14:55:03 +0530 Subject: [PATCH 002/196] add scopes required for messaging service --- app/config/scopes.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/config/scopes.php b/app/config/scopes.php index e058454917..fe9e258f83 100644 --- a/app/config/scopes.php +++ b/app/config/scopes.php @@ -76,4 +76,34 @@ return [ // List of publicly visible scopes 'health.read' => [ 'description' => 'Access to read your project\'s health status', ], + 'providers.read' => [ + 'description' => 'Access to read your project\'s providers', + ], + 'providers.write' => [ + 'description' => 'Access to create, update, and delete your project\'s providers', + ], + 'messages.read' => [ + 'description' => 'Access to read your project\'s messages', + ], + 'messages.write' => [ + 'description' => 'Access to create, update, and delete your project\'s messages', + ], + 'topics.read' => [ + 'description' => 'Access to read your project\'s topics', + ], + 'topics.write' => [ + 'description' => 'Access to create, update, and delete your project\'s topics', + ], + 'subscribers.read' => [ + 'description' => 'Access to read your project\'s subscribers', + ], + 'subscribers.write' => [ + 'description' => 'Access to create, update, and delete your project\'s subscribers', + ], + 'targets.read' => [ + 'description' => 'Access to read your project\'s targets', + ], + 'targets.write' => [ + 'description' => 'Access to create, update, and delete your project\'s targets', + ], ]; From 19fd30d6d8ff4fa191d93276a5cdc4658eb0d747 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 4 Aug 2023 15:01:26 +0530 Subject: [PATCH 003/196] fix lint issues --- app/config/scopes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/scopes.php b/app/config/scopes.php index fe9e258f83..f62090cdd5 100644 --- a/app/config/scopes.php +++ b/app/config/scopes.php @@ -105,5 +105,5 @@ return [ // List of publicly visible scopes ], 'targets.write' => [ 'description' => 'Access to create, update, and delete your project\'s targets', - ], + ], ]; From 867f3e8c0869083e9a59795c397f315683b00afa Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 4 Aug 2023 19:00:08 +0530 Subject: [PATCH 004/196] adds messaging providers rename providers.php to authProviders.php --- .../{providers.php => authProviders.php} | 0 app/config/messagingProviders.php | 299 ++++++++++++++++++ app/init.php | 3 +- 3 files changed, 301 insertions(+), 1 deletion(-) rename app/config/{providers.php => authProviders.php} (100%) create mode 100644 app/config/messagingProviders.php diff --git a/app/config/providers.php b/app/config/authProviders.php similarity index 100% rename from app/config/providers.php rename to app/config/authProviders.php diff --git a/app/config/messagingProviders.php b/app/config/messagingProviders.php new file mode 100644 index 0000000000..c60a80d7a0 --- /dev/null +++ b/app/config/messagingProviders.php @@ -0,0 +1,299 @@ + [ + 'mailchimp' => [ + 'name' => 'Mailchimp', + 'developers' => 'https://mailchimp.com/developer/marketing/api/', + 'icon' => 'icon-mailchimp', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'mailgun' => [ + 'name' => 'Mailgun', + 'developers' => 'https://documentation.mailgun.com/', + 'icon' => 'icon-mailgun', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'mailjet' => [ + 'name' => 'Mailjet', + 'developers' => 'https://dev.mailjet.com/', + 'icon' => 'icon-mailjet', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'postmark' => [ + 'name' => 'Postmark', + 'developers' => 'https://postmarkapp.com/developer', + 'icon' => 'icon-postmark', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sendgrid' => [ + 'name' => 'Sendgrid', + 'developers' => 'https://docs.sendgrid.com/api-reference/how-to-use-the-sendgrid-v3-api/', + 'icon' => 'icon-sendgrid', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sendinblue' => [ + 'name' => 'SendinBlue', + 'developers' => 'https://developers.sendinblue.com/', + 'icon' => 'icon-sendinblue', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'mailslurp' => [ + 'name' => 'MailSlurp', + 'developers' => 'https://www.mailslurp.com/docs/', + 'icon' => 'icon-mailslurp', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'elasticemail' => [ + 'name' => 'ElasticEmail', + 'developers' => 'https://api.elasticemail.com/public/help', + 'icon' => 'icon-elasticemail', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'ses' => [ + 'name' => 'SES', + 'developers' => 'https://docs.aws.amazon.com/ses/latest/APIReference/', + 'icon' => 'icon-ses', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + ], + 'sms' => [ + 'africastalking' => [ + 'name' => 'Africa\'s Talking', + 'developers' => 'https://developers.africastalking.com/', + 'icon' => 'icon-africastalking', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'clickatell' => [ + 'name' => 'Clickatell', + 'developers' => 'https://www.clickatell.com/developers/api-docs/', + 'icon' => 'icon-clickatell', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'infobip' => [ + 'name' => 'Infobip', + 'developers' => 'https://www.infobip.com/docs/', + 'icon' => 'icon-infobip', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'msg91' => [ + 'name' => 'Msg91', + 'developers' => 'https://docs.msg91.com/reference/overview', + 'icon' => 'icon-msg91', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'plivo' => [ + 'name' => 'Plivo', + 'developers' => 'https://developers.plivo.com/', + 'icon' => 'icon-plivo', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sinch' => [ + 'name' => 'Sinch', + 'developers' => 'https://developers.sinch.com/', + 'icon' => 'icon-sinch', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sms77' => [ + 'name' => 'Sms77', + 'developers' => 'https://sms77.io/docs/gateway/', + 'icon' => 'icon-sms77', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'telesign' => [ + 'name' => 'Telesign', + 'developers' => 'https://developer.telesign.com/enterprise/docs', + 'icon' => 'icon-telesign', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'textmagic' => [ + 'name' => 'TextMagic', + 'developers' => 'https://www.textmagic.com/docs/api/', + 'icon' => 'icon-twilio', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'twilio' => [ + 'name' => 'Twilio', + 'developers' => 'https://www.twilio.com/docs/sms', + 'icon' => 'icon-twilio', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'twilio-notify' => [ + 'name' => 'Twilio Notify', + 'developers' => 'https://www.twilio.com/docs/notify', + 'icon' => 'icon-twilio', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'vonage' => [ + 'name' => 'Vonage', + 'developers' => 'https://developer.nexmo.com/', + 'icon' => 'icon-vonage', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + ], + 'push' => [ + 'apns' => [ + 'name' => 'APNS', + 'developers' => 'https://developer.apple.com/documentation/usernotifications', + 'icon' => 'icon-apns', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'fcm' => [ + 'name' => 'FCM', + 'developers' => 'https://firebase.google.com/docs/cloud-messaging', + 'icon' => 'icon-fcm', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'one_signal' => [ + 'name' => 'OneSignal', + 'developers' => 'https://documentation.onesignal.com/docs', + 'icon' => 'icon-onesignal', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'pushbullet' => [ + 'name' => 'PushBullet', + 'developers' => 'https://docs.pushbullet.com/', + 'icon' => 'icon-pushbullet', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'pusher' => [ + 'name' => 'Pusher', + 'developers' => 'https://pusher.com/docs', + 'icon' => 'icon-pusher', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'pushwoosh' => [ + 'name' => 'Pushwoosh', + 'developers' => 'https://www.pushwoosh.com/docs/', + 'icon' => 'icon-pushwoosh', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'urban_airship' => [ + 'name' => 'Urban Airship', + 'developers' => 'https://docs.airship.com/api/', + 'icon' => 'icon-urbanairship', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'web_push' => [ + 'name' => 'WebPush', + 'developers' => 'https://developer.mozilla.org/en-US/docs/Web/API/Push_API', + 'icon' => 'icon-webpush', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + ] +]; diff --git a/app/init.php b/app/init.php index 6fb707acb0..1464d20c3d 100644 --- a/app/init.php +++ b/app/init.php @@ -188,7 +188,7 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION)); Config::load('events', __DIR__ . '/config/events.php'); Config::load('auth', __DIR__ . '/config/auth.php'); Config::load('errors', __DIR__ . '/config/errors.php'); -Config::load('providers', __DIR__ . '/config/providers.php'); +Config::load('providers', __DIR__ . '/config/authProviders.php'); Config::load('platforms', __DIR__ . '/config/platforms.php'); Config::load('collections', __DIR__ . '/config/collections.php'); Config::load('runtimes', __DIR__ . '/config/runtimes.php'); @@ -212,6 +212,7 @@ Config::load('storage-logos', __DIR__ . '/config/storage/logos.php'); Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php'); Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php'); Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php'); +Config::load('messagingProviders', __DIR__ . '/config/messagingProviders.php'); $user = App::getEnv('_APP_REDIS_USER', ''); $pass = App::getEnv('_APP_REDIS_PASS', ''); From 4ca798f4d7bd5181504d43d828b475af00c34c15 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 4 Aug 2023 19:01:55 +0530 Subject: [PATCH 005/196] fix lint issues --- app/config/messagingProviders.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/config/messagingProviders.php b/app/config/messagingProviders.php index c60a80d7a0..a33665196b 100644 --- a/app/config/messagingProviders.php +++ b/app/config/messagingProviders.php @@ -1,4 +1,5 @@ [ 'mailchimp' => [ From 5baa0d674ae2d1af4a1622f65a4cd4fb7d8755ff Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 7 Aug 2023 14:17:02 +0530 Subject: [PATCH 006/196] rename providers.php to authProviders.php in docs and test --- docs/tutorials/add-oauth2-provider.md | 6 +++--- tests/e2e/Services/Projects/ProjectsConsoleClientTest.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/add-oauth2-provider.md b/docs/tutorials/add-oauth2-provider.md index 4aa20649ca..93698d7b64 100644 --- a/docs/tutorials/add-oauth2-provider.md +++ b/docs/tutorials/add-oauth2-provider.md @@ -37,7 +37,7 @@ Finally, you will need to create a `feat-XXX-YYY-oauth` branch based on the `mas The first step in adding a new OAuth2 provider is to add it to the list of providers located at: ``` -app/config/providers.php +app/config/authProviders.php ``` Make sure to fill in all data needed and that your provider array key name: @@ -45,7 +45,7 @@ Make sure to fill in all data needed and that your provider array key name: - is in [`camelCase`](https://en.wikipedia.org/wiki/Camel_case) format - has no spaces or special characters -> Please make sure to keep the list of providers in `providers.php` in the alphabetical order A-Z. +> Please make sure to keep the list of providers in `authProviders.php` in the alphabetical order A-Z. ### 2.2 Add Provider Logo @@ -199,7 +199,7 @@ If you need any help with the contribution, feel free to head over to [our Disco If your OAuth provider requires special configuration apart from `clientId` and `clientSecret` you can create a custom form. Currently this is being realized through putting all custom fields as JSON into the `clientSecret` field to keep the project API stable. You can implement your custom form following these steps: -1. Add your custom form in `app/views/console/users/oauth/[PROVIDER].phtml`. Below is a template you can use. Add the filename to `app/config/providers.php`. +1. Add your custom form in `app/views/console/users/oauth/[PROVIDER].phtml`. Below is a template you can use. Add the filename to `app/config/authProviders.php`. ```php Date: Mon, 7 Aug 2023 15:54:00 +0530 Subject: [PATCH 007/196] rename provider param in config --- app/config/collections.php | 2 +- app/controllers/api/account.php | 10 ++-- app/controllers/api/projects.php | 2 +- app/controllers/api/users.php | 2 +- app/init.php | 2 +- composer.lock | 58 +++++++++---------- src/Appwrite/Migration/Version/V15.php | 2 +- src/Appwrite/Migration/Version/V16.php | 2 +- .../Utopia/Response/Model/Project.php | 2 +- 9 files changed, 41 insertions(+), 41 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 6a608fe5f5..0c7e6e0a12 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -5,7 +5,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Helpers\ID; -$providers = Config::getParam('providers', []); +$providers = Config::getParam('authProviders', []); $auth = Config::getParam('auth', []); /** diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index bb19e2222d..d525e09da4 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -280,7 +280,7 @@ App::get('/v1/account/sessions/oauth2/:provider') ->label('sdk.methodType', 'webAuth') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('providers'), fn($node) => (!$node['mock'])))) . '.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('authProviders'), fn($node) => (!$node['mock'])))) . '.') ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. 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']) ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. 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']) ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) @@ -338,7 +338,7 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->label('scope', 'public') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048, 0), 'OAuth2 code.', true) ->param('state', '', new Text(2048), 'Login state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) @@ -371,7 +371,7 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->label('origin', '*') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048, 0), 'OAuth2 code.', true) ->param('state', '', new Text(2048), 'Login state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) @@ -410,7 +410,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('docs', false) ->label('usage.metric', 'sessions.{scope}.requests.create') ->label('usage.params', ['provider:{request.provider}']) - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048, 0), 'OAuth2 code.', true) ->param('state', '', new Text(2048), 'OAuth2 state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) @@ -438,7 +438,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } - $providers = Config::getParam('providers'); + $providers = Config::getParam('authProviders'); $providerName = $providers[$provider]['name'] ?? ''; /** @var Appwrite\Auth\OAuth2 $oauth2 */ diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 80cc111695..0c628fdd78 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -531,7 +531,7 @@ App::patch('/v1/projects/:projectId/oauth2') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'Provider Name') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'Provider Name') ->param('appId', null, new Text(256), 'Provider app ID. Max length: 256 chars.', true) ->param('secret', null, new text(512), 'Provider secret key. Max length: 512 chars.', true) ->param('enabled', null, new Boolean(), 'Provider status. Set to \'false\' to disable new session creation.', true) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 21c84e8a07..2803f33be6 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1140,7 +1140,7 @@ App::get('/v1/users/usage') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_USAGE_USERS) ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true) - ->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('providers', [])))), true), 'Provider Name.', true) + ->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('authProviders', [])))), true), 'Provider Name.', true) ->inject('response') ->inject('dbForProject') ->inject('register') diff --git a/app/init.php b/app/init.php index 1464d20c3d..8c799163b8 100644 --- a/app/init.php +++ b/app/init.php @@ -188,7 +188,7 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION)); Config::load('events', __DIR__ . '/config/events.php'); Config::load('auth', __DIR__ . '/config/auth.php'); Config::load('errors', __DIR__ . '/config/errors.php'); -Config::load('providers', __DIR__ . '/config/authProviders.php'); +Config::load('authProviders', __DIR__ . '/config/authProviders.php'); Config::load('platforms', __DIR__ . '/config/platforms.php'); Config::load('collections', __DIR__ . '/config/collections.php'); Config::load('runtimes', __DIR__ . '/config/runtimes.php'); diff --git a/composer.lock b/composer.lock index 7bd2b3a78a..5f02dacceb 100644 --- a/composer.lock +++ b/composer.lock @@ -607,16 +607,16 @@ }, { "name": "guzzlehttp/promises", - "version": "2.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6" + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/3a494dc7dc1d7d12e511890177ae2d0e6c107da6", - "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6", + "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d", + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d", "shasum": "" }, "require": { @@ -670,7 +670,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.0" + "source": "https://github.com/guzzle/promises/tree/2.0.1" }, "funding": [ { @@ -686,20 +686,20 @@ "type": "tidelift" } ], - "time": "2023-05-21T13:50:22+00:00" + "time": "2023-08-03T15:11:55+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.5.0", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6" + "reference": "8bd7c33a0734ae1c5d074360512beb716bef3f77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/8bd7c33a0734ae1c5d074360512beb716bef3f77", + "reference": "8bd7c33a0734ae1c5d074360512beb716bef3f77", "shasum": "" }, "require": { @@ -786,7 +786,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.5.0" + "source": "https://github.com/guzzle/psr7/tree/2.6.0" }, "funding": [ { @@ -802,7 +802,7 @@ "type": "tidelift" } ], - "time": "2023-04-17T16:11:26+00:00" + "time": "2023-08-03T15:06:02+00:00" }, { "name": "influxdb/influxdb-php", @@ -994,16 +994,16 @@ }, { "name": "matomo/device-detector", - "version": "6.1.3", + "version": "6.1.4", "source": { "type": "git", "url": "https://github.com/matomo-org/device-detector.git", - "reference": "3e0fac7e77f3faadc3858fea9f5fa7efeb9cf239" + "reference": "74f6c4f6732b3ad6cdf25560746841d522969112" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/3e0fac7e77f3faadc3858fea9f5fa7efeb9cf239", - "reference": "3e0fac7e77f3faadc3858fea9f5fa7efeb9cf239", + "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/74f6c4f6732b3ad6cdf25560746841d522969112", + "reference": "74f6c4f6732b3ad6cdf25560746841d522969112", "shasum": "" }, "require": { @@ -1059,7 +1059,7 @@ "source": "https://github.com/matomo-org/matomo", "wiki": "https://dev.matomo.org/" }, - "time": "2023-06-06T11:58:07+00:00" + "time": "2023-08-02T08:48:53+00:00" }, { "name": "mongodb/mongodb", @@ -3785,16 +3785,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.23.0", + "version": "1.23.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "a2b24135c35852b348894320d47b3902a94bc494" + "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a2b24135c35852b348894320d47b3902a94bc494", - "reference": "a2b24135c35852b348894320d47b3902a94bc494", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/846ae76eef31c6d7790fac9bc399ecee45160b26", + "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26", "shasum": "" }, "require": { @@ -3826,9 +3826,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.23.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.1" }, - "time": "2023-07-23T22:17:56+00:00" + "time": "2023-08-03T16:32:59+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4758,16 +4758,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { @@ -4810,7 +4810,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" }, "funding": [ { @@ -4818,7 +4818,7 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2023-08-02T09:26:13+00:00" }, { "name": "sebastian/lines-of-code", diff --git a/src/Appwrite/Migration/Version/V15.php b/src/Appwrite/Migration/Version/V15.php index 60f5fa20ab..b6deb780da 100644 --- a/src/Appwrite/Migration/Version/V15.php +++ b/src/Appwrite/Migration/Version/V15.php @@ -34,7 +34,7 @@ class V15 extends Migration ['email', 'anonymous'], \array_map( fn ($value) => "oauth-" . $value, - \array_keys(Config::getParam('providers', [])) + \array_keys(Config::getParam('authProviders', [])) ) ); diff --git a/src/Appwrite/Migration/Version/V16.php b/src/Appwrite/Migration/Version/V16.php index 1d56b246d6..bee2236dfb 100644 --- a/src/Appwrite/Migration/Version/V16.php +++ b/src/Appwrite/Migration/Version/V16.php @@ -126,7 +126,7 @@ class V16 extends Migration */ $authProviders = $document->getAttribute('authProviders', []); - foreach (Config::getParam('providers') as $provider => $value) { + foreach (Config::getParam('authProviders') as $provider => $value) { if (!$value['enabled']) { continue; } diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 7671d412fb..0fc334abc2 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -315,7 +315,7 @@ class Project extends Model } // Providers - $providers = Config::getParam('providers', []); + $providers = Config::getParam('authProviders', []); $providerValues = $document->getAttribute('authProviders', []); $projectProviders = []; From be1afc61b0a27739a9a6ba8c052271afac3ba03c Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 7 Aug 2023 16:19:55 +0530 Subject: [PATCH 008/196] rename provider model to AuthProvider --- src/Appwrite/Utopia/Response.php | 9 +++++---- .../Model/{Provider.php => AuthProvider.php} | 12 ++++++------ src/Appwrite/Utopia/Response/Model/Project.php | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) rename src/Appwrite/Utopia/Response/Model/{Provider.php => AuthProvider.php} (82%) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index e65f65cd52..902d50b0c7 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -31,6 +31,7 @@ use Appwrite\Utopia\Response\Model\AttributeIP; use Appwrite\Utopia\Response\Model\AttributeURL; use Appwrite\Utopia\Response\Model\AttributeDatetime; use Appwrite\Utopia\Response\Model\AttributeRelationship; +use Appwrite\Utopia\Response\Model\AuthProvider; use Appwrite\Utopia\Response\Model\BaseList; use Appwrite\Utopia\Response\Model\Collection; use Appwrite\Utopia\Response\Model\Database; @@ -205,8 +206,8 @@ class Response extends SwooleResponse public const MODEL_WEBHOOK_LIST = 'webhookList'; public const MODEL_KEY = 'key'; public const MODEL_KEY_LIST = 'keyList'; - public const MODEL_PROVIDER = 'provider'; - public const MODEL_PROVIDER_LIST = 'providerList'; + public const MODEL_AUTH_PROVIDER = 'authProvider'; + public const MODEL_AUTH_PROVIDER_LIST = 'authProviderList'; public const MODEL_PLATFORM = 'platform'; public const MODEL_PLATFORM_LIST = 'platformList'; public const MODEL_DOMAIN = 'domain'; @@ -277,7 +278,7 @@ class Response extends SwooleResponse ->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT, true, false)) ->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK, true, false)) ->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false)) - ->setModel(new BaseList('Providers List', self::MODEL_PROVIDER_LIST, 'platforms', self::MODEL_PROVIDER, true, false)) + ->setModel(new BaseList('Providers List', self::MODEL_AUTH_PROVIDER_LIST, 'platforms', self::MODEL_AUTH_PROVIDER, true, false)) ->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM, true, false)) ->setModel(new BaseList('Domains List', self::MODEL_DOMAIN_LIST, 'domains', self::MODEL_DOMAIN, true, false)) ->setModel(new BaseList('Countries List', self::MODEL_COUNTRY_LIST, 'countries', self::MODEL_COUNTRY)) @@ -334,7 +335,7 @@ class Response extends SwooleResponse ->setModel(new Webhook()) ->setModel(new Key()) ->setModel(new Domain()) - ->setModel(new Provider()) + ->setModel(new AuthProvider()) ->setModel(new Platform()) ->setModel(new Variable()) ->setModel(new Country()) diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/AuthProvider.php similarity index 82% rename from src/Appwrite/Utopia/Response/Model/Provider.php rename to src/Appwrite/Utopia/Response/Model/AuthProvider.php index c589011a46..0171a3c152 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/AuthProvider.php @@ -5,7 +5,7 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; -class Provider extends Model +class AuthProvider extends Model { /** * @var bool @@ -17,13 +17,13 @@ class Provider extends Model $this ->addRule('key', [ 'type' => self::TYPE_STRING, - 'description' => 'Provider.', + 'description' => 'Auth Provider.', 'default' => '', 'example' => 'github', ]) ->addRule('name', [ 'type' => self::TYPE_STRING, - 'description' => 'Provider name.', + 'description' => 'Auth Provider name.', 'default' => '', 'example' => 'GitHub', ]) @@ -41,7 +41,7 @@ class Provider extends Model ]) ->addRule('enabled', [ 'type' => self::TYPE_BOOLEAN, - 'description' => 'Provider is active and can be used to create session.', + 'description' => 'Auth Provider is active and can be used to create session.', 'example' => '', ]) ; @@ -54,7 +54,7 @@ class Provider extends Model */ public function getName(): string { - return 'Provider'; + return 'AuthProvider'; } /** @@ -64,6 +64,6 @@ class Provider extends Model */ public function getType(): string { - return Response::MODEL_PROVIDER; + return Response::MODEL_AUTH_PROVIDER; } } diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 0fc334abc2..cebf951596 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -133,8 +133,8 @@ class Project extends Model 'example' => true, ]) ->addRule('providers', [ - 'type' => Response::MODEL_PROVIDER, - 'description' => 'List of Providers.', + 'type' => Response::MODEL_AUTH_PROVIDER, + 'description' => 'List of Auth Providers.', 'default' => [], 'example' => [new \stdClass()], 'array' => true, From 3e70a19e4fd716b1818f2bd9940a975f199085e4 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 7 Aug 2023 20:56:03 +0530 Subject: [PATCH 009/196] add response models required for messaging service --- src/Appwrite/Utopia/Response.php | 26 +++++ .../Utopia/Response/Model/Message.php | 97 +++++++++++++++++++ .../Utopia/Response/Model/Provider.php | 63 ++++++++++++ .../Utopia/Response/Model/Subsciber.php | 63 ++++++++++++ src/Appwrite/Utopia/Response/Model/Target.php | 70 +++++++++++++ src/Appwrite/Utopia/Response/Model/Topic.php | 64 ++++++++++++ 6 files changed, 383 insertions(+) create mode 100644 src/Appwrite/Utopia/Response/Model/Message.php create mode 100644 src/Appwrite/Utopia/Response/Model/Provider.php create mode 100644 src/Appwrite/Utopia/Response/Model/Subsciber.php create mode 100644 src/Appwrite/Utopia/Response/Model/Target.php create mode 100644 src/Appwrite/Utopia/Response/Model/Topic.php diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 902d50b0c7..37e6d7682b 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -2,6 +2,9 @@ namespace Appwrite\Utopia; +use Appwrite\Utopia\Response\Model\Message; +use Appwrite\Utopia\Response\Model\Subscriber; +use Appwrite\Utopia\Response\Model\Topic; use Exception; use Swoole\Http\Request as SwooleRequest; use Utopia\Swoole\Response as SwooleResponse; @@ -78,6 +81,7 @@ use Appwrite\Utopia\Response\Model\LocaleCode; use Appwrite\Utopia\Response\Model\Mock; // Keep last use Appwrite\Utopia\Response\Model\Provider; use Appwrite\Utopia\Response\Model\Runtime; +use Appwrite\Utopia\Response\Model\Target; use Appwrite\Utopia\Response\Model\TemplateSMS; use Appwrite\Utopia\Response\Model\UsageBuckets; use Appwrite\Utopia\Response\Model\UsageCollection; @@ -180,6 +184,18 @@ class Response extends SwooleResponse public const MODEL_PHONE = 'phone'; public const MODEL_PHONE_LIST = 'phoneList'; + // Messaging + public const MODEL_PROVIDER = 'provider'; + public const MODEL_PROVIDER_LIST = 'providerList'; + public const MODEL_MESSAGE = 'message'; + public const MODEL_MESSAGE_LIST = 'messageList'; + public const MODEL_TOPIC = 'topic'; + public const MODEL_TOPIC_LIST = 'topicList'; + public const MODEL_SUBSCRIBER = 'subscriber'; + public const MODEL_SUBSCRIBER_LIST = 'subscriberList'; + public const MODEL_TARGET = 'target'; + public const MODEL_TARGET_LIST = 'targetList'; + // Teams public const MODEL_TEAM = 'team'; public const MODEL_TEAM_LIST = 'teamList'; @@ -289,6 +305,11 @@ class Response extends SwooleResponse ->setModel(new BaseList('Metric List', self::MODEL_METRIC_LIST, 'metrics', self::MODEL_METRIC, true, false)) ->setModel(new BaseList('Variables List', self::MODEL_VARIABLE_LIST, 'variables', self::MODEL_VARIABLE)) ->setModel(new BaseList('Locale codes list', self::MODEL_LOCALE_CODE_LIST, 'localeCodes', self::MODEL_LOCALE_CODE)) + ->setModel(new BaseList('Provider list', self::MODEL_PROVIDER_LIST, 'providers', self::MODEL_PROVIDER)) + ->setModel(new BaseList('Message list', self::MODEL_MESSAGE_LIST, 'messages', self::MODEL_MESSAGE)) + ->setModel(new BaseList('Topic list', self::MODEL_TOPIC_LIST, 'topics', self::MODEL_TOPIC)) + ->setModel(new BaseList('Subscriber list', self::MODEL_SUBSCRIBER_LIST, 'subscribers', self::MODEL_SUBSCRIBER)) + ->setModel(new BaseList('Target list', self::MODEL_TARGET_LIST, 'targets', self::MODEL_TARGET)) // Entities ->setModel(new Database()) ->setModel(new Collection()) @@ -361,6 +382,11 @@ class Response extends SwooleResponse ->setModel(new TemplateSMS()) ->setModel(new TemplateEmail()) ->setModel(new ConsoleVariables()) + ->setModel(new Provider()) + ->setModel(new Message()) + ->setModel(new Topic()) + ->setModel(new Subscriber()) + ->setModel(new Target()) // Verification // Recovery // Tests (keep last) diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php new file mode 100644 index 0000000000..f8a7913ff6 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -0,0 +1,97 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Message ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('providerId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider Id for the message.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('data', [ + 'type' => self::TYPE_JSON, + 'description' => 'Message Data.', + 'default' => '', + 'required' => false, + 'example' => '', + ]) + ->addRule('to', [ + 'type' => self::TYPE_STRING, + 'description' => 'Recipient of message.', + 'default' => '', + 'example' => ['user-1'], + ]) + ->addRule('deliveryTime', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Recipient of message.', + 'required' => false, + 'default' => DateTime::now(), + 'example' => DateTime::now(), + ]) + ->addRule('deliveryError', [ + 'type' => self::TYPE_STRING, + 'description' => 'Delivery error if any.', + 'required' => false, + 'default' => '', + 'example' => 'Provider not valid.', + ]) + ->addRule('deliveredTo', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of recipients the message was delivered to.', + 'default' => '', + 'example' => 1, + ]) + ->addRule('delivered', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Status of delivery.', + 'default' => '', + 'example' => true, + ]) + ->addRule('search', [ + 'type' => self::TYPE_STRING, + 'description' => 'Field that can be used for searching message.', + 'default' => '', + 'example' => 'Hello everyone', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Message'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_MESSAGE; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php new file mode 100644 index 0000000000..6bd43261ad --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -0,0 +1,63 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'The user-given name for the provider instance.', + 'default' => '', + 'example' => 'Mailgun', + ]) + ->addRule('provider', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider name setup in Utopia.', + 'default' => '', + 'example' => 'mailgun', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Type of provider.', + 'default' => '', + 'example' => 'sms', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Provider'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_PROVIDER; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Subsciber.php b/src/Appwrite/Utopia/Response/Model/Subsciber.php new file mode 100644 index 0000000000..a72146ccf3 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Subsciber.php @@ -0,0 +1,63 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Subscriber ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('userId', [ + 'type' => self::TYPE_STRING, + 'description' => 'User ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('targetId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('topicId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Topic ID.', + 'default' => '', + 'example' => '259125845563242502', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Subscriber'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_SUBSCRIBER; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php new file mode 100644 index 0000000000..1ecc0126cc --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -0,0 +1,70 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('userId', [ + 'type' => self::TYPE_STRING, + 'description' => 'User ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('providerId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider ID.', + 'required' => false, + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('providerType', [ + 'type' => self::TYPE_STRING, + 'description' => 'The type of provider supported by this target.', + 'default' => '', + 'example' => 'sms', + ]) + ->addRule('identifier', [ + 'type' => self::TYPE_STRING, + 'description' => 'The target identifier.', + 'default' => '', + 'example' => 'token', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Target'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_TARGET; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Topic.php b/src/Appwrite/Utopia/Response/Model/Topic.php new file mode 100644 index 0000000000..d22364f917 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Topic.php @@ -0,0 +1,64 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Topic ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('providerId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'The name of the topic.', + 'default' => '', + 'example' => 'events', + ]) + ->addRule('description', [ + 'type' => self::TYPE_STRING, + 'description' => 'Description of the topic.', + 'default' => '', + 'required' => false, + 'example' => 'All events related messages will be sent to this topic.', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Topic'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_TOPIC; + } +} From d7f806e67110cecce9c0e98e36b14ccb280cef4e Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 7 Aug 2023 21:01:25 +0530 Subject: [PATCH 010/196] fix lint issuesl --- src/Appwrite/Utopia/Response.php | 2 +- .../Utopia/Response/Model/Message.php | 62 +++++++++---------- .../Utopia/Response/Model/Provider.php | 42 ++++++------- .../Utopia/Response/Model/Subsciber.php | 42 ++++++------- src/Appwrite/Utopia/Response/Model/Target.php | 46 +++++++------- src/Appwrite/Utopia/Response/Model/Topic.php | 42 ++++++------- 6 files changed, 118 insertions(+), 118 deletions(-) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 37e6d7682b..97b870bf61 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -309,7 +309,7 @@ class Response extends SwooleResponse ->setModel(new BaseList('Message list', self::MODEL_MESSAGE_LIST, 'messages', self::MODEL_MESSAGE)) ->setModel(new BaseList('Topic list', self::MODEL_TOPIC_LIST, 'topics', self::MODEL_TOPIC)) ->setModel(new BaseList('Subscriber list', self::MODEL_SUBSCRIBER_LIST, 'subscribers', self::MODEL_SUBSCRIBER)) - ->setModel(new BaseList('Target list', self::MODEL_TARGET_LIST, 'targets', self::MODEL_TARGET)) + ->setModel(new BaseList('Target list', self::MODEL_TARGET_LIST, 'targets', self::MODEL_TARGET)) // Entities ->setModel(new Database()) ->setModel(new Collection()) diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index f8a7913ff6..28536012ab 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -11,87 +11,87 @@ class Message extends Model /** * @var bool */ - protected bool $public = false; + protected bool $public = false; - public function __construct() - { - $this - ->addRule('$id', [ + public function __construct() + { + $this + ->addRule('$id', [ 'type' => self::TYPE_STRING, 'description' => 'Message ID.', 'default' => '', 'example' => '5e5ea5c16897e', - ]) - ->addRule('providerId', [ + ]) + ->addRule('providerId', [ 'type' => self::TYPE_STRING, 'description' => 'Provider Id for the message.', 'default' => '', 'example' => '5e5ea5c16897e', - ]) - ->addRule('data', [ + ]) + ->addRule('data', [ 'type' => self::TYPE_JSON, 'description' => 'Message Data.', 'default' => '', 'required' => false, 'example' => '', - ]) - ->addRule('to', [ + ]) + ->addRule('to', [ 'type' => self::TYPE_STRING, 'description' => 'Recipient of message.', 'default' => '', 'example' => ['user-1'], - ]) - ->addRule('deliveryTime', [ + ]) + ->addRule('deliveryTime', [ 'type' => self::TYPE_DATETIME, 'description' => 'Recipient of message.', 'required' => false, 'default' => DateTime::now(), 'example' => DateTime::now(), - ]) - ->addRule('deliveryError', [ + ]) + ->addRule('deliveryError', [ 'type' => self::TYPE_STRING, 'description' => 'Delivery error if any.', 'required' => false, 'default' => '', 'example' => 'Provider not valid.', - ]) - ->addRule('deliveredTo', [ + ]) + ->addRule('deliveredTo', [ 'type' => self::TYPE_INTEGER, 'description' => 'Number of recipients the message was delivered to.', 'default' => '', 'example' => 1, - ]) - ->addRule('delivered', [ + ]) + ->addRule('delivered', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Status of delivery.', 'default' => '', 'example' => true, - ]) - ->addRule('search', [ + ]) + ->addRule('search', [ 'type' => self::TYPE_STRING, 'description' => 'Field that can be used for searching message.', 'default' => '', 'example' => 'Hello everyone', - ]); - } + ]); + } /** * Get Name * * @return string */ - public function getName(): string - { - return 'Message'; - } + public function getName(): string + { + return 'Message'; + } /** * Get Type * * @return string */ - public function getType(): string - { - return Response::MODEL_MESSAGE; - } + public function getType(): string + { + return Response::MODEL_MESSAGE; + } } diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index 6bd43261ad..fcaacd87c0 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -10,54 +10,54 @@ class Provider extends Model /** * @var bool */ - protected bool $public = false; + protected bool $public = false; - public function __construct() - { - $this - ->addRule('$id', [ + public function __construct() + { + $this + ->addRule('$id', [ 'type' => self::TYPE_STRING, 'description' => 'Provider ID.', 'default' => '', 'example' => '5e5ea5c16897e', - ]) - ->addRule('name', [ + ]) + ->addRule('name', [ 'type' => self::TYPE_STRING, 'description' => 'The user-given name for the provider instance.', 'default' => '', 'example' => 'Mailgun', - ]) - ->addRule('provider', [ + ]) + ->addRule('provider', [ 'type' => self::TYPE_STRING, 'description' => 'Provider name setup in Utopia.', 'default' => '', 'example' => 'mailgun', - ]) - ->addRule('type', [ + ]) + ->addRule('type', [ 'type' => self::TYPE_STRING, 'description' => 'Type of provider.', 'default' => '', 'example' => 'sms', - ]); - } + ]); + } /** * Get Name * * @return string */ - public function getName(): string - { - return 'Provider'; - } + public function getName(): string + { + return 'Provider'; + } /** * Get Type * * @return string */ - public function getType(): string - { - return Response::MODEL_PROVIDER; - } + public function getType(): string + { + return Response::MODEL_PROVIDER; + } } diff --git a/src/Appwrite/Utopia/Response/Model/Subsciber.php b/src/Appwrite/Utopia/Response/Model/Subsciber.php index a72146ccf3..11905180e3 100644 --- a/src/Appwrite/Utopia/Response/Model/Subsciber.php +++ b/src/Appwrite/Utopia/Response/Model/Subsciber.php @@ -10,54 +10,54 @@ class Subscriber extends Model /** * @var bool */ - protected bool $public = false; + protected bool $public = false; - public function __construct() - { - $this - ->addRule('$id', [ + public function __construct() + { + $this + ->addRule('$id', [ 'type' => self::TYPE_STRING, 'description' => 'Subscriber ID.', 'default' => '', 'example' => '259125845563242502', - ]) - ->addRule('userId', [ + ]) + ->addRule('userId', [ 'type' => self::TYPE_STRING, 'description' => 'User ID.', 'default' => '', 'example' => '259125845563242502', - ]) - ->addRule('targetId', [ + ]) + ->addRule('targetId', [ 'type' => self::TYPE_STRING, 'description' => 'Target ID.', 'default' => '', 'example' => '259125845563242502', - ]) - ->addRule('topicId', [ + ]) + ->addRule('topicId', [ 'type' => self::TYPE_STRING, 'description' => 'Topic ID.', 'default' => '', 'example' => '259125845563242502', - ]); - } + ]); + } /** * Get Name * * @return string */ - public function getName(): string - { - return 'Subscriber'; - } + public function getName(): string + { + return 'Subscriber'; + } /** * Get Type * * @return string */ - public function getType(): string - { - return Response::MODEL_SUBSCRIBER; - } + public function getType(): string + { + return Response::MODEL_SUBSCRIBER; + } } diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php index 1ecc0126cc..8bc90731ba 100644 --- a/src/Appwrite/Utopia/Response/Model/Target.php +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -10,61 +10,61 @@ class Target extends Model /** * @var bool */ - protected bool $public = false; + protected bool $public = false; - public function __construct() - { - $this - ->addRule('$id', [ + public function __construct() + { + $this + ->addRule('$id', [ 'type' => self::TYPE_STRING, 'description' => 'Target ID.', 'default' => '', 'example' => '259125845563242502', - ]) - ->addRule('userId', [ + ]) + ->addRule('userId', [ 'type' => self::TYPE_STRING, 'description' => 'User ID.', 'default' => '', 'example' => '259125845563242502', - ]) - ->addRule('providerId', [ + ]) + ->addRule('providerId', [ 'type' => self::TYPE_STRING, 'description' => 'Provider ID.', 'required' => false, 'default' => '', 'example' => '259125845563242502', - ]) - ->addRule('providerType', [ + ]) + ->addRule('providerType', [ 'type' => self::TYPE_STRING, 'description' => 'The type of provider supported by this target.', 'default' => '', 'example' => 'sms', - ]) - ->addRule('identifier', [ + ]) + ->addRule('identifier', [ 'type' => self::TYPE_STRING, 'description' => 'The target identifier.', 'default' => '', 'example' => 'token', - ]); - } + ]); + } /** * Get Name * * @return string */ - public function getName(): string - { - return 'Target'; - } + public function getName(): string + { + return 'Target'; + } /** * Get Type * * @return string */ - public function getType(): string - { - return Response::MODEL_TARGET; - } + public function getType(): string + { + return Response::MODEL_TARGET; + } } diff --git a/src/Appwrite/Utopia/Response/Model/Topic.php b/src/Appwrite/Utopia/Response/Model/Topic.php index d22364f917..42ecd583af 100644 --- a/src/Appwrite/Utopia/Response/Model/Topic.php +++ b/src/Appwrite/Utopia/Response/Model/Topic.php @@ -10,55 +10,55 @@ class Topic extends Model /** * @var bool */ - protected bool $public = false; + protected bool $public = false; - public function __construct() - { - $this - ->addRule('$id', [ + public function __construct() + { + $this + ->addRule('$id', [ 'type' => self::TYPE_STRING, 'description' => 'Topic ID.', 'default' => '', 'example' => '259125845563242502', - ]) - ->addRule('providerId', [ + ]) + ->addRule('providerId', [ 'type' => self::TYPE_STRING, 'description' => 'Provider ID.', 'default' => '', 'example' => '259125845563242502', - ]) - ->addRule('name', [ + ]) + ->addRule('name', [ 'type' => self::TYPE_STRING, 'description' => 'The name of the topic.', 'default' => '', 'example' => 'events', - ]) - ->addRule('description', [ + ]) + ->addRule('description', [ 'type' => self::TYPE_STRING, 'description' => 'Description of the topic.', 'default' => '', 'required' => false, 'example' => 'All events related messages will be sent to this topic.', - ]); - } + ]); + } /** * Get Name * * @return string */ - public function getName(): string - { - return 'Topic'; - } + public function getName(): string + { + return 'Topic'; + } /** * Get Type * * @return string */ - public function getType(): string - { - return Response::MODEL_TOPIC; - } + public function getType(): string + { + return Response::MODEL_TOPIC; + } } From 296a54d0ce98c9882e2b82a345421e3b74b65fc5 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 14 Aug 2023 21:11:24 +0530 Subject: [PATCH 011/196] adds messages event config and target attribute in user model --- app/config/events.php | 61 ++++++++++++++++++++- src/Appwrite/Utopia/Response/Model/User.php | 7 +++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/app/config/events.php b/app/config/events.php index 55dfad77d0..45bb45fbf8 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -44,6 +44,20 @@ return [ '$description' => 'This event triggers when a verification token for a user is validated.' ], ], + 'targets' => [ + '$model' => Response::MODEL_TARGET, + '$resource' => true, + '$description' => 'This event triggers on any user\'s target event.', + 'create' => [ + '$description' => 'This event triggers when a user\'s target is created.', + ], + 'update' => [ + '$description' => 'This event triggers when a user\'s target is updated.', + ], + 'delete' => [ + '$description' => 'This event triggers when a user\'s target is deleted.', + ], + ], 'create' => [ '$description' => 'This event triggers when a user is created.' ], @@ -236,5 +250,50 @@ return [ 'update' => [ '$description' => 'This event triggers when a function is updated.', ] - ] + ], + 'messages' => [ + '$model' => Response::MODEL_MESSAGE, + '$resource' => true, + '$description' => 'This event triggers on any messaging event.', + 'create' => [ + '$description' => 'This event triggers when a message is created.', + ], + 'providers' => [ + '$model' => Response::MODEL_PROVIDER, + '$resource' => true, + '$description' => 'This event triggers on any provider event.', + 'create' => [ + '$description' => 'This event triggers when a provider is created.', + ], + 'update' => [ + '$description' => 'This event triggers when a provider is updated.', + ], + 'delete' => [ + '$description' => 'This event triggers when a provider is deleted.' + ], + ], + 'topics' => [ + '$model' => Response::MODEL_TOPIC, + '$resource' => true, + '$description' => 'This event triggers on any topic event.', + 'create' => [ + '$description' => 'This event triggers when a provider is created.', + ], + 'delete' => [ + '$description' => 'This event triggers when a provider is deleted.' + ], + 'subscribers' => [ + '$model' => Response::MODEL_SUBSCRIBER, + '$resource' => true, + '$description' => 'This event triggers on any subscriber event.', + 'create' => [ + '$description' => 'This event triggers when a subscriber is created.', + ], + 'delete' => [ + '$description' => 'This event triggers when a subscriber is deleted.' + ], + ], + ], + + ], ]; diff --git a/src/Appwrite/Utopia/Response/Model/User.php b/src/Appwrite/Utopia/Response/Model/User.php index ce2bd6188c..d6988b47f4 100644 --- a/src/Appwrite/Utopia/Response/Model/User.php +++ b/src/Appwrite/Utopia/Response/Model/User.php @@ -120,6 +120,13 @@ class User extends Model 'default' => new \stdClass(), 'example' => ['theme' => 'pink', 'timezone' => 'UTC'], ]) + ->addRule('targets', [ + 'type' => Response::MODEL_TARGET, + 'description' => 'A user-owned message receiver. A single user may have multiple e.g. emails, phones, and a browser. Each target is registered with a single provider.', + 'default' => [], + 'array' => true, + 'example' => [], + ]) ->addRule('accessedAt', [ 'type' => self::TYPE_DATETIME, 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_USER_ACCCESS / 60 / 60 . ' hours.', From 9fc75e553527035e3a54fbd4d493708048ea4494 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 16 Aug 2023 18:48:38 +0530 Subject: [PATCH 012/196] moves messaging collection to common, adds subqueryTargets --- app/config/collections.php | 1227 ++++++++++++++++++------------------ app/init.php | 13 + 2 files changed, 634 insertions(+), 606 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index d1bee47fe9..d884e71527 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -221,6 +221,17 @@ $commonCollections = [ 'array' => false, 'filters' => ['subQueryMemberships'], ], + [ + '$id' => ID::custom('targets'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['subQueryTargets'], + ], [ '$id' => ID::custom('search'), 'type' => Database::VAR_STRING, @@ -1228,6 +1239,616 @@ $commonCollections = [ ], ], ], + + 'providers' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('providers'), + 'name' => 'Providers', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('name'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('provider'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('type'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('credentials'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => ['json', 'encrypt'], + ] + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_provider'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['provider'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_name'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['name'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ] + ], + ], + + 'messages' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('messages'), + 'name' => 'Messages', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('type'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('data'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['json'], + ], + [ + '$id' => ID::custom('to'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16834, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('deliveryTime'), + 'type' => Database::VAR_DATETIME, + 'format' => '', + 'size' => 0, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['datetime'], + ], + [ + '$id' => ID::custom('deliveryError'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('deliveredTo'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('delivered'), + 'type' => Database::VAR_BOOLEAN, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => true, + 'default' => false, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerInternalId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_search'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['search'], + 'lengths' => [], + 'orders' => [], + ], + ], + ], + + 'topics' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('topics'), + 'name' => 'Topics', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('name'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('description'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerInternalId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_name'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['name'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_description'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['description'], + 'lengths' => [], + 'orders' => [], + ], + ], + ], + + 'subscribers' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('subscribers'), + 'name' => 'Subscribers', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('targetId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('targetInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('topicId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('topicInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userInternalId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_targetId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['targetId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_targetInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['targetInternalId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_topicId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['topicId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_topicInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['topicInternalId'], + 'lengths' => [], + 'orders' => [], + ] + ], + ], + + 'targets' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('targets'), + 'name' => 'Targets', + 'attributes' => [ + [ + '$id' => ID::custom('id'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerType'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('identifier'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_id'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['id'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userInternalId'], + 'lengths' => [128], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_providerInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerInternalId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_providerType'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerType'], + 'lengths' => [], + 'orders' => [], + ], + ], + ] ]; $projectCollections = array_merge([ @@ -3878,612 +4499,6 @@ $dbCollections = [ ], ], ], - - 'providers' => [ - '$collection' => ID::custom(DATABASE::METADATA), - '$id' => ID::custom('providers'), - 'name' => 'Providers', - 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('name'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 128, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('provider'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('type'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 128, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('credentials'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 16384, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => ['json', 'encrypt'], - ] - ], - 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_provider'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['provider'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_name'), - 'type' => Database::INDEX_FULLTEXT, - 'attributes' => ['name'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ] - ], - ], - 'messages' => [ - '$collection' => ID::custom(DATABASE::METADATA), - '$id' => ID::custom('messages'), - 'name' => 'Messages', - 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('providerId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('providerInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('type'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 128, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('data'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 16384, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => ['json'], - ], - [ - '$id' => ID::custom('to'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 16834, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => true, - 'filters' => [], - ], - [ - '$id' => ID::custom('deliveryTime'), - 'type' => Database::VAR_DATETIME, - 'format' => '', - 'size' => 0, - 'signed' => false, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => ['datetime'], - ], - [ - '$id' => ID::custom('deliveryError'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 2048, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('deliveredTo'), - 'type' => Database::VAR_INTEGER, - 'format' => '', - 'size' => 0, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('delivered'), - 'type' => Database::VAR_BOOLEAN, - 'format' => '', - 'size' => 0, - 'signed' => true, - 'required' => true, - 'default' => false, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('search'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 16384, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - ], - 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_providerId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_providerInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerInternalId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_search'), - 'type' => Database::INDEX_FULLTEXT, - 'attributes' => ['search'], - 'lengths' => [], - 'orders' => [], - ], - ], - ], - 'topics' => [ - '$collection' => ID::custom(DATABASE::METADATA), - '$id' => ID::custom('topics'), - 'name' => 'Topics', - 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('providerId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('providerInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('name'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 128, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('description'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 2048, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - ], - 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_providerId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_providerInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerInternalId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_name'), - 'type' => Database::INDEX_FULLTEXT, - 'attributes' => ['name'], - 'lengths' => [], - 'orders' => [], - ], - [ - '$id' => ID::custom('_key_description'), - 'type' => Database::INDEX_FULLTEXT, - 'attributes' => ['description'], - 'lengths' => [], - 'orders' => [], - ], - ], - ], - 'subscribers' => [ - '$collection' => ID::custom(DATABASE::METADATA), - '$id' => ID::custom('subscribers'), - 'name' => 'Subscribers', - 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('userId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('userInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('targetId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('targetInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('topicId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('topicInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - ], - 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_userId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_userInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userInternalId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_targetId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['targetId'], - 'lengths' => [], - 'orders' => [], - ], - [ - '$id' => ID::custom('_key_targetInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['targetInternalId'], - 'lengths' => [], - 'orders' => [], - ], - [ - '$id' => ID::custom('_key_topicId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['topicId'], - 'lengths' => [], - 'orders' => [], - ], - [ - '$id' => ID::custom('_key_topicInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['topicInternalId'], - 'lengths' => [], - 'orders' => [], - ] - ], - ], - 'targets' => [ - '$collection' => ID::custom(DATABASE::METADATA), - '$id' => ID::custom('targets'), - 'name' => 'Targets', - 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('userId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('userInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('providerId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('providerInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('providerType'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('identifier'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 2048, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - ], - 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_userId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_userInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userInternalId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_providerId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerId'], - 'lengths' => [], - 'orders' => [], - ], - [ - '$id' => ID::custom('_key_providerInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerInternalId'], - 'lengths' => [], - 'orders' => [], - ], - [ - '$id' => ID::custom('_key_providerType'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerType'], - 'lengths' => [], - 'orders' => [], - ], - ], - ] ]; diff --git a/app/init.php b/app/init.php index 1b74b81bc4..9f3d41ba0a 100644 --- a/app/init.php +++ b/app/init.php @@ -521,6 +521,19 @@ Database::addFilter( } ); +Database::addFilter( + 'subQueryTargets', + function (mixed $value) { + return null; + }, + function (mixed $value, Document $document, Database $database) { + return Authorization::skip(fn() => $database + ->find('targets', [ + Query::equal('userInternalId', [$document->getInternalId()]), + Query::limit(APP_LIMIT_SUBQUERY), + ])); + } +); /** * DB Formats */ From c7dec3762b2bc85be3973adbdca586322af4dba5 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 16 Aug 2023 20:13:38 +0530 Subject: [PATCH 013/196] Adds getTarget and list targets controller to user and account --- app/config/errors.php | 5 ++ app/controllers/api/account.php | 50 +++++++++++++++ app/controllers/api/users.php | 62 +++++++++++++++++++ src/Appwrite/Extend/Exception.php | 1 + .../Utopia/Response/Model/BaseList.php | 2 +- 5 files changed, 119 insertions(+), 1 deletion(-) diff --git a/app/config/errors.php b/app/config/errors.php index ed1a9f0aa2..5006df0e89 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -230,6 +230,11 @@ return [ 'description' => 'OAuth2 provider returned some error.', 'code' => 424, ], + Exception::USER_TARGET_NOT_FOUND => [ + 'name' => Exception::USER_TARGET_NOT_FOUND, + 'description' => 'The current user target could not be found.', + 'code' => 404, + ], /** Teams */ Exception::TEAM_NOT_FOUND => [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index ce06a807fb..0e69ccdcd9 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1653,6 +1653,29 @@ App::get('/v1/account/logs') ]), Response::MODEL_LOG_LIST); }); +App::get('/v1/account/targets') + ->desc('List Account Targets') + ->groups(['api', 'account']) + ->label('scope', 'account') + ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'listTargets') + ->label('sdk.description', '/docs/references/account/list-targets.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TARGET_LIST) + ->inject('response') + ->inject('user') + ->action(function (Response $response, Document $user) { + + $targets = $user->getAttribute('targets', []); + + $response->dynamic(new Document([ + 'targets' => $targets, + 'total' => count($targets), + ]), Response::MODEL_TARGET_LIST); + }); + App::get('/v1/account/sessions/:sessionId') ->desc('Get Session') ->groups(['api', 'account']) @@ -1697,6 +1720,33 @@ App::get('/v1/account/sessions/:sessionId') throw new Exception(Exception::USER_SESSION_NOT_FOUND); }); +App::get('/v1/account/targets/:targetId') + ->desc('Get Target') + ->groups(['api', 'account']) + ->label('scope', 'account') + ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'getTarget') + ->label('sdk.description', '/docs/references/account/get-Target.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_SESSION) + ->label('sdk.offline.model', '/account/targets') + ->label('sdk.offline.key', '{targetId}') + ->param('targetId', '', new UID(), 'Target ID.') + ->inject('response') + ->inject('user') + ->action(function (string $targetId, Response $response, Document $user) { + + $target = $user->find('$id', $targetId, 'targets'); + + if (empty($target)) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + $response->dynamic($target, Response::MODEL_TARGET); + }); + App::patch('/v1/account/name') ->desc('Update Name') ->groups(['api', 'account']) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index c3129d41eb..adc02a3b02 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -461,6 +461,38 @@ App::get('/v1/users/:userId/prefs') $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); }); +App::get('/v1/users/:userId/targets/:targetId') + ->desc('Get User Target') + ->groups(['api', 'users']) + ->label('scope', 'users.read') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'users') + ->label('sdk.method', 'getTarget') + ->label('sdk.description', '/docs/references/users/get-user-target.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TARGET) + ->param('userId', '', new UID(), 'User ID.') + ->param('targetId', '', new UID(), 'Target ID.') + ->inject('response') + ->inject('dbForProject') + ->action(function (string $userId, string $targetId, Response $response, Database $dbForProject) { + + $user = $dbForProject->getDocument('users', $userId); + + if ($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $target = $user->find('$id', $targetId, 'targets'); + + if (empty($target)) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + $response->dynamic($target, Response::MODEL_TARGET); + }); + App::get('/v1/users/:userId/sessions') ->desc('List User Sessions') ->groups(['api', 'users']) @@ -622,6 +654,36 @@ App::get('/v1/users/:userId/logs') ]), Response::MODEL_LOG_LIST); }); +App::get('/v1/users/:userId/targets') + ->desc('List User Targets') + ->groups(['api', 'users']) + ->label('scope', 'users.read') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'users') + ->label('sdk.method', 'listTargets') + ->label('sdk.description', '/docs/references/users/list-user-targets.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TARGET_LIST) + ->param('userId', '', new UID(), 'User ID.') + ->inject('response') + ->inject('dbForProject') + ->action(function (string $userId, Response $response, Database $dbForProject) { + + $user = $dbForProject->getDocument('users', $userId); + + if ($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $targets = $user->getAttribute('targets', []); + var_dump($user); + $response->dynamic(new Document([ + 'targets' => $targets, + 'total' => count($targets), + ]), Response::MODEL_TARGET_LIST); + }); + App::patch('/v1/users/:userId/status') ->desc('Update User Status') ->groups(['api', 'users']) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 6b448db8ec..1392faaed6 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -81,6 +81,7 @@ class Exception extends \Exception public const USER_OAUTH2_BAD_REQUEST = 'user_oauth2_bad_request'; public const USER_OAUTH2_UNAUTHORIZED = 'user_oauth2_unauthorized'; public const USER_OAUTH2_PROVIDER_ERROR = 'user_oauth2_provider_error'; + public const USER_TARGET_NOT_FOUND = 'user_target_not_found'; /** Teams */ public const TEAM_NOT_FOUND = 'team_not_found'; diff --git a/src/Appwrite/Utopia/Response/Model/BaseList.php b/src/Appwrite/Utopia/Response/Model/BaseList.php index 06a5249388..0c2cc072f3 100644 --- a/src/Appwrite/Utopia/Response/Model/BaseList.php +++ b/src/Appwrite/Utopia/Response/Model/BaseList.php @@ -34,7 +34,7 @@ class BaseList extends Model $namesWithCap = [ 'documents', 'collections', 'users', 'files', 'buckets', 'functions', 'deployments', 'executions', 'projects', 'webhooks', 'keys', - 'platforms', 'domains', 'memberships', 'teams' + 'platforms', 'domains', 'memberships', 'teams', 'targets' ]; if (\in_array($name, $namesWithCap)) { From e53f189b3b455f71873d752a4010ede92bc2a0fb Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 16 Aug 2023 20:17:36 +0530 Subject: [PATCH 014/196] lint fix --- app/controllers/api/users.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index adc02a3b02..c1b664ca26 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -483,7 +483,7 @@ App::get('/v1/users/:userId/targets/:targetId') if ($user->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); } - + $target = $user->find('$id', $targetId, 'targets'); if (empty($target)) { @@ -491,7 +491,7 @@ App::get('/v1/users/:userId/targets/:targetId') } $response->dynamic($target, Response::MODEL_TARGET); - }); + }); App::get('/v1/users/:userId/sessions') ->desc('List User Sessions') @@ -675,7 +675,7 @@ App::get('/v1/users/:userId/targets') if ($user->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); } - + $targets = $user->getAttribute('targets', []); var_dump($user); $response->dynamic(new Document([ From 40f419663c908598772fecfc3135525f519f93c6 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 16 Aug 2023 20:28:40 +0530 Subject: [PATCH 015/196] removes id attribute from collections config --- app/config/collections.php | 90 -------------------------------------- 1 file changed, 90 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index d884e71527..15effbf5ae 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1245,17 +1245,6 @@ $commonCollections = [ '$id' => ID::custom('providers'), 'name' => 'Providers', 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('name'), 'type' => Database::VAR_STRING, @@ -1302,13 +1291,6 @@ $commonCollections = [ ] ], 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_provider'), 'type' => Database::INDEX_KEY, @@ -1331,17 +1313,6 @@ $commonCollections = [ '$id' => ID::custom('messages'), 'name' => 'Messages', 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('providerId'), 'type' => Database::VAR_STRING, @@ -1454,13 +1425,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_providerId'), 'type' => Database::INDEX_KEY, @@ -1490,17 +1454,6 @@ $commonCollections = [ '$id' => ID::custom('topics'), 'name' => 'Topics', 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('providerId'), 'type' => Database::VAR_STRING, @@ -1547,13 +1500,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_providerId'), 'type' => Database::INDEX_KEY, @@ -1590,17 +1536,6 @@ $commonCollections = [ '$id' => ID::custom('subscribers'), 'name' => 'Subscribers', 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('userId'), 'type' => Database::VAR_STRING, @@ -1669,13 +1604,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_userId'), 'type' => Database::INDEX_KEY, @@ -1726,17 +1654,6 @@ $commonCollections = [ '$id' => ID::custom('targets'), 'name' => 'Targets', 'attributes' => [ - [ - '$id' => ID::custom('id'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('userId'), 'type' => Database::VAR_STRING, @@ -1805,13 +1722,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_id'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['id'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_userId'), 'type' => Database::INDEX_KEY, From 07b7a9db0f33ced450ec4a469269548526eb581b Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 17 Aug 2023 17:24:45 +0530 Subject: [PATCH 016/196] adds controller for creating a user target --- app/config/collections.php | 6 +-- app/config/errors.php | 14 ++++++- app/config/roles.php | 4 ++ app/controllers/api/account.php | 2 +- app/controllers/api/users.php | 63 ++++++++++++++++++++++++++++++- app/init.php | 19 ++++++++++ src/Appwrite/Extend/Exception.php | 5 ++- 7 files changed, 105 insertions(+), 8 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index f6fff4c474..929a8572b9 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1704,16 +1704,16 @@ $commonCollections = [ 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, - 'filters' => [], + 'filters' => ['subQueryProviderType'], ], [ '$id' => ID::custom('identifier'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 2048, + 'size' => Database::LENGTH_KEY, 'signed' => true, 'required' => true, 'default' => null, diff --git a/app/config/errors.php b/app/config/errors.php index 5006df0e89..9e8bdd2da7 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -232,7 +232,12 @@ return [ ], Exception::USER_TARGET_NOT_FOUND => [ 'name' => Exception::USER_TARGET_NOT_FOUND, - 'description' => 'The current user target could not be found.', + 'description' => 'The target could not be found.', + 'code' => 404, + ], + Exception::USER_TARGET_ALREADY_EXISTS => [ + 'name' => Exception::USER_TARGET_ALREADY_EXISTS, + 'description' => 'A target with the same ID already exists.', 'code' => 404, ], @@ -664,4 +669,11 @@ return [ 'description' => 'Too many queries.', 'code' => 400, ], + + /** Provider Errors */ + Exception::PROVIDER_NOT_FOUND => [ + 'name' => Exception::PROVIDER_NOT_FOUND, + 'description' => 'Provider with the request ID could not be found.', + 'code' => 400, + ], ]; diff --git a/app/config/roles.php b/app/config/roles.php index f0039841d2..8574a1392c 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -20,6 +20,8 @@ $member = [ 'avatars.read', 'execution.read', 'execution.write', + 'targets.read', + 'targets.write', ]; $admins = [ @@ -51,6 +53,8 @@ $admins = [ 'functions.write', 'execution.read', 'execution.write', + 'targets.read', + 'targets.write', ]; return [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 0e69ccdcd9..64fe71a0dd 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1672,7 +1672,7 @@ App::get('/v1/account/targets') $response->dynamic(new Document([ 'targets' => $targets, - 'total' => count($targets), + 'total' => \count($targets), ]), Response::MODEL_TARGET_LIST); }); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index c1b664ca26..2290a77c3e 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -363,6 +363,66 @@ App::post('/v1/users/scrypt-modified') ->dynamic($user, Response::MODEL_USER); }); +App::post('/v1/users/:userId/targets') + ->desc('Create User Target') + ->groups(['api', 'users']) + ->label('event', 'users.[userId].targets.[targetId].create') + ->label('scope', 'targets.write') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'users') + ->label('sdk.method', 'createTarget') + ->label('sdk.description', '/docs/references/users/create-target.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TARGET) + ->param('targetId', '', new UID(), 'Target ID.', false) + ->param('userId', '', new UID(), 'ID of the user.', false) + ->param('providerId', '', new UID(), 'ID of the provider.', false) + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', false) + ->inject('response') + ->inject('project') + ->inject('dbForProject') + ->inject('events') + ->action(function (string $targetId, string $userId, string $providerId, string $identifier, Response $response, Document $project, Database $dbForProject, Event $events) { + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $user = $dbForProject->getDocument('users', $userId); + + if($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $target = $dbForProject->getDocument('targets', $targetId); + + if(!$target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + + $target = $dbForProject->createDocument('targets', new Document([ + '$id' => $targetId, + // TO DO: what permissions should be given when created a target. + '$permissions' => [ + Permission::read(Role::any()) + ], + 'providerId' => $providerId, + 'providerInternalId' => $provider->getInternalId(), + 'providerType' => null, + 'userId' => $userId, + 'userInternalId' => $user->getInternalId(), + 'identifier' => $identifier, + ])); + $events + ->setParam('userId', $userId) + ->setParam('targetId', $targetId); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($target, Response::MODEL_TARGET); + }); + App::get('/v1/users') ->desc('List Users') ->groups(['api', 'users']) @@ -677,10 +737,9 @@ App::get('/v1/users/:userId/targets') } $targets = $user->getAttribute('targets', []); - var_dump($user); $response->dynamic(new Document([ 'targets' => $targets, - 'total' => count($targets), + 'total' => \count($targets), ]), Response::MODEL_TARGET_LIST); }); diff --git a/app/init.php b/app/init.php index 65cf4034a6..46b19cbe16 100644 --- a/app/init.php +++ b/app/init.php @@ -535,6 +535,25 @@ Database::addFilter( ])); } ); + +Database::addFilter( + 'subQueryProviderType', + function (mixed $value) { + return null; + }, + function (mixed $value, Document $document, Database $database) { + $provider = Authorization::skip(fn() => $database + ->findOne('providers', [ + Query::equal('$id', [$document->getAttribute('providerId')]), + Query::select(['type']), + Query::limit(APP_LIMIT_SUBQUERY), + ])); + if($provider) + return $provider->getAttribute('type'); + return null; + } +); + /** * DB Formats */ diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 1392faaed6..92bbd5c6c4 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -82,7 +82,7 @@ class Exception extends \Exception public const USER_OAUTH2_UNAUTHORIZED = 'user_oauth2_unauthorized'; public const USER_OAUTH2_PROVIDER_ERROR = 'user_oauth2_provider_error'; public const USER_TARGET_NOT_FOUND = 'user_target_not_found'; - + public const USER_TARGET_ALREADY_EXISTS = 'user_target_already_exists'; /** Teams */ public const TEAM_NOT_FOUND = 'team_not_found'; public const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; @@ -205,6 +205,9 @@ class Exception extends \Exception public const GRAPHQL_NO_QUERY = 'graphql_no_query'; public const GRAPHQL_TOO_MANY_QUERIES = 'graphql_too_many_queries'; + /** Provider */ + public const PROVIDER_NOT_FOUND = 'provider_not_found'; + protected $type = ''; protected $errors = []; From c83e4db23d15fb210dcc6dd913e58263f91e927e Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 17 Aug 2023 19:02:07 +0530 Subject: [PATCH 017/196] lint fix --- app/controllers/api/users.php | 4 ++-- app/init.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 2290a77c3e..d47024f81e 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -392,13 +392,13 @@ App::post('/v1/users/:userId/targets') $user = $dbForProject->getDocument('users', $userId); - if($user->isEmpty()) { + if ($user->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); } $target = $dbForProject->getDocument('targets', $targetId); - if(!$target->isEmpty()) { + if (!$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } diff --git a/app/init.php b/app/init.php index 46b19cbe16..233e022a1e 100644 --- a/app/init.php +++ b/app/init.php @@ -548,8 +548,9 @@ Database::addFilter( Query::select(['type']), Query::limit(APP_LIMIT_SUBQUERY), ])); - if($provider) + if ($provider) { return $provider->getAttribute('type'); + } return null; } ); From f73b3bf2723a4c761c6df017962c1abc02bbe7a6 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 18 Aug 2023 01:07:42 +0530 Subject: [PATCH 018/196] deletes user cache document --- app/controllers/api/users.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index d47024f81e..b66429d9ba 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -380,10 +380,9 @@ App::post('/v1/users/:userId/targets') ->param('providerId', '', new UID(), 'ID of the provider.', false) ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', false) ->inject('response') - ->inject('project') ->inject('dbForProject') ->inject('events') - ->action(function (string $targetId, string $userId, string $providerId, string $identifier, Response $response, Document $project, Database $dbForProject, Event $events) { + ->action(function (string $targetId, string $userId, string $providerId, string $identifier, Response $response, Database $dbForProject, Event $events) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -415,6 +414,7 @@ App::post('/v1/users/:userId/targets') 'userInternalId' => $user->getInternalId(), 'identifier' => $identifier, ])); + $dbForProject->deleteCachedDocument('users', $user->getId()); $events ->setParam('userId', $userId) ->setParam('targetId', $targetId); From 36a5d1e245ca2f3ea131ad18f92c31845d4e961b Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 18 Aug 2023 23:28:12 +0530 Subject: [PATCH 019/196] adds remaining controllers for target in account and users --- app/controllers/api/account.php | 153 ++++++++++++++++++++++++++++++++ app/controllers/api/users.php | 101 ++++++++++++++++++++- composer.lock | 22 ++--- 3 files changed, 261 insertions(+), 15 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 64fe71a0dd..d9749f0274 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -2818,3 +2818,156 @@ App::put('/v1/account/verification/phone') $response->dynamic($verificationDocument, Response::MODEL_TOKEN); }); + +App::post('/v1/account/targets') + ->desc('Create User Target') + ->groups(['api', 'account']) + ->label('event', 'users.[userId].targets.[targetId].create') + ->label('scope', 'targets.write') + ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'createTarget') + ->label('sdk.description', '/docs/references/account/create-target.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TARGET) + ->param('userId', '', new UID(), 'ID of the user.', false) + ->param('targetId', '', new UID(), 'Target ID.', false) + ->param('providerId', '', new UID(), 'ID of the provider.', false) + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', false) + ->inject('response') + ->inject('dbForProject') + ->inject('events') + ->action(function (string $targetId, string $userId, string $providerId, string $identifier, Response $response, Database $dbForProject, Event $events) { + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $user = $dbForProject->getDocument('users', $userId); + + if ($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $target = $dbForProject->getDocument('targets', $targetId); + + if (!$target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + + $target = $dbForProject->createDocument('targets', new Document([ + '$id' => $targetId, + // TO DO: what permissions should be given when created a target. + '$permissions' => [ + Permission::read(Role::any()) + ], + 'providerId' => $providerId, + 'providerInternalId' => $provider->getInternalId(), + 'providerType' => null, + 'userId' => $userId, + 'userInternalId' => $user->getInternalId(), + 'identifier' => $identifier, + ])); + $dbForProject->deleteCachedDocument('users', $user->getId()); + $events + ->setParam('userId', $userId) + ->setParam('targetId', $targetId); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($target, Response::MODEL_TARGET); + }); + +App::patch('/v1/account/targets/:targetId/identifier') + ->desc('Update user target\'s identifier') + ->groups(['api', 'account']) + ->label('event', 'users.[userId].targets.[targetId].update') + ->label('scope', 'targets.write') + ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'updateTargetIdentifier') + ->label('sdk.description', '/docs/references/account/update-target-identifier.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TARGET) + ->param('userId', '', new UID(), 'ID of the user.', false) + ->param('targetId', '', new UID(), 'Target ID.', false) + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) + ->inject('response') + ->inject('dbForProject') + ->inject('events') + ->action(function (string $targetId, string $userId, string $identifier, Response $response, Database $dbForProject, Event $events) { + + $user = $dbForProject->getDocument('users', $userId); + + if ($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $target = $dbForProject->getDocument('targets', $targetId); + + if ($target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + // Update the target identifier here + $target->setAttribute('identifier', $identifier); + + $target = $dbForProject->updateDocument('targets', $target->getId(), $target); + $dbForProject->deleteCachedDocument('users', $user->getId()); + + $events + ->setParam('userId', $userId) + ->setParam('targetId', $targetId); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($target, Response::MODEL_TARGET); + }); + +App::delete('/v1/account/targets/:targetId') + ->desc('Delete user target') + ->groups(['api', 'account']) + ->label('event', 'users.[userId].targets.[targetId].delete') + ->label('scope', 'targets.write') + ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'deleteTarget') + ->label('sdk.description', '/docs/references/account/delete-target.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('userId', '', new UID(), 'ID of the user.', false) + ->param('targetId', '', new UID(), 'Target ID.', false) + ->inject('response') + ->inject('dbForProject') + ->inject('events') + ->action(function (string $targetId, string $userId, Response $response, Database $dbForProject, Event $events) { + + $user = $dbForProject->getDocument('users', $userId); + + if ($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $target = $dbForProject->getDocument('targets', $targetId); + + if ($target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + $target = $dbForProject->deleteDocument('targets', $target->getId()); + $dbForProject->deleteCachedDocument('users', $user->getId()); + $user = $dbForProject->getDocument('users', $userId); + + // clone user object to send to workers + $clone = clone $user; + + $events + ->setParam('userId', $userId) + ->setParam('targetId', $targetId) + ->setPayload($response->output($clone, Response::MODEL_USER)); + + $response->noContent(); + }); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index b66429d9ba..86f25579ca 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -368,15 +368,15 @@ App::post('/v1/users/:userId/targets') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].create') ->label('scope', 'targets.write') - ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createTarget') ->label('sdk.description', '/docs/references/users/create-target.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET) - ->param('targetId', '', new UID(), 'Target ID.', false) ->param('userId', '', new UID(), 'ID of the user.', false) + ->param('targetId', '', new UID(), 'Target ID.', false) ->param('providerId', '', new UID(), 'ID of the provider.', false) ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', false) ->inject('response') @@ -525,7 +525,7 @@ App::get('/v1/users/:userId/targets/:targetId') ->desc('Get User Target') ->groups(['api', 'users']) ->label('scope', 'users.read') - ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'getTarget') ->label('sdk.description', '/docs/references/users/get-user-target.md') @@ -718,7 +718,7 @@ App::get('/v1/users/:userId/targets') ->desc('List User Targets') ->groups(['api', 'users']) ->label('scope', 'users.read') - ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'listTargets') ->label('sdk.description', '/docs/references/users/list-user-targets.md') @@ -1147,6 +1147,53 @@ App::patch('/v1/users/:userId/prefs') $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); }); +App::patch('/v1/users/:userId/targets/:targetId/identifier') + ->desc('Update user target\'s identifier') + ->groups(['api', 'users']) + ->label('event', 'users.[userId].targets.[targetId].update') + ->label('scope', 'targets.write') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'users') + ->label('sdk.method', 'updateTargetIdentifier') + ->label('sdk.description', '/docs/references/users/update-target-identifier.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TARGET) + ->param('userId', '', new UID(), 'ID of the user.', false) + ->param('targetId', '', new UID(), 'Target ID.', false) + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) + ->inject('response') + ->inject('dbForProject') + ->inject('events') + ->action(function (string $targetId, string $userId, string $identifier, Response $response, Database $dbForProject, Event $events) { + + $user = $dbForProject->getDocument('users', $userId); + + if ($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $target = $dbForProject->getDocument('targets', $targetId); + + if ($target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + // Update the target identifier here + $target->setAttribute('identifier', $identifier); + + $target = $dbForProject->updateDocument('targets', $target->getId(), $target); + $dbForProject->deleteCachedDocument('users', $user->getId()); + + $events + ->setParam('userId', $userId) + ->setParam('targetId', $targetId); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($target, Response::MODEL_TARGET); + }); + App::delete('/v1/users/:userId/sessions/:sessionId') ->desc('Delete User Session') ->groups(['api', 'users']) @@ -1274,6 +1321,52 @@ App::delete('/v1/users/:userId') $response->noContent(); }); +App::delete('/v1/users/:userId/targets/:targetId') + ->desc('Delete user target') + ->groups(['api', 'users']) + ->label('event', 'users.[userId].targets.[targetId].delete') + ->label('scope', 'targets.write') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'users') + ->label('sdk.method', 'deleteTarget') + ->label('sdk.description', '/docs/references/users/delete-target.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('userId', '', new UID(), 'ID of the user.', false) + ->param('targetId', '', new UID(), 'Target ID.', false) + ->inject('response') + ->inject('dbForProject') + ->inject('events') + ->action(function (string $targetId, string $userId, Response $response, Database $dbForProject, Event $events) { + + $user = $dbForProject->getDocument('users', $userId); + + if ($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $target = $dbForProject->getDocument('targets', $targetId); + + if ($target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + $target = $dbForProject->deleteDocument('targets', $target->getId()); + $dbForProject->deleteCachedDocument('users', $user->getId()); + $user = $dbForProject->getDocument('users', $userId); + + // clone user object to send to workers + $clone = clone $user; + + $events + ->setParam('userId', $userId) + ->setParam('targetId', $targetId) + ->setPayload($response->output($clone, Response::MODEL_USER)); + + $response->noContent(); + }); + App::get('/v1/users/usage') ->desc('Get usage stats for the users API') ->groups(['api', 'users', 'usage']) diff --git a/composer.lock b/composer.lock index 0e72c867d2..579029b79c 100644 --- a/composer.lock +++ b/composer.lock @@ -686,16 +686,16 @@ }, { "name": "matomo/device-detector", - "version": "6.1.4", + "version": "6.1.5", "source": { "type": "git", "url": "https://github.com/matomo-org/device-detector.git", - "reference": "74f6c4f6732b3ad6cdf25560746841d522969112" + "reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/74f6c4f6732b3ad6cdf25560746841d522969112", - "reference": "74f6c4f6732b3ad6cdf25560746841d522969112", + "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/40ca2990dba2c1719e5c62168e822e0b86c167d4", + "reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4", "shasum": "" }, "require": { @@ -751,7 +751,7 @@ "source": "https://github.com/matomo-org/matomo", "wiki": "https://dev.matomo.org/" }, - "time": "2023-08-02T08:48:53+00:00" + "time": "2023-08-17T16:17:41+00:00" }, { "name": "mongodb/mongodb", @@ -1516,16 +1516,16 @@ }, { "name": "utopia-php/database", - "version": "0.42.1", + "version": "0.42.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "9ff69a9b9eadc581771798833d423829c9d8cc90" + "reference": "bc5ceb30c85fb685b0b5704d2f74886d813ebd41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/9ff69a9b9eadc581771798833d423829c9d8cc90", - "reference": "9ff69a9b9eadc581771798833d423829c9d8cc90", + "url": "https://api.github.com/repos/utopia-php/database/zipball/bc5ceb30c85fb685b0b5704d2f74886d813ebd41", + "reference": "bc5ceb30c85fb685b0b5704d2f74886d813ebd41", "shasum": "" }, "require": { @@ -1566,9 +1566,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.42.1" + "source": "https://github.com/utopia-php/database/tree/0.42.2" }, - "time": "2023-08-14T16:09:09+00:00" + "time": "2023-08-17T19:04:37+00:00" }, { "name": "utopia-php/domains", From a174aca2c8018b01ffee0fb7cdda4b429b64a350 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 18 Aug 2023 23:30:42 +0530 Subject: [PATCH 020/196] lint fix and rename subscriber model file correctly --- .../Utopia/Response/Model/Message.php | 140 +++++++++--------- .../Utopia/Response/Model/Provider.php | 74 ++++----- .../Utopia/Response/Model/Subsciber.php | 63 -------- .../Utopia/Response/Model/Subscriber.php | 63 ++++++++ src/Appwrite/Utopia/Response/Model/Target.php | 88 +++++------ src/Appwrite/Utopia/Response/Model/Topic.php | 76 +++++----- 6 files changed, 252 insertions(+), 252 deletions(-) delete mode 100644 src/Appwrite/Utopia/Response/Model/Subsciber.php create mode 100644 src/Appwrite/Utopia/Response/Model/Subscriber.php diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 28536012ab..177058be9b 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -8,88 +8,88 @@ use Utopia\Database\DateTime; class Message extends Model { - /** - * @var bool - */ + /** + * @var bool + */ protected bool $public = false; public function __construct() { $this - ->addRule('$id', [ - 'type' => self::TYPE_STRING, - 'description' => 'Message ID.', - 'default' => '', - 'example' => '5e5ea5c16897e', - ]) - ->addRule('providerId', [ - 'type' => self::TYPE_STRING, - 'description' => 'Provider Id for the message.', - 'default' => '', - 'example' => '5e5ea5c16897e', - ]) - ->addRule('data', [ - 'type' => self::TYPE_JSON, - 'description' => 'Message Data.', - 'default' => '', - 'required' => false, - 'example' => '', - ]) - ->addRule('to', [ - 'type' => self::TYPE_STRING, - 'description' => 'Recipient of message.', - 'default' => '', - 'example' => ['user-1'], - ]) - ->addRule('deliveryTime', [ - 'type' => self::TYPE_DATETIME, - 'description' => 'Recipient of message.', - 'required' => false, - 'default' => DateTime::now(), - 'example' => DateTime::now(), - ]) - ->addRule('deliveryError', [ - 'type' => self::TYPE_STRING, - 'description' => 'Delivery error if any.', - 'required' => false, - 'default' => '', - 'example' => 'Provider not valid.', - ]) - ->addRule('deliveredTo', [ - 'type' => self::TYPE_INTEGER, - 'description' => 'Number of recipients the message was delivered to.', - 'default' => '', - 'example' => 1, - ]) - ->addRule('delivered', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Status of delivery.', - 'default' => '', - 'example' => true, - ]) - ->addRule('search', [ - 'type' => self::TYPE_STRING, - 'description' => 'Field that can be used for searching message.', - 'default' => '', - 'example' => 'Hello everyone', - ]); + ->addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Message ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('providerId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider Id for the message.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('data', [ + 'type' => self::TYPE_JSON, + 'description' => 'Message Data.', + 'default' => '', + 'required' => false, + 'example' => '', + ]) + ->addRule('to', [ + 'type' => self::TYPE_STRING, + 'description' => 'Recipient of message.', + 'default' => '', + 'example' => ['user-1'], + ]) + ->addRule('deliveryTime', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Recipient of message.', + 'required' => false, + 'default' => DateTime::now(), + 'example' => DateTime::now(), + ]) + ->addRule('deliveryError', [ + 'type' => self::TYPE_STRING, + 'description' => 'Delivery error if any.', + 'required' => false, + 'default' => '', + 'example' => 'Provider not valid.', + ]) + ->addRule('deliveredTo', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of recipients the message was delivered to.', + 'default' => '', + 'example' => 1, + ]) + ->addRule('delivered', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Status of delivery.', + 'default' => '', + 'example' => true, + ]) + ->addRule('search', [ + 'type' => self::TYPE_STRING, + 'description' => 'Field that can be used for searching message.', + 'default' => '', + 'example' => 'Hello everyone', + ]); } - /** - * Get Name - * - * @return string - */ + /** + * Get Name + * + * @return string + */ public function getName(): string { return 'Message'; } - /** - * Get Type - * - * @return string - */ + /** + * Get Type + * + * @return string + */ public function getType(): string { return Response::MODEL_MESSAGE; diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index fcaacd87c0..6dd12a4d7a 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -7,55 +7,55 @@ use Appwrite\Utopia\Response\Model; class Provider extends Model { - /** - * @var bool - */ + /** + * @var bool + */ protected bool $public = false; public function __construct() { $this - ->addRule('$id', [ - 'type' => self::TYPE_STRING, - 'description' => 'Provider ID.', - 'default' => '', - 'example' => '5e5ea5c16897e', - ]) - ->addRule('name', [ - 'type' => self::TYPE_STRING, - 'description' => 'The user-given name for the provider instance.', - 'default' => '', - 'example' => 'Mailgun', - ]) - ->addRule('provider', [ - 'type' => self::TYPE_STRING, - 'description' => 'Provider name setup in Utopia.', - 'default' => '', - 'example' => 'mailgun', - ]) - ->addRule('type', [ - 'type' => self::TYPE_STRING, - 'description' => 'Type of provider.', - 'default' => '', - 'example' => 'sms', - ]); + ->addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'The user-given name for the provider instance.', + 'default' => '', + 'example' => 'Mailgun', + ]) + ->addRule('provider', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider name setup in Utopia.', + 'default' => '', + 'example' => 'mailgun', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Type of provider.', + 'default' => '', + 'example' => 'sms', + ]); } - /** - * Get Name - * - * @return string - */ + /** + * Get Name + * + * @return string + */ public function getName(): string { return 'Provider'; } - /** - * Get Type - * - * @return string - */ + /** + * Get Type + * + * @return string + */ public function getType(): string { return Response::MODEL_PROVIDER; diff --git a/src/Appwrite/Utopia/Response/Model/Subsciber.php b/src/Appwrite/Utopia/Response/Model/Subsciber.php deleted file mode 100644 index 11905180e3..0000000000 --- a/src/Appwrite/Utopia/Response/Model/Subsciber.php +++ /dev/null @@ -1,63 +0,0 @@ -addRule('$id', [ - 'type' => self::TYPE_STRING, - 'description' => 'Subscriber ID.', - 'default' => '', - 'example' => '259125845563242502', - ]) - ->addRule('userId', [ - 'type' => self::TYPE_STRING, - 'description' => 'User ID.', - 'default' => '', - 'example' => '259125845563242502', - ]) - ->addRule('targetId', [ - 'type' => self::TYPE_STRING, - 'description' => 'Target ID.', - 'default' => '', - 'example' => '259125845563242502', - ]) - ->addRule('topicId', [ - 'type' => self::TYPE_STRING, - 'description' => 'Topic ID.', - 'default' => '', - 'example' => '259125845563242502', - ]); - } - - /** - * Get Name - * - * @return string - */ - public function getName(): string - { - return 'Subscriber'; - } - - /** - * Get Type - * - * @return string - */ - public function getType(): string - { - return Response::MODEL_SUBSCRIBER; - } -} diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php new file mode 100644 index 0000000000..a9682cf0a6 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -0,0 +1,63 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Subscriber ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('userId', [ + 'type' => self::TYPE_STRING, + 'description' => 'User ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('targetId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('topicId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Topic ID.', + 'default' => '', + 'example' => '259125845563242502', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Subscriber'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_SUBSCRIBER; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php index 8bc90731ba..272c929e11 100644 --- a/src/Appwrite/Utopia/Response/Model/Target.php +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -7,62 +7,62 @@ use Appwrite\Utopia\Response\Model; class Target extends Model { - /** - * @var bool - */ + /** + * @var bool + */ protected bool $public = false; public function __construct() { $this - ->addRule('$id', [ - 'type' => self::TYPE_STRING, - 'description' => 'Target ID.', - 'default' => '', - 'example' => '259125845563242502', - ]) - ->addRule('userId', [ - 'type' => self::TYPE_STRING, - 'description' => 'User ID.', - 'default' => '', - 'example' => '259125845563242502', - ]) - ->addRule('providerId', [ - 'type' => self::TYPE_STRING, - 'description' => 'Provider ID.', - 'required' => false, - 'default' => '', - 'example' => '259125845563242502', - ]) - ->addRule('providerType', [ - 'type' => self::TYPE_STRING, - 'description' => 'The type of provider supported by this target.', - 'default' => '', - 'example' => 'sms', - ]) - ->addRule('identifier', [ - 'type' => self::TYPE_STRING, - 'description' => 'The target identifier.', - 'default' => '', - 'example' => 'token', - ]); + ->addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('userId', [ + 'type' => self::TYPE_STRING, + 'description' => 'User ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('providerId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider ID.', + 'required' => false, + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('providerType', [ + 'type' => self::TYPE_STRING, + 'description' => 'The type of provider supported by this target.', + 'default' => '', + 'example' => 'sms', + ]) + ->addRule('identifier', [ + 'type' => self::TYPE_STRING, + 'description' => 'The target identifier.', + 'default' => '', + 'example' => 'token', + ]); } - /** - * Get Name - * - * @return string - */ + /** + * Get Name + * + * @return string + */ public function getName(): string { return 'Target'; } - /** - * Get Type - * - * @return string - */ + /** + * Get Type + * + * @return string + */ public function getType(): string { return Response::MODEL_TARGET; diff --git a/src/Appwrite/Utopia/Response/Model/Topic.php b/src/Appwrite/Utopia/Response/Model/Topic.php index 42ecd583af..c0996fcf55 100644 --- a/src/Appwrite/Utopia/Response/Model/Topic.php +++ b/src/Appwrite/Utopia/Response/Model/Topic.php @@ -7,56 +7,56 @@ use Appwrite\Utopia\Response\Model; class Topic extends Model { - /** - * @var bool - */ + /** + * @var bool + */ protected bool $public = false; public function __construct() { $this - ->addRule('$id', [ - 'type' => self::TYPE_STRING, - 'description' => 'Topic ID.', - 'default' => '', - 'example' => '259125845563242502', - ]) - ->addRule('providerId', [ - 'type' => self::TYPE_STRING, - 'description' => 'Provider ID.', - 'default' => '', - 'example' => '259125845563242502', - ]) - ->addRule('name', [ - 'type' => self::TYPE_STRING, - 'description' => 'The name of the topic.', - 'default' => '', - 'example' => 'events', - ]) - ->addRule('description', [ - 'type' => self::TYPE_STRING, - 'description' => 'Description of the topic.', - 'default' => '', - 'required' => false, - 'example' => 'All events related messages will be sent to this topic.', - ]); + ->addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Topic ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('providerId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'The name of the topic.', + 'default' => '', + 'example' => 'events', + ]) + ->addRule('description', [ + 'type' => self::TYPE_STRING, + 'description' => 'Description of the topic.', + 'default' => '', + 'required' => false, + 'example' => 'All events related messages will be sent to this topic.', + ]); } - /** - * Get Name - * - * @return string - */ + /** + * Get Name + * + * @return string + */ public function getName(): string { return 'Topic'; } - /** - * Get Type - * - * @return string - */ + /** + * Get Type + * + * @return string + */ public function getType(): string { return Response::MODEL_TOPIC; From fe8b8d3dc686555648b7cea9a768a179f96e7408 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 21 Aug 2023 14:14:06 +0530 Subject: [PATCH 021/196] fix lint --- app/controllers/api/users.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 8bf107b5ee..e6d5e8e1b9 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1530,4 +1530,4 @@ App::get('/v1/users/usage') 'usersTotal' => $usage[$metrics[0]], 'sessionsTotal' => $usage[$metrics[1]], ]), Response::MODEL_USAGE_USERS); - }); \ No newline at end of file + }); From a6d613542bfaa0845f8ec2f1ccad03ffa5c101b6 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 21 Aug 2023 16:14:50 +0530 Subject: [PATCH 022/196] adds messaging api controlle for mailgun provider --- app/config/services.php | 13 ++++++++++ app/controllers/api/messaging.php | 42 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 app/controllers/api/messaging.php diff --git a/app/config/services.php b/app/config/services.php index e14a1d5781..f80431f784 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -225,4 +225,17 @@ return [ 'optional' => true, 'icon' => '/images/services/migrations.png', ], + 'messaging' => [ + 'key' => 'messaging', + 'name' => 'Messaging', + 'subtitle' => 'The Messaging service allows you to send messages to any provider type (SMTP, push notification, SMS, etc.).', + 'description' => '/docs/services/messaging.md', + 'controller' => 'api/messaging.php', + 'sdk' => true, + 'docs' => true, + 'docsUrl' => 'https://appwrite.io/docs/server/messaging', + 'tests' => false, + 'optional' => true, + 'icon' => '/images/services/messaging.png', + ] ]; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php new file mode 100644 index 0000000000..2f0c50348a --- /dev/null +++ b/app/controllers/api/messaging.php @@ -0,0 +1,42 @@ +desc('Create Mailgun Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.create') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.description', '/docs/references/messaging/create-provider-mailgun.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('apiKey', null, new Text(0), 'Mailgun API Key.', true) + ->param('domain', null, new Text(0), 'Mailgun Domain.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', '64e33e70dd07f0d03efb'); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'Mailgun', + 'type' => 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + 'domain' => $domain + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); From 4406c7bd554eedb63e764c03a01822ca1fd344e1 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 21 Aug 2023 22:15:15 +0530 Subject: [PATCH 023/196] adds messaging worker and send an email controller --- app/controllers/api/messaging.php | 55 +++++++++++++- app/workers/messaging.php | 118 ++++++++++++++++++++---------- composer.json | 4 +- composer.lock | 67 ++++++++++------- 4 files changed, 175 insertions(+), 69 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 2f0c50348a..f5ee54c852 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1,9 +1,13 @@ inject('dbForProject') ->inject('response') ->action(function (string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', '64e33e70dd07f0d03efb'); $provider = $dbForProject->createDocument('providers', new Document([ 'name' => $name, 'provider' => 'Mailgun', @@ -40,3 +43,53 @@ App::post('/v1/messaging/providers/mailgun') ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); + +App::post('/v1/messaging/messages/email') + ->desc('Send an email.') + ->groups(['api', 'messaging']) + ->label('event', 'messages.create') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.description', '/docs/references/messaging/send-email.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('providerId', '', new Text(128), 'Email Provider ID.') + ->param('to', [], new ArrayList(new Text(0)), 'Email Recepient.', true) + ->param('subject', null, new Text(0), 'Email Subject.', true) + ->param('content', null, new Text(0), 'Email Content.', true) + ->param('from', null, new Text(0), 'Email from.', false) + ->param('html', null, new Text(0), 'Is content of type HTML', false) + ->param('deliveryTime', null, new Datetime(), 'Delivery time of the message', false) + ->inject('dbForProject') + ->inject('events') + ->inject('response') + ->action(function (string $providerId, string $to, string $subject, string $content, string $from, string $html, DateTime $deliveryTime, Database $dbForProject, Event $eventsInstance, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $message = $dbForProject->createDocument('messages', new Document([ + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'to' => $to, + 'data' => [ + 'subject' => $subject, + 'content' => $content, + ], + 'deliveryTime' => $deliveryTime, + 'deliveryError' => null, + 'deliveredTo' => null, + 'delivered' => false, + 'search' => null + ])); + + $eventsInstance->setParam('messageId', $message->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_MESSAGE); + }); diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 5732c8c00b..3e730b120a 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -1,17 +1,23 @@ getAttribute('credentials'); + return match ($record->getAttribute('provider')) { + 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), + 'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']), + 'telesign' => new Telesign($credentials['username'], $credentials['password']), + 'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']), + 'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']), + default => null + }; + } + + function push($record): ?PushAdapter + { + $credentials = $record->getAttribute('credentials'); + return match ($record->getAttribute('provider')) { + 'apns' => new APNS( + $credentials['authKey'], + $credentials['authKeyId'], + $credentials['teamId'], + $credentials['bundleId'], + $credentials['endpoint'] + ), + 'fcm' => new FCM($credentials['serverKey']), + default => null + }; + } + + public function email($record): ?EmailAdapter + { + $credentials = $record->getAttribute('credentials'); + return match ($record->getAttribute('provider')) { + 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain']), + 'sendgrid' => new SendGrid($credentials['apiKey']), + default => null + }; + } + public function init(): void { - $dsn = new DSN(App::getEnv('_APP_SMS_PROVIDER')); - $user = $dsn->getUser(); - $secret = $dsn->getPassword(); - - $this->sms = match ($dsn->getHost()) { - 'mock' => new Mock($user, $secret), // used for tests - 'twilio' => new Twilio($user, $secret), - 'text-magic' => new TextMagic($user, $secret), - 'telesign' => new Telesign($user, $secret), - 'msg91' => new Msg91($user, $secret), - 'vonage' => new Vonage($user, $secret), - default => null - }; - - $this->from = App::getEnv('_APP_SMS_FROM'); } public function run(): void { - if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { - Console::info('Skipped sms processing. No Phone provider has been set.'); - return; - } + $providerId = $this->args['providerId']; + $providerRecord = + $this + ->getConsoleDB() + ->getDocument('providers', $providerId); - if (empty($this->from)) { - Console::info('Skipped sms processing. No phone number has been set.'); - return; - } + $provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed. + 'sms' => $this->sms($providerRecord), + 'push' => $this->push($providerRecord), + 'email' => $this->email($providerRecord), + default => null + }; - $message = new SMS( - to: [$this->args['recipient']], - content: $this->args['message'], - from: $this->from, - ); + // Query for the provider + // switch on provider name + // call function passing needed credentials returns required provider. - try { - $this->sms->send($message); - } catch (\Exception $error) { - throw new Exception('Error sending message: ' . $error->getMessage(), 500); - } + $messageId = $this->args['messageId']; + $message = + $this + ->getConsoleDB() + ->getDocument('messages', $messageId); + + // Contrust Message Object according to each provider type. + // Send the message using respective adapter } - public function shutdown(): void + function shutdown(): void { } } diff --git a/composer.json b/composer.json index 2fd93cf510..e73d67b6a7 100644 --- a/composer.json +++ b/composer.json @@ -50,13 +50,13 @@ "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", "utopia-php/database": "0.42.*", - "utopia-php/domains": "1.1.*", + "utopia-php/domains": "0.3.*", "utopia-php/dsn": "0.1.*", "utopia-php/framework": "0.28.*", "utopia-php/image": "0.5.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.3.*", - "utopia-php/messaging": "0.1.*", + "utopia-php/messaging": "dev-feat-push as 0.1.1", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.4.*", "utopia-php/pools": "0.4.*", diff --git a/composer.lock b/composer.lock index cf6f442954..55e84a6e74 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": "2098172fc4b71eb0d41dcdbfea2f5061", + "content-hash": "d599591131c16b547bb7ad8c83a35482", "packages": [ { "name": "adhocore/jwt", @@ -1557,16 +1557,16 @@ }, { "name": "utopia-php/database", - "version": "0.42.1", + "version": "0.42.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "9ff69a9b9eadc581771798833d423829c9d8cc90" + "reference": "bc5ceb30c85fb685b0b5704d2f74886d813ebd41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/9ff69a9b9eadc581771798833d423829c9d8cc90", - "reference": "9ff69a9b9eadc581771798833d423829c9d8cc90", + "url": "https://api.github.com/repos/utopia-php/database/zipball/bc5ceb30c85fb685b0b5704d2f74886d813ebd41", + "reference": "bc5ceb30c85fb685b0b5704d2f74886d813ebd41", "shasum": "" }, "require": { @@ -1607,29 +1607,31 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.42.1" + "source": "https://github.com/utopia-php/database/tree/0.42.2" }, - "time": "2023-08-14T16:09:09+00:00" + "time": "2023-08-17T19:04:37+00:00" }, { "name": "utopia-php/domains", - "version": "v1.1.0", + "version": "0.3.2", "source": { "type": "git", "url": "https://github.com/utopia-php/domains.git", - "reference": "1665e1d9932afa3be63b5c1e0dcfe01fe77d8e73" + "reference": "aaa8c9a96c69ccb397997b1f4f2299c66f77eefb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/domains/zipball/1665e1d9932afa3be63b5c1e0dcfe01fe77d8e73", - "reference": "1665e1d9932afa3be63b5c1e0dcfe01fe77d8e73", + "url": "https://api.github.com/repos/utopia-php/domains/zipball/aaa8c9a96c69ccb397997b1f4f2299c66f77eefb", + "reference": "aaa8c9a96c69ccb397997b1f4f2299c66f77eefb", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.0", + "utopia-php/framework": "0.*.*" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3" }, "type": "library", "autoload": { @@ -1645,6 +1647,10 @@ { "name": "Eldad Fux", "email": "eldad@appwrite.io" + }, + { + "name": "Wess Cope", + "email": "wess@appwrite.io" } ], "description": "Utopia Domains library is simple and lite library for parsing web domains. This library is aiming to be as simple and easy to learn and use.", @@ -1661,9 +1667,9 @@ ], "support": { "issues": "https://github.com/utopia-php/domains/issues", - "source": "https://github.com/utopia-php/domains/tree/master" + "source": "https://github.com/utopia-php/domains/tree/0.3.2" }, - "time": "2020-02-23T07:40:02+00:00" + "time": "2023-07-19T16:39:24+00:00" }, { "name": "utopia-php/dsn", @@ -1915,16 +1921,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.1.1", + "version": "dev-feat-push", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "a75d66ddd59b834ab500a4878a2c084e6572604a" + "reference": "5f85757316eb842e9169d318e234124ff252c404" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/a75d66ddd59b834ab500a4878a2c084e6572604a", - "reference": "a75d66ddd59b834ab500a4878a2c084e6572604a", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/5f85757316eb842e9169d318e234124ff252c404", + "reference": "5f85757316eb842e9169d318e234124ff252c404", "shasum": "" }, "require": { @@ -1933,8 +1939,8 @@ }, "require-dev": { "laravel/pint": "^1.2", - "phpmailer/phpmailer": "6.6.*", - "phpunit/phpunit": "9.5.*" + "phpmailer/phpmailer": "^6.8", + "phpunit/phpunit": "^9.6" }, "type": "library", "autoload": { @@ -1957,9 +1963,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.1.1" + "source": "https://github.com/utopia-php/messaging/tree/feat-push" }, - "time": "2023-02-07T05:42:46+00:00" + "time": "2023-08-14T20:35:31+00:00" }, { "name": "utopia-php/migration", @@ -5351,9 +5357,18 @@ "time": "2023-07-26T07:16:09+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/messaging", + "version": "dev-feat-push", + "alias": "0.1.1", + "alias_normalized": "0.1.1.0" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "utopia-php/messaging": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -5377,5 +5392,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } From 9f19bec7a74f090f15e996a7521b377ae355f48d Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 22 Aug 2023 18:21:30 +0530 Subject: [PATCH 024/196] lint fix --- app/controllers/api/messaging.php | 5 ++-- app/workers/messaging.php | 42 ++++++++++++++----------------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index f5ee54c852..8d1c13492e 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -11,8 +11,9 @@ use Utopia\Validator\ArrayList; use Utopia\Validator\Text; /** - * Email Providers + * Email Providers */ + App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun Provider') ->groups(['api', 'messaging']) @@ -69,7 +70,7 @@ App::post('/v1/messaging/messages/email') $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $message = $dbForProject->createDocument('messages', new Document([ diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 3e730b120a..5fba550baa 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -2,23 +2,19 @@ use Appwrite\Resque\Worker; use Utopia\CLI\Console; - use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Adapters\SMS\Msg91; use Utopia\Messaging\Adapters\SMS\Telesign; use Utopia\Messaging\Adapters\SMS\TextMagic; use Utopia\Messaging\Adapters\SMS\Twilio; use Utopia\Messaging\Adapters\SMS\Vonage; - use Utopia\Messaging\Adapters\Push as PushAdapter; use Utopia\Messaging\Adapters\Push\APNS; use Utopia\Messaging\Adapters\Push\FCM; - use Utopia\Messaging\Adapters\Email as EmailAdapter; use Utopia\Messaging\Adapters\Email\Mailgun; use Utopia\Messaging\Adapters\Email\SendGrid; - require_once __DIR__ . '/../init.php'; Console::title('Messaging V1 Worker'); @@ -29,8 +25,8 @@ class MessagingV1 extends Worker protected ?SMSAdapter $sms = null; protected ?PushAdapter $push = null; protected ?EmailAdapter $email = null; - - + + protected ?string $from = null; public function getName(): string @@ -48,7 +44,7 @@ class MessagingV1 extends Worker 'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']), 'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']), default => null - }; + }; } function push($record): ?PushAdapter @@ -56,15 +52,15 @@ class MessagingV1 extends Worker $credentials = $record->getAttribute('credentials'); return match ($record->getAttribute('provider')) { 'apns' => new APNS( - $credentials['authKey'], - $credentials['authKeyId'], - $credentials['teamId'], - $credentials['bundleId'], + $credentials['authKey'], + $credentials['authKeyId'], + $credentials['teamId'], + $credentials['bundleId'], $credentials['endpoint'] ), 'fcm' => new FCM($credentials['serverKey']), default => null - }; + }; } public function email($record): ?EmailAdapter @@ -74,7 +70,7 @@ class MessagingV1 extends Worker 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain']), 'sendgrid' => new SendGrid($credentials['apiKey']), default => null - }; + }; } public function init(): void @@ -83,25 +79,25 @@ class MessagingV1 extends Worker public function run(): void { - $providerId = $this->args['providerId']; - $providerRecord = + $providerId = $this->args['providerId']; + $providerRecord = $this ->getConsoleDB() ->getDocument('providers', $providerId); - $provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed. - 'sms' => $this->sms($providerRecord), - 'push' => $this->push($providerRecord), - 'email' => $this->email($providerRecord), - default => null - }; + $provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed. + 'sms' => $this->sms($providerRecord), + 'push' => $this->push($providerRecord), + 'email' => $this->email($providerRecord), + default => null + }; // Query for the provider // switch on provider name // call function passing needed credentials returns required provider. - $messageId = $this->args['messageId']; - $message = + $messageId = $this->args['messageId']; + $message = $this ->getConsoleDB() ->getDocument('messages', $messageId); From 78385a59c6ddd286d4d28cff98d8745f2c1e1caf Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 22 Aug 2023 22:15:31 +0530 Subject: [PATCH 025/196] adds remaining provider controllers --- app/config/errors.php | 6 +- app/controllers/api/account.php | 7 +- app/controllers/api/messaging.php | 861 +++++++++++++++++- app/controllers/api/users.php | 7 +- src/Appwrite/Extend/Exception.php | 1 + .../Database/Validator/Queries/Providers.php | 21 + 6 files changed, 885 insertions(+), 18 deletions(-) create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Providers.php diff --git a/app/config/errors.php b/app/config/errors.php index 99cde0baee..5942c6027c 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -696,7 +696,11 @@ return [ Exception::PROVIDER_NOT_FOUND => [ 'name' => Exception::PROVIDER_NOT_FOUND, 'description' => 'Provider with the request ID could not be found.', + 'code' => 404, + ], + Exception::PROVIDER_INCORRECT_TYPE => [ + 'name' => Exception::PROVIDER_INCORRECT_TYPE, + 'description' => 'Provider with the request ID is of incorrect type: ', 'code' => 400, - ] ]; diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index e6b0b2addc..46acd2efdb 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -3051,8 +3051,7 @@ App::post('/v1/account/targets') ])); $dbForProject->deleteCachedDocument('users', $user->getId()); $events - ->setParam('userId', $userId) - ->setParam('targetId', $targetId); + ->setParam('userId', $userId); $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($target, Response::MODEL_TARGET); @@ -3097,8 +3096,7 @@ App::patch('/v1/account/targets/:targetId/identifier') $dbForProject->deleteCachedDocument('users', $user->getId()); $events - ->setParam('userId', $userId) - ->setParam('targetId', $targetId); + ->setParam('userId', $userId); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -3145,7 +3143,6 @@ App::delete('/v1/account/targets/:targetId') $events ->setParam('userId', $userId) - ->setParam('targetId', $targetId) ->setPayload($response->output($clone, Response::MODEL_USER)); $response->noContent(); diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 8d1c13492e..14065f9097 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -2,18 +2,87 @@ use Appwrite\Event\Event; use Appwrite\Extend\Exception; +use Appwrite\Utopia\Database\Validator\Queries\Providers; use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime; +use Utopia\Database\Validator\UID; use Utopia\Validator\ArrayList; use Utopia\Validator\Text; +App::get('/v1/messaging/providers') + ->desc('List Providers') + ->groups(['api', 'messaging']) + ->label('scope', 'providers.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listProviders') + ->label('sdk.description', '/docs/references/messaging/list-providers.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER_LIST) + ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->inject('dbForProject') + ->inject('response') + ->action(function (array $queries, Database $dbForProject, Response $response) { + $queries = Query::parseQueries($queries); + + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); + + if ($cursor) { + $providerId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ + Query::equal('$id', [$providerId]), + Query::limit(1), + ])); + + if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument[0]); + } + + $filterQueries = Query::groupByType($queries)['filters']; + $response->dynamic(new Document([ + 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), + 'indexes' => $dbForProject->find('providers', $queries), + ]), Response::MODEL_PROVIDER_LIST); + }); + +App::get('/v1/messaging/providers/:id') + ->desc('Get Provider') + ->groups(['api', 'messaging']) + ->label('scope', 'providers.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'getProvider') + ->label('sdk.description', '/docs/references/messaging/get-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', null, new UID(), 'Provider ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, Response $response, Database $dbForProject) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $response->dynamic($provider, Response::MODEL_PROVIDER); + }); + /** * Email Providers */ - App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun Provider') ->groups(['api', 'messaging']) @@ -21,23 +90,24 @@ App::post('/v1/messaging/providers/mailgun') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderMailgun') ->label('sdk.description', '/docs/references/messaging/create-provider-mailgun.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('name', '', new Text(128), 'Provider name.') - ->param('apiKey', null, new Text(0), 'Mailgun API Key.', true) - ->param('domain', null, new Text(0), 'Mailgun Domain.', true) + ->param('apiKey', '', new Text(0), 'Mailgun API Key.') + ->param('domain', '', new Text(0), 'Mailgun Domain.') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { $provider = $dbForProject->createDocument('providers', new Document([ 'name' => $name, - 'provider' => 'Mailgun', + 'provider' => 'mailgun', 'type' => 'email', 'credentials' => [ 'apiKey' => $apiKey, - 'domain' => $domain + 'domain' => $domain, ], ])); $response @@ -45,6 +115,782 @@ App::post('/v1/messaging/providers/mailgun') ->dynamic($provider, Response::MODEL_PROVIDER); }); +App::patch('/v1/messaging/providers/:id/mailgun') + ->desc('Update Mailgun Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.update') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderMailgun') + ->label('sdk.description', '/docs/references/messaging/update-provider-mailgun.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) + ->param('domain', '', new Text(0), 'Mailgun Domain.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); + + if ($providerAttr !== 'mailgun') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($apiKey || $domain) { + // Check if all five variables are present + if ($apiKey && $domain) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'domain' => $domain + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/sendgrid') + ->desc('Create Sendgrid Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.create') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderSendgrid') + ->label('sdk.description', '/docs/references/messaging/create-provider-sendgrid.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('apiKey', '', new Text(0), 'Sendgrid API key.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'sendgrid', + 'type' => 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/sendgrid') + ->desc('Update Sendgrid Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.update') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderSendgrid') + ->label('sdk.description', '/docs/references/messaging/update-provider-sendgrid.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); + + if ($providerAttr !== 'sendgrid') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($apiKey) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey + ]); + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +/** + * SMS Providers + */ +App::post('/v1/messaging/providers/msg91') + ->desc('Create Msg91 Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.create') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderMsg91') + ->label('sdk.description', '/docs/references/messaging/create-provider-msg91.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') + ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'msg91', + 'type' => 'sms', + 'credentials' => [ + 'senderId' => $senderId, + 'authKey' => $authKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/msg91') + ->desc('Update Msg91 Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.update') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderMsg91') + ->label('sdk.description', '/docs/references/messaging/update-provider-msg91.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) + ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); + + if ($providerAttr !== 'msg91') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($senderId || $authKey) { + // Check if all five variables are present + if ($senderId && $authKey) { + $provider->setAttribute('credentials', [ + 'senderId' => $senderId, + 'authKey' => $authKey + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/telesign') + ->desc('Create Telesign Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.create') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderTelesign') + ->label('sdk.description', '/docs/references/messaging/create-provider-telesign.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('username', '', new Text(0), 'Telesign username.') + ->param('password', '', new Text(0), 'Telesign password.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $username, string $password, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'telesign', + 'type' => 'sms', + 'credentials' => [ + 'username' => $username, + 'password' => $password, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/telesign') + ->desc('Update Telesign Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.update') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderTelesign') + ->label('sdk.description', '/docs/references/messaging/update-provider-telesign.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('username', '', new Text(0), 'Telesign username.', true) + ->param('password', '', new Text(0), 'Telesign password.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $username, string $password, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); + + if ($providerAttr !== 'telesign') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($username || $password) { + // Check if all five variables are present + if ($username && $password) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'password' => $password + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/textmagic') + ->desc('Create Textmagic Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.create') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderTextmagic') + ->label('sdk.description', '/docs/references/messaging/create-provider-textmagic.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('username', '', new Text(0), 'Textmagic username.') + ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'text-magic', + 'type' => 'sms', + 'credentials' => [ + 'username' => $username, + 'apiKey' => $apiKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/textmagic') + ->desc('Update Textmagic Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.update') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderTextmagic') + ->label('sdk.description', '/docs/references/messaging/update-provider-textmagic.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('username', '', new Text(0), 'Textmagic username.', true) + ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); + + if ($providerAttr !== 'text-magic') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($username || $apiKey) { + // Check if all five variables are present + if ($username && $apiKey) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'apiKey' => $apiKey + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/twilio') + ->desc('Create Twilio Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.create') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderTwilio') + ->label('sdk.description', '/docs/references/messaging/create-provider-twilio.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') + ->param('authToken', '', new Text(0), 'Twilio authentication token.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'twilio', + 'type' => 'sms', + 'credentials' => [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/twilio') + ->desc('Update Twilio Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.update') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderTwilio') + ->label('sdk.description', '/docs/references/messaging/update-provider-twilio.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) + ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); + + if ($providerAttr !== 'twilio') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($accountSid || $authToken) { + // Check if all five variables are present + if ($accountSid && $authToken) { + $provider->setAttribute('credentials', [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/vonage') + ->desc('Create Vonage Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.create') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderVonage') + ->label('sdk.description', '/docs/references/messaging/create-provider-vonage.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('apiKey', '', new Text(0), 'Vonage API key.') + ->param('apiSecret', '', new Text(0), 'Vonage API secret.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'vonage', + 'type' => 'sms', + 'credentials' => [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/vonage') + ->desc('Update Vonage Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.update') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderVonage') + ->label('sdk.description', '/docs/references/messaging/update-provider-vonage.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('apiKey', '', new Text(0), 'Vonage API key.', true) + ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); + + if ($providerAttr !== 'vonage') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($apiKey || $apiSecret) { + // Check if all five variables are present + if ($apiKey && $apiSecret) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +/** + * Push Providers + */ +App::post('/v1/messaging/providers/fcm') + ->desc('Create FCM Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.create') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderFCM') + ->label('sdk.description', '/docs/references/messaging/create-provider-fcm.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('serverKey', '', new Text(0), 'FCM Server Key.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $serverKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'fcm', + 'type' => 'push', + 'credentials' => [ + 'serverKey' => $serverKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/fcm') + ->desc('Update FCM Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.update') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderFCM') + ->label('sdk.description', '/docs/references/messaging/update-provider-fcm.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $serverKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); + + if ($providerAttr !== 'fcm') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($serverKey) { + $provider->setAttribute('credentials', ['serverKey' => $serverKey]); + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/apns') + ->desc('Create APNS Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.create') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderAPNS') + ->label('sdk.description', '/docs/references/messaging/create-provider-apns.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('authKey', '', new Text(0), 'APNS authentication key.') + ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') + ->param('teamId', '', new Text(0), 'APNS team ID.') + ->param('bundleId', '', new Text(0), 'APNS bundle ID.') + ->param('endpoint', '', new Text(0), 'APNS endpoint.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'apns', + 'type' => 'push', + 'credentials' => [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/apns') + ->desc('Update APNS Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.update') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderAPNS') + ->label('sdk.description', '/docs/references/messaging/update-provider-apns.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('authKey', '', new Text(0), 'APNS authentication key.', true) + ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) + ->param('teamId', '', new Text(0), 'APNS team ID.', true) + ->param('bundleId', '', new Text(0), 'APNS bundle ID.', true) + ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); + + if ($providerAttr !== 'apns') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { + // Check if all five variables are present + if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { + $provider->setAttribute('credentials', [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::delete('/v1/messaging/providers/:id') + ->desc('Delete Provider') + ->groups(['api', 'messaging']) + ->label('event', 'messages.providers.[id].delete') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'deleteProvider') + ->label('sdk.description', '/docs/references/messaging/delete-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('id', '', new UID(), 'Provider ID.') + ->inject('response') + ->inject('dbForProject') + ->inject('events') + ->action(function (string $id, Response $response, Database $dbForProject) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $dbForProject->deleteDocument('providers', $provider->getId()); + + $response->noContent(); + }); + App::post('/v1/messaging/messages/email') ->desc('Send an email.') ->groups(['api', 'messaging']) @@ -52,6 +898,7 @@ App::post('/v1/messaging/messages/email') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'sendEmail') ->label('sdk.description', '/docs/references/messaging/send-email.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -70,7 +917,7 @@ App::post('/v1/messaging/messages/email') $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $message = $dbForProject->createDocument('messages', new Document([ @@ -85,7 +932,7 @@ App::post('/v1/messaging/messages/email') 'deliveryError' => null, 'deliveredTo' => null, 'delivered' => false, - 'search' => null + 'search' => null, ])); $eventsInstance->setParam('messageId', $message->getId()); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index e6d5e8e1b9..cf94135351 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -425,8 +425,7 @@ App::post('/v1/users/:userId/targets') ])); $dbForProject->deleteCachedDocument('users', $user->getId()); $events - ->setParam('userId', $userId) - ->setParam('targetId', $targetId); + ->setParam('userId', $userId); $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($target, Response::MODEL_TARGET); @@ -1251,8 +1250,7 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') $dbForProject->deleteCachedDocument('users', $user->getId()); $events - ->setParam('userId', $userId) - ->setParam('targetId', $targetId); + ->setParam('userId', $userId); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -1426,7 +1424,6 @@ App::delete('/v1/users/:userId/targets/:targetId') $events ->setParam('userId', $userId) - ->setParam('targetId', $targetId) ->setPayload($response->output($clone, Response::MODEL_USER)); $response->noContent(); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index a3e6817645..d5803f5fbf 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -214,6 +214,7 @@ class Exception extends \Exception /** Provider */ public const PROVIDER_NOT_FOUND = 'provider_not_found'; + public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; protected $type = ''; protected $errors = []; diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php new file mode 100644 index 0000000000..83dbf665f1 --- /dev/null +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php @@ -0,0 +1,21 @@ + Date: Tue, 22 Aug 2023 22:16:09 +0530 Subject: [PATCH 026/196] lint fix --- app/controllers/api/messaging.php | 210 +++++++++++++++--------------- 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 14065f9097..ba1d66b1ed 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -36,17 +36,17 @@ App::get('/v1/messaging/providers') $cursor = reset($cursor); if ($cursor) { - $providerId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ + $providerId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ Query::equal('$id', [$providerId]), Query::limit(1), ])); - if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { - throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); - } + if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); + } - $cursor->setValue($cursorDocument[0]); + $cursor->setValue($cursorDocument[0]); } $filterQueries = Query::groupByType($queries)['filters']; @@ -74,7 +74,7 @@ App::get('/v1/messaging/providers/:id') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $response->dynamic($provider, Response::MODEL_PROVIDER); @@ -137,29 +137,29 @@ App::patch('/v1/messaging/providers/:id/mailgun') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'mailgun') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { - $provider->setAttribute('name', $name); + $provider->setAttribute('name', $name); } if ($apiKey || $domain) { // Check if all five variables are present - if ($apiKey && $domain) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'domain' => $domain - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + if ($apiKey && $domain) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'domain' => $domain + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); @@ -221,22 +221,22 @@ App::patch('/v1/messaging/providers/:id/sendgrid') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'sendgrid') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { - $provider->setAttribute('name', $name); + $provider->setAttribute('name', $name); } if ($apiKey) { - $provider->setAttribute('credentials', [ + $provider->setAttribute('credentials', [ 'apiKey' => $apiKey - ]); + ]); } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); @@ -304,29 +304,29 @@ App::patch('/v1/messaging/providers/:id/msg91') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'msg91') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { - $provider->setAttribute('name', $name); + $provider->setAttribute('name', $name); } if ($senderId || $authKey) { // Check if all five variables are present - if ($senderId && $authKey) { - $provider->setAttribute('credentials', [ - 'senderId' => $senderId, - 'authKey' => $authKey - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + if ($senderId && $authKey) { + $provider->setAttribute('credentials', [ + 'senderId' => $senderId, + 'authKey' => $authKey + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); @@ -391,29 +391,29 @@ App::patch('/v1/messaging/providers/:id/telesign') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'telesign') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { - $provider->setAttribute('name', $name); + $provider->setAttribute('name', $name); } if ($username || $password) { // Check if all five variables are present - if ($username && $password) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'password' => $password - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + if ($username && $password) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'password' => $password + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); @@ -478,29 +478,29 @@ App::patch('/v1/messaging/providers/:id/textmagic') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'text-magic') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { - $provider->setAttribute('name', $name); + $provider->setAttribute('name', $name); } if ($username || $apiKey) { // Check if all five variables are present - if ($username && $apiKey) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'apiKey' => $apiKey - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + if ($username && $apiKey) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'apiKey' => $apiKey + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); @@ -565,29 +565,29 @@ App::patch('/v1/messaging/providers/:id/twilio') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'twilio') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { - $provider->setAttribute('name', $name); + $provider->setAttribute('name', $name); } if ($accountSid || $authToken) { // Check if all five variables are present - if ($accountSid && $authToken) { - $provider->setAttribute('credentials', [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + if ($accountSid && $authToken) { + $provider->setAttribute('credentials', [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); @@ -652,29 +652,29 @@ App::patch('/v1/messaging/providers/:id/vonage') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'vonage') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { - $provider->setAttribute('name', $name); + $provider->setAttribute('name', $name); } if ($apiKey || $apiSecret) { // Check if all five variables are present - if ($apiKey && $apiSecret) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + if ($apiKey && $apiSecret) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); @@ -739,20 +739,20 @@ App::patch('/v1/messaging/providers/:id/fcm') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'fcm') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { - $provider->setAttribute('name', $name); + $provider->setAttribute('name', $name); } if ($serverKey) { - $provider->setAttribute('credentials', ['serverKey' => $serverKey]); + $provider->setAttribute('credentials', ['serverKey' => $serverKey]); } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); @@ -826,32 +826,32 @@ App::patch('/v1/messaging/providers/:id/apns') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'apns') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { - $provider->setAttribute('name', $name); + $provider->setAttribute('name', $name); } if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { // Check if all five variables are present - if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { - $provider->setAttribute('credentials', [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { + $provider->setAttribute('credentials', [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); @@ -882,7 +882,7 @@ App::delete('/v1/messaging/providers/:id') $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $dbForProject->deleteCachedDocument('providers', $provider->getId()); @@ -917,7 +917,7 @@ App::post('/v1/messaging/messages/email') $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + throw new Exception(Exception::PROVIDER_NOT_FOUND); } $message = $dbForProject->createDocument('messages', new Document([ From dbbf4522e301d53c32623a80d0d659c123d9613f Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 22 Aug 2023 22:17:32 +0530 Subject: [PATCH 027/196] lint fix --- app/workers/messaging.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 5fba550baa..0ed9853e41 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -47,7 +47,7 @@ class MessagingV1 extends Worker }; } - function push($record): ?PushAdapter + public function push($record): ?PushAdapter { $credentials = $record->getAttribute('credentials'); return match ($record->getAttribute('provider')) { @@ -106,7 +106,7 @@ class MessagingV1 extends Worker // Send the message using respective adapter } - function shutdown(): void + public function shutdown(): void { } } From c225563d776ef5da3ae641b964cef15619d5fe17 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 23 Aug 2023 15:31:29 +0530 Subject: [PATCH 028/196] adds test for provider controllers --- app/config/roles.php | 8 + app/controllers/api/messaging.php | 58 +++--- phpunit.xml | 1 + tests/e2e/Scopes/ProjectCustom.php | 4 + .../Messaging/MessagingServerTest.php | 187 ++++++++++++++++++ 5 files changed, 224 insertions(+), 34 deletions(-) create mode 100644 tests/e2e/Services/Messaging/MessagingServerTest.php diff --git a/app/config/roles.php b/app/config/roles.php index a95b34d820..4bc85f7a28 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -22,6 +22,10 @@ $member = [ 'execution.write', 'targets.read', 'targets.write', + 'providers.write', + 'providers.read', + 'messages.write', + 'messages.read' ]; $admins = [ @@ -57,6 +61,10 @@ $admins = [ 'migrations.write', 'targets.read', 'targets.write', + 'providers.write', + 'providers.read', + 'messages.write', + 'messages.read' ]; return [ diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index ba1d66b1ed..1ff95fbeea 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -70,7 +70,7 @@ App::get('/v1/messaging/providers/:id') ->param('id', null, new UID(), 'Provider ID.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, Response $response, Database $dbForProject) { + ->action(function (string $id, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -86,7 +86,7 @@ App::get('/v1/messaging/providers/:id') App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.create') + ->label('audits.event', 'messages.providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -118,7 +118,7 @@ App::post('/v1/messaging/providers/mailgun') App::patch('/v1/messaging/providers/:id/mailgun') ->desc('Update Mailgun Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.update') + ->label('audits.event', 'messages.providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -166,14 +166,13 @@ App::patch('/v1/messaging/providers/:id/mailgun') $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/sendgrid') ->desc('Create Sendgrid Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.create') + ->label('audits.event', 'messages.providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -203,7 +202,7 @@ App::post('/v1/messaging/providers/sendgrid') App::patch('/v1/messaging/providers/:id/sendgrid') ->desc('Update Sendgrid Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.update') + ->label('audits.event', 'messages.providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -243,7 +242,6 @@ App::patch('/v1/messaging/providers/:id/sendgrid') $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -253,7 +251,7 @@ App::patch('/v1/messaging/providers/:id/sendgrid') App::post('/v1/messaging/providers/msg91') ->desc('Create Msg91 Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.create') + ->label('audits.event', 'messages.providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -285,7 +283,7 @@ App::post('/v1/messaging/providers/msg91') App::patch('/v1/messaging/providers/:id/msg91') ->desc('Update Msg91 Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.update') + ->label('audits.event', 'messages.providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -333,14 +331,13 @@ App::patch('/v1/messaging/providers/:id/msg91') $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/telesign') ->desc('Create Telesign Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.create') + ->label('audits.event', 'messages.providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -372,7 +369,7 @@ App::post('/v1/messaging/providers/telesign') App::patch('/v1/messaging/providers/:id/telesign') ->desc('Update Telesign Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.update') + ->label('audits.event', 'messages.providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -420,14 +417,13 @@ App::patch('/v1/messaging/providers/:id/telesign') $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/textmagic') ->desc('Create Textmagic Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.create') + ->label('audits.event', 'messages.providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -459,7 +455,7 @@ App::post('/v1/messaging/providers/textmagic') App::patch('/v1/messaging/providers/:id/textmagic') ->desc('Update Textmagic Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.update') + ->label('audits.event', 'messages.providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -507,14 +503,13 @@ App::patch('/v1/messaging/providers/:id/textmagic') $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/twilio') ->desc('Create Twilio Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.create') + ->label('audits.event', 'messages.providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -546,7 +541,7 @@ App::post('/v1/messaging/providers/twilio') App::patch('/v1/messaging/providers/:id/twilio') ->desc('Update Twilio Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.update') + ->label('audits.event', 'messages.providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -594,14 +589,13 @@ App::patch('/v1/messaging/providers/:id/twilio') $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/vonage') ->desc('Create Vonage Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.create') + ->label('audits.event', 'messages.providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -633,7 +627,7 @@ App::post('/v1/messaging/providers/vonage') App::patch('/v1/messaging/providers/:id/vonage') ->desc('Update Vonage Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.update') + ->label('audits.event', 'messages.providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -681,7 +675,6 @@ App::patch('/v1/messaging/providers/:id/vonage') $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -691,7 +684,7 @@ App::patch('/v1/messaging/providers/:id/vonage') App::post('/v1/messaging/providers/fcm') ->desc('Create FCM Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.create') + ->label('audits.event', 'messages.providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -721,7 +714,7 @@ App::post('/v1/messaging/providers/fcm') App::patch('/v1/messaging/providers/:id/fcm') ->desc('Update FCM Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.update') + ->label('audits.event', 'messages.providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -759,14 +752,13 @@ App::patch('/v1/messaging/providers/:id/fcm') $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/apns') ->desc('Create APNS Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.create') + ->label('audits.event', 'messages.providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -804,7 +796,7 @@ App::post('/v1/messaging/providers/apns') App::patch('/v1/messaging/providers/:id/apns') ->desc('Update APNS Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.update') + ->label('audits.event', 'messages.providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -858,27 +850,25 @@ App::patch('/v1/messaging/providers/:id/apns') $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); App::delete('/v1/messaging/providers/:id') ->desc('Delete Provider') ->groups(['api', 'messaging']) - ->label('event', 'messages.providers.[id].delete') + ->label('audits.event', 'messages.providers.delete') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'deleteProvider') ->label('sdk.description', '/docs/references/messaging/delete-provider.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) ->param('id', '', new UID(), 'Provider ID.') - ->inject('response') ->inject('dbForProject') - ->inject('events') - ->action(function (string $id, Response $response, Database $dbForProject) { + ->inject('response') + ->action(function (string $id, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -894,7 +884,7 @@ App::delete('/v1/messaging/providers/:id') App::post('/v1/messaging/messages/email') ->desc('Send an email.') ->groups(['api', 'messaging']) - ->label('event', 'messages.create') + ->label('audits.event', 'messages.create') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') diff --git a/phpunit.xml b/phpunit.xml index f83f9f0fae..cffe166336 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -32,6 +32,7 @@ ./tests/e2e/Services/Teams ./tests/e2e/Services/Users ./tests/e2e/Services/Webhooks + ./tests/e2e/Services/Messaging ./tests/e2e/Services/Functions/FunctionsBase.php ./tests/e2e/Services/Functions/FunctionsCustomServerTest.php ./tests/e2e/Services/Functions/FunctionsCustomClientTest.php diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index 1bd4de501c..ee41129fde 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -81,6 +81,10 @@ trait ProjectCustom 'locale.read', 'avatars.read', 'health.read', + 'providers.read', + 'providers.write', + 'messages.read', + 'messages.write', ], ]); diff --git a/tests/e2e/Services/Messaging/MessagingServerTest.php b/tests/e2e/Services/Messaging/MessagingServerTest.php new file mode 100644 index 0000000000..2547c8a756 --- /dev/null +++ b/tests/e2e/Services/Messaging/MessagingServerTest.php @@ -0,0 +1,187 @@ + [ + 'name' => 'Sengrid1', + 'apiKey' => 'my-apikey', + ], + 'mailgun' => [ + 'name' => 'Mailgun1', + 'apiKey' => 'my-apikey', + 'domain' => 'my-domain', + ], + 'twilio' => [ + 'name' => 'Twilio1', + 'accountSid' => 'my-accountSid', + 'authToken' => 'my-authToken', + ], + 'telesign' => [ + 'name' => 'Telesign1', + 'username' => 'my-username', + 'password' => 'my-password', + ], + 'textmagic' => [ + 'name' => 'Textmagic1', + 'username' => 'my-username', + 'apiKey' => 'my-apikey', + ], + 'msg91' => [ + 'name' => 'Ms91-1', + 'senderId' => 'my-senderid', + 'authKey' => 'my-authkey', + ], + 'vonage' => [ + 'name' => 'Vonage1', + 'apiKey' => 'my-apikey', + 'apiSecret' => 'my-apisecret', + ], + 'fcm' => [ + 'name' => 'FCM1', + 'serverKey' => 'my-serverkey', + ], + 'apns' => [ + 'name' => 'APNS1', + 'authKey' => 'my-authkey', + 'authKeyId' => 'my-authkeyid', + 'teamId' => 'my-teamid', + 'bundleId' => 'my-bundleid', + 'endpoint' => 'my-endpoint', + ], + ]; + $providers = []; + + foreach (\array_keys($providersParams) as $key) { + $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/'.$key, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], $providersParams[$key]); + \array_push($providers, $response['body']); + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertEquals($providersParams[$key]['name'], $response['body']['name']); + } + + return $providers; + } + + /** + * @depends testCreateProviders + */ + public function testUpdateProviders(array $providers): array + { + $providersParams = [ + 'sendgrid' => [ + 'name' => 'Sengrid2', + 'apiKey' => 'my-apikey', + ], + 'mailgun' => [ + 'name' => 'Mailgun2', + 'apiKey' => 'my-apikey', + 'domain' => 'my-domain', + ], + 'twilio' => [ + 'name' => 'Twilio2', + 'accountSid' => 'my-accountSid', + 'authToken' => 'my-authToken', + ], + 'telesign' => [ + 'name' => 'Telesign2', + 'username' => 'my-username', + 'password' => 'my-password', + ], + 'textmagic' => [ + 'name' => 'Textmagic2', + 'username' => 'my-username', + 'apiKey' => 'my-apikey', + ], + 'msg91' => [ + 'name' => 'Ms91-2', + 'senderId' => 'my-senderid', + 'authKey' => 'my-authkey', + ], + 'vonage' => [ + 'name' => 'Vonage2', + 'apiKey' => 'my-apikey', + 'apiSecret' => 'my-apisecret', + ], + 'fcm' => [ + 'name' => 'FCM2', + 'serverKey' => 'my-serverkey', + ], + 'apns' => [ + 'name' => 'APNS2', + 'authKey' => 'my-authkey', + 'authKeyId' => 'my-authkeyid', + 'teamId' => 'my-teamid', + 'bundleId' => 'my-bundleid', + 'endpoint' => 'my-endpoint', + ], + ]; + foreach (\array_keys($providersParams) as $index => $key) { + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/'. $providers[$index]['$id'] . '/' . $key, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], $providersParams[$key]); + $providers[$index] = $response['body']; + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($providersParams[$key]['name'], $response['body']['name']); + } + + return $providers; + } + + /** + * @depends testUpdateProviders + */ + public function testListProviders(array $providers) { + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(\count($providers), $response['body']['total']); + } + + /** + * @depends testUpdateProviders + */ + public function testGetProvider(array $providers) { + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' .$providers[0]['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($providers[0]['name'], $response['body']['name']); + } + + /** + * @depends testUpdateProviders + */ + public function testDeleteProvider(array $providers) { + foreach ($providers as $provider) { + $response = $this->client->call(Client::METHOD_DELETE, '/messaging/providers/'. $provider['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(204, $response['headers']['status-code']); + } + } +} From 55d00d9afaac9cb40662076c4e9423db72cb3e54 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 23 Aug 2023 15:36:12 +0530 Subject: [PATCH 029/196] lint fix --- .../Services/Messaging/MessagingServerTest.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/e2e/Services/Messaging/MessagingServerTest.php b/tests/e2e/Services/Messaging/MessagingServerTest.php index 2547c8a756..7b93ab29ac 100644 --- a/tests/e2e/Services/Messaging/MessagingServerTest.php +++ b/tests/e2e/Services/Messaging/MessagingServerTest.php @@ -65,7 +65,7 @@ class MessagingServerTest extends Scope $providers = []; foreach (\array_keys($providersParams) as $key) { - $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/'.$key, [ + $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/' . $key, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -132,7 +132,7 @@ class MessagingServerTest extends Scope ], ]; foreach (\array_keys($providersParams) as $index => $key) { - $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/'. $providers[$index]['$id'] . '/' . $key, [ + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/' . $providers[$index]['$id'] . '/' . $key, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -148,7 +148,8 @@ class MessagingServerTest extends Scope /** * @depends testUpdateProviders */ - public function testListProviders(array $providers) { + public function testListProviders(array $providers) + { $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -161,8 +162,9 @@ class MessagingServerTest extends Scope /** * @depends testUpdateProviders */ - public function testGetProvider(array $providers) { - $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' .$providers[0]['$id'], [ + public function testGetProvider(array $providers) + { + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -174,9 +176,10 @@ class MessagingServerTest extends Scope /** * @depends testUpdateProviders */ - public function testDeleteProvider(array $providers) { + public function testDeleteProvider(array $providers) + { foreach ($providers as $provider) { - $response = $this->client->call(Client::METHOD_DELETE, '/messaging/providers/'. $provider['$id'], [ + $response = $this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $provider['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], From 3e7805afe1a7ad48d0628516fe5c640fa532909d Mon Sep 17 00:00:00 2001 From: wess Date: Wed, 23 Aug 2023 08:49:32 -0400 Subject: [PATCH 030/196] Updates deps Adds message builders to messaging worker Adds Makefile to .gitignore ;) --- .gitignore | 1 + app/workers/messaging.php | 63 +++++++++++++++++++++++++++++++++++---- composer.lock | 13 ++++---- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 3151de5adb..ac88830b49 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ debug/ app/sdks dev/yasd_init.php .phpunit.result.cache +Makefile diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 0ed9853e41..e958d5ece4 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -97,16 +97,67 @@ class MessagingV1 extends Worker // call function passing needed credentials returns required provider. $messageId = $this->args['messageId']; - $message = - $this - ->getConsoleDB() - ->getDocument('messages', $messageId); + $messageRecord = + $this + ->getConsoleDB() + ->getDocument('messages', $messageId); - // Contrust Message Object according to each provider type. - // Send the message using respective adapter + $message = match ($providerRecord->getAttribute('type')) { + 'sms' => $this->buildSMSMessage($messageRecord->getArrayCopy()), + 'push' => $this->buildPushMessage($messageRecord->getArrayCopy()), + 'email' => $this->buildEmailMessage($messageRecord->getArrayCopy()), + default => null + }; + + + $provider->send($message); } public function shutdown(): void { } + + private function buildEmailMessage($data): array + { + $from = $data['from']; + $to = $data['to']; + $subject = $data['subject']; + $body = $data['content']; + + return [ + 'from' => $from, + 'to' => $to, + 'subject' => $subject, + 'body' => $body, + ]; + return $message; + } + + private function buildSMSMessage($data): array + { + $from = $data['from']; + $to = $data['to']; + $body = $data['content']; + + return [ + 'from' => $from, + 'to' => $to, + 'body' => $body + ]; + } + + private function buildPushMessage($data): array + { + $to = $data['to']; + $title = $data['title']; + $body = $data['body']; + $data = $data['data']; + + return [ + 'to' => $to, + 'title' => $title, + 'body' => $body, + 'data' => $data + ]; + } } diff --git a/composer.lock b/composer.lock index 55e84a6e74..f2b39d8414 100644 --- a/composer.lock +++ b/composer.lock @@ -1557,19 +1557,20 @@ }, { "name": "utopia-php/database", - "version": "0.42.2", + "version": "0.42.3", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "bc5ceb30c85fb685b0b5704d2f74886d813ebd41" + "reference": "ab0e2f8ad46884f69b354cd8ee84a1a75fee26d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/bc5ceb30c85fb685b0b5704d2f74886d813ebd41", - "reference": "bc5ceb30c85fb685b0b5704d2f74886d813ebd41", + "url": "https://api.github.com/repos/utopia-php/database/zipball/ab0e2f8ad46884f69b354cd8ee84a1a75fee26d1", + "reference": "ab0e2f8ad46884f69b354cd8ee84a1a75fee26d1", "shasum": "" }, "require": { + "ext-mbstring": "*", "ext-pdo": "*", "php": ">=8.0", "utopia-php/cache": "0.8.*", @@ -1607,9 +1608,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.42.2" + "source": "https://github.com/utopia-php/database/tree/0.42.3" }, - "time": "2023-08-17T19:04:37+00:00" + "time": "2023-08-22T02:15:28+00:00" }, { "name": "utopia-php/domains", From eba91ae55a2f446e65bac1b15181b9a12c12941c Mon Sep 17 00:00:00 2001 From: wess Date: Wed, 23 Aug 2023 12:22:04 -0400 Subject: [PATCH 031/196] Stubbing in tests and message builder --- app/workers/messaging.php | 1 - tests/e2e/Services/Messaging/MessagingServerTest.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/workers/messaging.php b/app/workers/messaging.php index e958d5ece4..84af6fa802 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -130,7 +130,6 @@ class MessagingV1 extends Worker 'subject' => $subject, 'body' => $body, ]; - return $message; } private function buildSMSMessage($data): array diff --git a/tests/e2e/Services/Messaging/MessagingServerTest.php b/tests/e2e/Services/Messaging/MessagingServerTest.php index 7b93ab29ac..9bc9f93caf 100644 --- a/tests/e2e/Services/Messaging/MessagingServerTest.php +++ b/tests/e2e/Services/Messaging/MessagingServerTest.php @@ -187,4 +187,5 @@ class MessagingServerTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } } + } From bf5f0a841921920e3a2cca09875fa9946d73ce89 Mon Sep 17 00:00:00 2001 From: wess Date: Wed, 23 Aug 2023 13:12:43 -0400 Subject: [PATCH 032/196] Pint linter ran --- app/cli.php | 31 +- app/config/authProviders.php | 14 +- app/config/avatars/browsers.php | 29 +- app/config/avatars/credit-cards.php | 34 +- app/config/avatars/flags.php | 388 +++--- app/config/avatars/os.php | 6 +- app/config/collections.php | 48 +- app/config/errors.php | 8 +- app/config/events.php | 66 +- app/config/locale/codes.php | 525 ++++---- app/config/locale/languages.php | 1106 ++++++++--------- app/config/locale/templates.php | 4 +- app/config/messagingProviders.php | 586 ++++----- app/config/platforms.php | 44 +- app/config/regions.php | 2 +- app/config/roles.php | 4 +- app/config/runtimes.php | 2 +- app/config/scopes.php | 4 +- app/config/services.php | 6 +- app/config/usage.php | 40 +- app/config/variables.php | 196 +-- app/controllers/api/account.php | 527 ++++---- app/controllers/api/avatars.php | 169 ++- app/controllers/api/console.php | 3 - app/controllers/api/databases.php | 642 +++++----- app/controllers/api/functions.php | 207 ++- app/controllers/api/graphql.php | 23 +- app/controllers/api/health.php | 98 +- app/controllers/api/locale.php | 27 +- app/controllers/api/messaging.php | 788 ++++++------ app/controllers/api/migrations.php | 40 +- app/controllers/api/project.php | 28 +- app/controllers/api/projects.php | 178 +-- app/controllers/api/storage.php | 306 +++-- app/controllers/api/teams.php | 175 ++- app/controllers/api/users.php | 139 +-- app/controllers/general.php | 157 ++- app/controllers/mock.php | 69 +- app/controllers/shared/api.php | 107 +- app/controllers/shared/api/auth.php | 3 +- app/controllers/web/console.php | 24 +- app/controllers/web/home.php | 4 +- app/http.php | 76 +- app/init.php | 303 ++--- app/preload.php | 40 +- app/realtime.php | 149 ++- app/worker.php | 40 +- app/workers/audits.php | 6 +- app/workers/builds.php | 39 +- app/workers/certificates.php | 144 +-- app/workers/databases.php | 104 +- app/workers/deletes.php | 275 ++-- app/workers/functions.php | 40 +- app/workers/mails.php | 18 +- app/workers/messaging.php | 37 +- app/workers/migrations.php | 4 +- app/workers/usage.php | 92 +- app/workers/webhooks.php | 30 +- src/Appwrite/Auth/Auth.php | 117 +- src/Appwrite/Auth/Hash.php | 25 +- src/Appwrite/Auth/Hash/Argon2.php | 10 +- src/Appwrite/Auth/Hash/Bcrypt.php | 12 +- src/Appwrite/Auth/Hash/Md5.php | 10 +- src/Appwrite/Auth/Hash/Phpass.php | 61 +- src/Appwrite/Auth/Hash/Scrypt.php | 12 +- src/Appwrite/Auth/Hash/Scryptmodified.php | 14 +- src/Appwrite/Auth/Hash/Sha.php | 12 +- src/Appwrite/Auth/OAuth2.php | 56 +- src/Appwrite/Auth/OAuth2/Amazon.php | 40 +- src/Appwrite/Auth/OAuth2/Apple.php | 47 +- src/Appwrite/Auth/OAuth2/Auth0.php | 41 +- src/Appwrite/Auth/OAuth2/Authentik.php | 47 +- src/Appwrite/Auth/OAuth2/Autodesk.php | 29 +- src/Appwrite/Auth/OAuth2/Bitbucket.php | 32 +- src/Appwrite/Auth/OAuth2/Bitly.php | 57 +- src/Appwrite/Auth/OAuth2/Box.php | 53 +- src/Appwrite/Auth/OAuth2/Dailymotion.php | 50 +- src/Appwrite/Auth/OAuth2/Discord.php | 39 +- src/Appwrite/Auth/OAuth2/Disqus.php | 36 +- src/Appwrite/Auth/OAuth2/Dropbox.php | 31 +- src/Appwrite/Auth/OAuth2/Etsy.php | 33 +- src/Appwrite/Auth/OAuth2/Exception.php | 6 +- src/Appwrite/Auth/OAuth2/Facebook.php | 39 +- src/Appwrite/Auth/OAuth2/Firebase.php | 75 +- src/Appwrite/Auth/OAuth2/Github.php | 40 +- src/Appwrite/Auth/OAuth2/Gitlab.php | 40 +- src/Appwrite/Auth/OAuth2/Google.php | 37 +- src/Appwrite/Auth/OAuth2/Linkedin.php | 33 +- src/Appwrite/Auth/OAuth2/Microsoft.php | 40 +- src/Appwrite/Auth/OAuth2/Mock.php | 38 +- src/Appwrite/Auth/OAuth2/Notion.php | 43 +- src/Appwrite/Auth/OAuth2/Oidc.php | 82 +- src/Appwrite/Auth/OAuth2/Okta.php | 41 +- src/Appwrite/Auth/OAuth2/Paypal.php | 41 +- src/Appwrite/Auth/OAuth2/PaypalSandbox.php | 2 - src/Appwrite/Auth/OAuth2/Podio.php | 41 +- src/Appwrite/Auth/OAuth2/Salesforce.php | 42 +- src/Appwrite/Auth/OAuth2/Slack.php | 39 +- src/Appwrite/Auth/OAuth2/Spotify.php | 47 +- src/Appwrite/Auth/OAuth2/Stripe.php | 37 +- src/Appwrite/Auth/OAuth2/Tradeshift.php | 52 +- src/Appwrite/Auth/OAuth2/TradeshiftBox.php | 2 - src/Appwrite/Auth/OAuth2/Twitch.php | 53 +- src/Appwrite/Auth/OAuth2/WordPress.php | 31 +- src/Appwrite/Auth/OAuth2/Yahoo.php | 49 +- src/Appwrite/Auth/OAuth2/Yammer.php | 37 +- src/Appwrite/Auth/OAuth2/Yandex.php | 43 +- src/Appwrite/Auth/OAuth2/Zoom.php | 39 +- src/Appwrite/Auth/Validator/Password.php | 5 +- .../Auth/Validator/PasswordDictionary.php | 7 +- .../Auth/Validator/PasswordHistory.php | 6 +- src/Appwrite/Auth/Validator/PersonalData.php | 7 +- src/Appwrite/Auth/Validator/Phone.php | 5 +- src/Appwrite/Detector/Detector.php | 8 +- src/Appwrite/Docker/Compose.php | 4 +- src/Appwrite/Docker/Compose/Service.php | 5 +- src/Appwrite/Docker/Env.php | 14 +- src/Appwrite/Event/Audit.php | 12 +- src/Appwrite/Event/Build.php | 11 +- src/Appwrite/Event/Certificate.php | 8 +- src/Appwrite/Event/Database.php | 17 +- src/Appwrite/Event/Delete.php | 25 +- src/Appwrite/Event/Event.php | 78 +- src/Appwrite/Event/Func.php | 20 +- src/Appwrite/Event/Mail.php | 37 +- src/Appwrite/Event/Migration.php | 14 +- src/Appwrite/Event/Phone.php | 8 +- src/Appwrite/Event/Usage.php | 13 +- src/Appwrite/Event/Validator/Event.php | 24 +- src/Appwrite/Extend/Exception.php | 371 ++++-- src/Appwrite/GraphQL/Promises/Adapter.php | 21 +- src/Appwrite/GraphQL/Resolvers.php | 129 +- src/Appwrite/GraphQL/Schema.php | 68 +- src/Appwrite/GraphQL/Types.php | 3 + src/Appwrite/GraphQL/Types/Assoc.php | 8 +- src/Appwrite/GraphQL/Types/InputFile.php | 3 +- src/Appwrite/GraphQL/Types/Json.php | 4 +- src/Appwrite/GraphQL/Types/Mapper.php | 49 +- src/Appwrite/GraphQL/Types/Registry.php | 8 +- src/Appwrite/Messaging/Adapter.php | 2 + src/Appwrite/Messaging/Adapter/Realtime.php | 84 +- src/Appwrite/Migration/Migration.php | 80 +- src/Appwrite/Migration/Version/V15.php | 47 +- src/Appwrite/Migration/Version/V16.php | 14 +- src/Appwrite/Migration/Version/V17.php | 12 +- src/Appwrite/Migration/Version/V18.php | 6 +- src/Appwrite/Migration/Version/V19.php | 11 +- src/Appwrite/Network/Validator/CNAME.php | 9 +- src/Appwrite/Network/Validator/Email.php | 6 +- src/Appwrite/Network/Validator/Origin.php | 39 +- src/Appwrite/OpenSSL/OpenSSL.php | 26 +- src/Appwrite/Platform/Services/Tasks.php | 20 +- src/Appwrite/Platform/Tasks/CalcTierStats.php | 54 +- .../Platform/Tasks/CalcUsersStats.php | 27 +- .../Platform/Tasks/ClearCardCache.php | 14 +- src/Appwrite/Platform/Tasks/Doctor.php | 91 +- src/Appwrite/Platform/Tasks/Hamster.php | 99 +- src/Appwrite/Platform/Tasks/Install.php | 68 +- src/Appwrite/Platform/Tasks/Maintenance.php | 18 +- src/Appwrite/Platform/Tasks/Migrate.php | 21 +- .../Tasks/PatchCreateMissingSchedules.php | 16 +- .../Tasks/PatchDeleteProjectCollections.php | 22 +- .../PatchDeleteScheduleUpdatedAtAttribute.php | 8 +- src/Appwrite/Platform/Tasks/SDKs.php | 86 +- src/Appwrite/Platform/Tasks/SSL.php | 6 +- src/Appwrite/Platform/Tasks/Schedule.php | 37 +- src/Appwrite/Platform/Tasks/Specs.php | 50 +- src/Appwrite/Platform/Tasks/Vars.php | 4 +- src/Appwrite/Platform/Tasks/VolumeSync.php | 14 +- src/Appwrite/Promises/Promise.php | 35 +- src/Appwrite/Promises/Swoole.php | 4 +- src/Appwrite/Resque/Worker.php | 84 +- src/Appwrite/Specification/Format.php | 31 +- .../Specification/Format/OpenAPI3.php | 92 +- .../Specification/Format/Swagger2.php | 82 +- src/Appwrite/Task/Validator/Cron.php | 5 +- src/Appwrite/Template/Template.php | 37 +- src/Appwrite/URL/URL.php | 34 +- .../Utopia/Database/Validator/CustomId.php | 2 - .../Utopia/Database/Validator/ProjectId.php | 1 - .../Database/Validator/Queries/Attributes.php | 5 +- .../Database/Validator/Queries/Base.php | 20 +- .../Database/Validator/Queries/Buckets.php | 3 +- .../Validator/Queries/Collections.php | 3 +- .../Database/Validator/Queries/Databases.php | 3 +- .../Validator/Queries/Deployments.php | 1 - .../Database/Validator/Queries/Executions.php | 3 +- .../Database/Validator/Queries/Files.php | 3 +- .../Database/Validator/Queries/Functions.php | 3 +- .../Database/Validator/Queries/Identities.php | 1 - .../Database/Validator/Queries/Indexes.php | 1 - .../Validator/Queries/Memberships.php | 3 +- .../Database/Validator/Queries/Migrations.php | 3 +- .../Database/Validator/Queries/Projects.php | 5 +- .../Database/Validator/Queries/Providers.php | 1 - .../Database/Validator/Queries/Teams.php | 3 +- .../Database/Validator/Queries/Users.php | 3 +- .../Database/Validator/Queries/Variables.php | 5 +- src/Appwrite/Utopia/Request.php | 11 +- src/Appwrite/Utopia/Request/Filter.php | 5 +- src/Appwrite/Utopia/Request/Filters/V12.php | 45 +- src/Appwrite/Utopia/Request/Filters/V13.php | 16 +- src/Appwrite/Utopia/Request/Filters/V14.php | 12 +- src/Appwrite/Utopia/Request/Filters/V15.php | 25 +- src/Appwrite/Utopia/Response.php | 258 ++-- src/Appwrite/Utopia/Response/Filter.php | 5 +- src/Appwrite/Utopia/Response/Filters/V11.php | 35 +- src/Appwrite/Utopia/Response/Filters/V12.php | 12 + src/Appwrite/Utopia/Response/Filters/V13.php | 3 + src/Appwrite/Utopia/Response/Filters/V15.php | 18 +- src/Appwrite/Utopia/Response/Model.php | 16 +- .../Utopia/Response/Model/AlgoArgon2.php | 3 +- .../Utopia/Response/Model/AlgoScrypt.php | 3 +- .../Response/Model/AlgoScryptModified.php | 3 +- .../Utopia/Response/Model/Attribute.php | 3 +- .../Response/Model/AttributeBoolean.php | 7 +- .../Response/Model/AttributeDatetime.php | 5 +- .../Utopia/Response/Model/AttributeEmail.php | 5 +- .../Utopia/Response/Model/AttributeEnum.php | 5 +- .../Utopia/Response/Model/AttributeFloat.php | 3 +- .../Utopia/Response/Model/AttributeIP.php | 5 +- .../Response/Model/AttributeInteger.php | 4 +- .../Utopia/Response/Model/AttributeList.php | 7 +- .../Response/Model/AttributeRelationship.php | 6 +- .../Utopia/Response/Model/AttributeString.php | 3 +- .../Utopia/Response/Model/AttributeURL.php | 5 +- .../Utopia/Response/Model/AuthProvider.php | 3 +- .../Utopia/Response/Model/BaseList.php | 20 +- src/Appwrite/Utopia/Response/Model/Bucket.php | 9 +- src/Appwrite/Utopia/Response/Model/Build.php | 3 +- .../Utopia/Response/Model/Collection.php | 7 +- .../Utopia/Response/Model/Continent.php | 3 +- .../Utopia/Response/Model/Country.php | 3 +- .../Utopia/Response/Model/Currency.php | 3 +- .../Utopia/Response/Model/Database.php | 3 +- .../Utopia/Response/Model/Deployment.php | 3 +- src/Appwrite/Utopia/Response/Model/Domain.php | 3 +- src/Appwrite/Utopia/Response/Model/Error.php | 3 +- .../Utopia/Response/Model/ErrorDev.php | 3 +- .../Utopia/Response/Model/Execution.php | 3 +- src/Appwrite/Utopia/Response/Model/File.php | 3 +- src/Appwrite/Utopia/Response/Model/Func.php | 7 +- .../Utopia/Response/Model/HealthAntivirus.php | 3 +- .../Utopia/Response/Model/HealthQueue.php | 3 +- .../Utopia/Response/Model/HealthStatus.php | 3 +- .../Utopia/Response/Model/HealthTime.php | 3 +- .../Utopia/Response/Model/HealthVersion.php | 3 +- .../Utopia/Response/Model/Identity.php | 3 +- src/Appwrite/Utopia/Response/Model/Index.php | 3 +- src/Appwrite/Utopia/Response/Model/JWT.php | 3 +- src/Appwrite/Utopia/Response/Model/Key.php | 9 +- .../Utopia/Response/Model/Language.php | 3 +- src/Appwrite/Utopia/Response/Model/Locale.php | 3 +- .../Utopia/Response/Model/LocaleCode.php | 3 +- src/Appwrite/Utopia/Response/Model/Log.php | 3 +- .../Utopia/Response/Model/Membership.php | 3 +- src/Appwrite/Utopia/Response/Model/Metric.php | 2 +- .../Utopia/Response/Model/Migration.php | 5 +- src/Appwrite/Utopia/Response/Model/Mock.php | 3 +- src/Appwrite/Utopia/Response/Model/Phone.php | 3 +- .../Utopia/Response/Model/Platform.php | 3 +- .../Utopia/Response/Model/Project.php | 37 +- .../Utopia/Response/Model/Runtime.php | 5 +- .../Utopia/Response/Model/Session.php | 3 +- src/Appwrite/Utopia/Response/Model/Team.php | 4 +- .../Utopia/Response/Model/Template.php | 3 +- .../Utopia/Response/Model/TemplateEmail.php | 3 +- .../Utopia/Response/Model/TemplateSMS.php | 1 + src/Appwrite/Utopia/Response/Model/Token.php | 3 +- .../Utopia/Response/Model/UsageBuckets.php | 7 +- .../Utopia/Response/Model/UsageCollection.php | 5 +- .../Utopia/Response/Model/UsageDatabase.php | 7 +- .../Utopia/Response/Model/UsageDatabases.php | 9 +- .../Utopia/Response/Model/UsageFunction.php | 17 +- .../Utopia/Response/Model/UsageFunctions.php | 19 +- .../Utopia/Response/Model/UsageProject.php | 19 +- .../Utopia/Response/Model/UsageStorage.php | 9 +- .../Utopia/Response/Model/UsageUsers.php | 7 +- src/Appwrite/Utopia/Response/Model/User.php | 6 +- .../Utopia/Response/Model/Variable.php | 3 +- .../Utopia/Response/Model/Webhook.php | 3 +- src/Appwrite/Utopia/View.php | 3 +- src/Executor/Executor.php | 104 +- tests/e2e/Client.php | 66 +- tests/e2e/General/AbuseTest.php | 42 +- tests/e2e/General/HTTPTest.php | 8 +- tests/e2e/General/UsageTest.php | 111 +- tests/e2e/Scopes/ProjectCustom.php | 23 +- tests/e2e/Scopes/Scope.php | 11 +- tests/e2e/Scopes/SideClient.php | 2 +- tests/e2e/Scopes/SideConsole.php | 4 +- tests/e2e/Scopes/SideServer.php | 2 +- tests/e2e/Services/Account/AccountBase.php | 197 ++- .../Account/AccountConsoleClientTest.php | 14 +- .../Account/AccountCustomClientTest.php | 141 +-- .../Account/AccountCustomServerTest.php | 2 +- tests/e2e/Services/Avatars/AvatarsBase.php | 17 +- .../Avatars/AvatarsConsoleClientTest.php | 2 +- .../Avatars/AvatarsCustomClientTest.php | 2 +- .../e2e/Services/Databases/DatabasesBase.php | 900 +++++++------- .../Databases/DatabasesConsoleClientTest.php | 84 +- .../Databases/DatabasesCustomClientTest.php | 269 ++-- .../Databases/DatabasesCustomServerTest.php | 1088 ++++++++-------- .../DatabasesPermissionsGuestTest.php | 48 +- .../DatabasesPermissionsMemberTest.php | 40 +- .../Databases/DatabasesPermissionsScope.php | 15 +- .../DatabasesPermissionsTeamTest.php | 27 +- .../e2e/Services/Functions/FunctionsBase.php | 3 +- .../Functions/FunctionsConsoleClientTest.php | 125 +- .../Functions/FunctionsCustomClientTest.php | 105 +- .../Functions/FunctionsCustomServerTest.php | 231 ++-- tests/e2e/Services/GraphQL/AbuseTest.php | 8 +- tests/e2e/Services/GraphQL/AccountTest.php | 36 +- tests/e2e/Services/GraphQL/AuthTest.php | 49 +- tests/e2e/Services/GraphQL/Base.php | 155 ++- tests/e2e/Services/GraphQL/BatchTest.php | 39 +- .../e2e/Services/GraphQL/ContentTypeTest.php | 8 +- .../Services/GraphQL/DatabaseClientTest.php | 22 +- .../Services/GraphQL/DatabaseServerTest.php | 137 +- .../Services/GraphQL/FunctionsClientTest.php | 26 +- .../Services/GraphQL/FunctionsServerTest.php | 54 +- .../e2e/Services/GraphQL/LocalizationTest.php | 2 +- tests/e2e/Services/GraphQL/ScopeTest.php | 5 +- .../Services/GraphQL/StorageClientTest.php | 36 +- .../Services/GraphQL/StorageServerTest.php | 49 +- .../e2e/Services/GraphQL/TeamsServerTest.php | 8 +- tests/e2e/Services/GraphQL/UsersTest.php | 39 +- tests/e2e/Services/Health/HealthBase.php | 2 - .../Health/HealthCustomServerTest.php | 3 +- tests/e2e/Services/Locale/LocaleBase.php | 16 +- .../Locale/LocaleConsoleClientTest.php | 2 +- .../Locale/LocaleCustomClientTest.php | 2 +- .../Locale/LocaleCustomServerTest.php | 1 - .../Messaging/MessagingServerTest.php | 9 +- tests/e2e/Services/Projects/ProjectsBase.php | 2 - .../Projects/ProjectsConsoleClientTest.php | 487 ++++---- .../Projects/ProjectsCustomClientTest.php | 3 +- .../Projects/ProjectsCustomServerTest.php | 1 - tests/e2e/Services/Realtime/RealtimeBase.php | 12 +- .../Realtime/RealtimeConsoleClientTest.php | 53 +- .../Realtime/RealtimeCustomClientTest.php | 331 +++-- tests/e2e/Services/Storage/StorageBase.php | 161 ++- .../Storage/StorageConsoleClientTest.php | 29 +- .../Storage/StorageCustomClientTest.php | 419 ++++--- .../Storage/StorageCustomServerTest.php | 46 +- .../Storage/StoragePermissionsScope.php | 16 +- tests/e2e/Services/Teams/TeamsBase.php | 47 +- tests/e2e/Services/Teams/TeamsBaseClient.php | 155 ++- tests/e2e/Services/Teams/TeamsBaseServer.php | 52 +- .../Services/Teams/TeamsConsoleClientTest.php | 34 +- .../Services/Teams/TeamsCustomClientTest.php | 2 +- .../Services/Teams/TeamsCustomServerTest.php | 1 - tests/e2e/Services/Users/UsersBase.php | 134 +- .../Services/Users/UsersConsoleClientTest.php | 9 +- .../Services/Users/UsersCustomServerTest.php | 1 - tests/e2e/Services/Webhooks/WebhooksBase.php | 136 +- .../Webhooks/WebhooksCustomClientTest.php | 102 +- .../Webhooks/WebhooksCustomServerTest.php | 77 +- tests/extensions/Retryable.php | 13 +- tests/extensions/TestHook.php | 2 +- tests/resources/functions/php-fn/index.php | 2 +- tests/resources/functions/php-large/index.php | 2 +- tests/resources/functions/php/index.php | 2 +- tests/unit/Auth/AuthTest.php | 62 +- .../Auth/Validator/PasswordDictionaryTest.php | 1 - tests/unit/Docker/ComposeTest.php | 2 +- tests/unit/Docker/EnvTest.php | 6 +- tests/unit/Event/EventTest.php | 12 +- tests/unit/General/CollectionsTest.php | 2 +- .../unit/Messaging/MessagingChannelsTest.php | 53 +- tests/unit/Messaging/MessagingGuestTest.php | 4 +- tests/unit/Messaging/MessagingTest.php | 28 +- tests/unit/Migration/MigrationTest.php | 50 +- tests/unit/Network/Validators/EmailTest.php | 5 +- tests/unit/Template/TemplateTest.php | 5 +- tests/unit/Usage/StatsTest.php | 23 +- tests/unit/Utopia/Lists.php | 2 +- tests/unit/Utopia/Nested.php | 2 +- tests/unit/Utopia/Request/Filters/V15Test.php | 26 +- .../unit/Utopia/Response/Filters/V15Test.php | 54 +- tests/unit/Utopia/ResponseTest.php | 13 +- tests/unit/Utopia/Single.php | 4 +- 382 files changed, 10227 insertions(+), 10339 deletions(-) diff --git a/app/cli.php b/app/cli.php index d1dd885775..2614e00e11 100644 --- a/app/cli.php +++ b/app/cli.php @@ -1,27 +1,27 @@ $register); +CLI::setResource('register', fn () => $register); CLI::setResource('cache', function ($pools) { $list = Config::getParam('pools-cache', []); @@ -31,8 +31,7 @@ CLI::setResource('cache', function ($pools) { $adapters[] = $pools ->get($value) ->pop() - ->getResource() - ; + ->getResource(); } return new Cache(new Sharding($adapters)); @@ -64,7 +63,7 @@ CLI::setResource('dbForConsole', function ($pools, $cache) { $collections = Config::getParam('collections', [])['console']; $last = \array_key_last($collections); - if (!($dbForConsole->exists($dbForConsole->getDefaultDatabase(), $last))) { /** TODO cache ready variable using registry */ + if (! ($dbForConsole->exists($dbForConsole->getDefaultDatabase(), $last))) { /** TODO cache ready variable using registry */ throw new Exception('Tables not ready yet.'); } @@ -76,8 +75,8 @@ CLI::setResource('dbForConsole', function ($pools, $cache) { } } while ($attempts < $maxAttempts); - if (!$ready) { - throw new Exception("Console is not ready yet. Please try again later."); + if (! $ready) { + throw new Exception('Console is not ready yet. Please try again later.'); } return $dbForConsole; @@ -95,7 +94,8 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, if (isset($databases[$databaseName])) { $database = $databases[$databaseName]; - $database->setNamespace('_' . $project->getInternalId()); + $database->setNamespace('_'.$project->getInternalId()); + return $database; } @@ -108,7 +108,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, $databases[$databaseName] = $database; - $database->setNamespace('_' . $project->getInternalId()); + $database->setNamespace('_'.$project->getInternalId()); return $database; }; @@ -116,7 +116,6 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, return $getProjectDB; }, ['pools', 'dbForConsole', 'cache']); - CLI::setResource('queueForFunctions', function (Group $pools) { return new Func($pools->get('queue')->pop()->getResource()); }, ['pools']); @@ -149,7 +148,7 @@ CLI::setResource('logError', function (Registry $register) { $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); $responseCode = $logger->addLog($log); - Console::info('Usage stats log pushed with status code: ' . $responseCode); + Console::info('Usage stats log pushed with status code: '.$responseCode); } Console::warning("Failed: {$error->getMessage()}"); diff --git a/app/config/authProviders.php b/app/config/authProviders.php index dedb4ec665..cf9ad052c3 100644 --- a/app/config/authProviders.php +++ b/app/config/authProviders.php @@ -69,7 +69,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false + 'mock' => false, ], 'box' => [ 'name' => 'Box', @@ -79,7 +79,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false + 'mock' => false, ], 'dailymotion' => [ 'name' => 'Dailymotion', @@ -89,7 +89,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false + 'mock' => false, ], 'discord' => [ 'name' => 'Discord', @@ -229,7 +229,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false + 'mock' => false, ], 'paypalSandbox' => [ 'name' => 'PayPal Sandbox', @@ -239,7 +239,7 @@ return [ // Ordered by ABC. 'sandbox' => true, 'form' => false, 'beta' => false, - 'mock' => false + 'mock' => false, ], 'podio' => [ 'name' => 'Podio', @@ -289,7 +289,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false + 'mock' => false, ], 'tradeshift' => [ 'name' => 'Tradeshift', @@ -329,7 +329,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false + 'mock' => false, ], 'yahoo' => [ 'name' => 'Yahoo', diff --git a/app/config/avatars/browsers.php b/app/config/avatars/browsers.php index e7d31c7443..7d80937bd3 100644 --- a/app/config/avatars/browsers.php +++ b/app/config/avatars/browsers.php @@ -2,21 +2,20 @@ return [ // Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php - 'aa' => ['name' => 'Avant Browser', 'path' => __DIR__ . '/browsers/avant.png'], - 'an' => ['name' => 'Android WebView Beta', 'path' => __DIR__ . '/browsers/android-webview-beta.png'], - 'ch' => ['name' => 'Google Chrome', 'path' => __DIR__ . '/browsers/chrome.png'], - 'ci' => ['name' => 'Google Chrome (iOS)', 'path' => __DIR__ . '/browsers/chrome.png'], - 'cm' => ['name' => 'Google Chrome (Mobile)', 'path' => __DIR__ . '/browsers/chrome.png'], - 'cr' => ['name' => 'Chromium', 'path' => __DIR__ . '/browsers/chromium.png'], - 'ff' => ['name' => 'Mozilla Firefox', 'path' => __DIR__ . '/browsers/firefox.png'], - 'sf' => ['name' => 'Safari', 'path' => __DIR__ . '/browsers/safari.png'], - 'mf' => ['name' => 'Mobile Safari', 'path' => __DIR__ . '/browsers/safari.png'], - 'ps' => ['name' => 'Microsoft Edge', 'path' => __DIR__ . '/browsers/edge.png'], - 'oi' => ['name' => 'Microsoft Edge (iOS)', 'path' => __DIR__ . '/browsers/edge.png'], - 'om' => ['name' => 'Opera Mini', 'path' => __DIR__ . '/browsers/opera-mini.png'], - 'op' => ['name' => 'Opera', 'path' => __DIR__ . '/browsers/opera.png'], - 'on' => ['name' => 'Opera (Next)', 'path' => __DIR__ . '/browsers/opera.png'], - + 'aa' => ['name' => 'Avant Browser', 'path' => __DIR__.'/browsers/avant.png'], + 'an' => ['name' => 'Android WebView Beta', 'path' => __DIR__.'/browsers/android-webview-beta.png'], + 'ch' => ['name' => 'Google Chrome', 'path' => __DIR__.'/browsers/chrome.png'], + 'ci' => ['name' => 'Google Chrome (iOS)', 'path' => __DIR__.'/browsers/chrome.png'], + 'cm' => ['name' => 'Google Chrome (Mobile)', 'path' => __DIR__.'/browsers/chrome.png'], + 'cr' => ['name' => 'Chromium', 'path' => __DIR__.'/browsers/chromium.png'], + 'ff' => ['name' => 'Mozilla Firefox', 'path' => __DIR__.'/browsers/firefox.png'], + 'sf' => ['name' => 'Safari', 'path' => __DIR__.'/browsers/safari.png'], + 'mf' => ['name' => 'Mobile Safari', 'path' => __DIR__.'/browsers/safari.png'], + 'ps' => ['name' => 'Microsoft Edge', 'path' => __DIR__.'/browsers/edge.png'], + 'oi' => ['name' => 'Microsoft Edge (iOS)', 'path' => __DIR__.'/browsers/edge.png'], + 'om' => ['name' => 'Opera Mini', 'path' => __DIR__.'/browsers/opera-mini.png'], + 'op' => ['name' => 'Opera', 'path' => __DIR__.'/browsers/opera.png'], + 'on' => ['name' => 'Opera (Next)', 'path' => __DIR__.'/browsers/opera.png'], /* '36' => '360 Phone Browser', diff --git a/app/config/avatars/credit-cards.php b/app/config/avatars/credit-cards.php index aaef17ee3f..0655c6fcda 100644 --- a/app/config/avatars/credit-cards.php +++ b/app/config/avatars/credit-cards.php @@ -1,20 +1,20 @@ ['name' => 'American Express', 'path' => __DIR__ . '/credit-cards/amex.png'], - 'argencard' => ['name' => 'Argencard', 'path' => __DIR__ . '/credit-cards/argencard.png'], - 'cabal' => ['name' => 'Cabal', 'path' => __DIR__ . '/credit-cards/cabal.png'], - 'censosud' => ['name' => 'Consosud', 'path' => __DIR__ . '/credit-cards/consosud.png'], - 'diners' => ['name' => 'Diners Club', 'path' => __DIR__ . '/credit-cards/diners.png'], - 'discover' => ['name' => 'Discover', 'path' => __DIR__ . '/credit-cards/discover.png'], - 'elo' => ['name' => 'Elo', 'path' => __DIR__ . '/credit-cards/elo.png'], - 'hipercard' => ['name' => 'Hipercard', 'path' => __DIR__ . '/credit-cards/hipercard.png'], - 'jcb' => ['name' => 'JCB', 'path' => __DIR__ . '/credit-cards/jcb.png'], - 'mastercard' => ['name' => 'Mastercard', 'path' => __DIR__ . '/credit-cards/mastercard.png'], - 'naranja' => ['name' => 'Naranja', 'path' => __DIR__ . '/credit-cards/naranja.png'], - 'targeta-shopping' => ['name' => 'Tarjeta Shopping', 'path' => __DIR__ . '/credit-cards/tarjeta-shopping.png'], - 'union-china-pay' => ['name' => 'Union China Pay', 'path' => __DIR__ . '/credit-cards/union-china-pay.png'], - 'visa' => ['name' => 'Visa', 'path' => __DIR__ . '/credit-cards/visa.png'], - 'mir' => ['name' => 'MIR', 'path' => __DIR__ . '/credit-cards/mir.png'], - 'maestro' => ['name' => 'Maestro', 'path' => __DIR__ . '/credit-cards/maestro.png'] - ]; + 'amex' => ['name' => 'American Express', 'path' => __DIR__.'/credit-cards/amex.png'], + 'argencard' => ['name' => 'Argencard', 'path' => __DIR__.'/credit-cards/argencard.png'], + 'cabal' => ['name' => 'Cabal', 'path' => __DIR__.'/credit-cards/cabal.png'], + 'censosud' => ['name' => 'Consosud', 'path' => __DIR__.'/credit-cards/consosud.png'], + 'diners' => ['name' => 'Diners Club', 'path' => __DIR__.'/credit-cards/diners.png'], + 'discover' => ['name' => 'Discover', 'path' => __DIR__.'/credit-cards/discover.png'], + 'elo' => ['name' => 'Elo', 'path' => __DIR__.'/credit-cards/elo.png'], + 'hipercard' => ['name' => 'Hipercard', 'path' => __DIR__.'/credit-cards/hipercard.png'], + 'jcb' => ['name' => 'JCB', 'path' => __DIR__.'/credit-cards/jcb.png'], + 'mastercard' => ['name' => 'Mastercard', 'path' => __DIR__.'/credit-cards/mastercard.png'], + 'naranja' => ['name' => 'Naranja', 'path' => __DIR__.'/credit-cards/naranja.png'], + 'targeta-shopping' => ['name' => 'Tarjeta Shopping', 'path' => __DIR__.'/credit-cards/tarjeta-shopping.png'], + 'union-china-pay' => ['name' => 'Union China Pay', 'path' => __DIR__.'/credit-cards/union-china-pay.png'], + 'visa' => ['name' => 'Visa', 'path' => __DIR__.'/credit-cards/visa.png'], + 'mir' => ['name' => 'MIR', 'path' => __DIR__.'/credit-cards/mir.png'], + 'maestro' => ['name' => 'Maestro', 'path' => __DIR__.'/credit-cards/maestro.png'], +]; diff --git a/app/config/avatars/flags.php b/app/config/avatars/flags.php index 696656738e..144a8bfd31 100644 --- a/app/config/avatars/flags.php +++ b/app/config/avatars/flags.php @@ -1,198 +1,198 @@ ['name' => 'Afghanistan', 'path' => __DIR__ . '/flags/af.png'], - 'ao' => ['name' => 'Angola', 'path' => __DIR__ . '/flags/ao.png'], - 'al' => ['name' => 'Albania', 'path' => __DIR__ . '/flags/al.png'], - 'ad' => ['name' => 'Andorra', 'path' => __DIR__ . '/flags/ad.png'], - 'ae' => ['name' => 'United Arab Emirates', 'path' => __DIR__ . '/flags/ae.png'], - 'ar' => ['name' => 'Argentina', 'path' => __DIR__ . '/flags/ar.png'], - 'am' => ['name' => 'Armenia', 'path' => __DIR__ . '/flags/am.png'], - 'ag' => ['name' => 'Antigua and Barbuda', 'path' => __DIR__ . '/flags/ag.png'], - 'au' => ['name' => 'Australia', 'path' => __DIR__ . '/flags/au.png'], - 'at' => ['name' => 'Austria', 'path' => __DIR__ . '/flags/at.png'], - 'az' => ['name' => 'Azerbaijan', 'path' => __DIR__ . '/flags/az.png'], - 'bi' => ['name' => 'Burundi', 'path' => __DIR__ . '/flags/bi.png'], - 'be' => ['name' => 'Belgium', 'path' => __DIR__ . '/flags/be.png'], - 'bj' => ['name' => 'Benin', 'path' => __DIR__ . '/flags/bj.png'], - 'bf' => ['name' => 'Burkina Faso', 'path' => __DIR__ . '/flags/bf.png'], - 'bd' => ['name' => 'Bangladesh', 'path' => __DIR__ . '/flags/bd.png'], - 'bg' => ['name' => 'Bulgaria', 'path' => __DIR__ . '/flags/bg.png'], - 'bh' => ['name' => 'Bahrain', 'path' => __DIR__ . '/flags/bh.png'], - 'bs' => ['name' => 'Bahamas', 'path' => __DIR__ . '/flags/bs.png'], - 'ba' => ['name' => 'Bosnia and Herzegovina', 'path' => __DIR__ . '/flags/ba.png'], - 'by' => ['name' => 'Belarus', 'path' => __DIR__ . '/flags/by.png'], - 'bz' => ['name' => 'Belize', 'path' => __DIR__ . '/flags/bz.png'], - 'bo' => ['name' => 'Bolivia', 'path' => __DIR__ . '/flags/bo.png'], - 'br' => ['name' => 'Brazil', 'path' => __DIR__ . '/flags/br.png'], - 'bb' => ['name' => 'Barbados', 'path' => __DIR__ . '/flags/bb.png'], - 'bn' => ['name' => 'Brunei Darussalam', 'path' => __DIR__ . '/flags/bn.png'], - 'bt' => ['name' => 'Bhutan', 'path' => __DIR__ . '/flags/bt.png'], - 'bw' => ['name' => 'Botswana', 'path' => __DIR__ . '/flags/bw.png'], - 'cf' => ['name' => 'Central African Republic', 'path' => __DIR__ . '/flags/cf.png'], - 'ca' => ['name' => 'Canada', 'path' => __DIR__ . '/flags/ca.png'], - 'ch' => ['name' => 'Switzerland', 'path' => __DIR__ . '/flags/ch.png'], - 'cl' => ['name' => 'Chile', 'path' => __DIR__ . '/flags/cl.png'], - 'cn' => ['name' => 'China', 'path' => __DIR__ . '/flags/cn.png'], - 'ci' => ['name' => 'Côte d\'Ivoire', 'path' => __DIR__ . '/flags/ci.png'], - 'cm' => ['name' => 'Cameroon', 'path' => __DIR__ . '/flags/cm.png'], - 'cd' => ['name' => 'Democratic Republic of the Congo', 'path' => __DIR__ . '/flags/cd.png'], - 'cg' => ['name' => 'Republic of the Congo', 'path' => __DIR__ . '/flags/cg.png'], - 'co' => ['name' => 'Colombia', 'path' => __DIR__ . '/flags/co.png'], - 'km' => ['name' => 'Comoros', 'path' => __DIR__ . '/flags/km.png'], - 'cv' => ['name' => 'Cape Verde', 'path' => __DIR__ . '/flags/cv.png'], - 'cr' => ['name' => 'Costa Rica', 'path' => __DIR__ . '/flags/cr.png'], - 'cu' => ['name' => 'Cuba', 'path' => __DIR__ . '/flags/cu.png'], - 'cy' => ['name' => 'Cyprus', 'path' => __DIR__ . '/flags/cy.png'], - 'cz' => ['name' => 'Czech Republic', 'path' => __DIR__ . '/flags/cz.png'], - 'de' => ['name' => 'Germany', 'path' => __DIR__ . '/flags/de.png'], - 'dj' => ['name' => 'Djibouti', 'path' => __DIR__ . '/flags/dj.png'], - 'dm' => ['name' => 'Dominica', 'path' => __DIR__ . '/flags/dm.png'], - 'dk' => ['name' => 'Denmark', 'path' => __DIR__ . '/flags/dk.png'], - 'do' => ['name' => 'Dominican Republic', 'path' => __DIR__ . '/flags/do.png'], - 'dz' => ['name' => 'Algeria', 'path' => __DIR__ . '/flags/dz.png'], - 'ec' => ['name' => 'Ecuador', 'path' => __DIR__ . '/flags/ec.png'], - 'eg' => ['name' => 'Egypt', 'path' => __DIR__ . '/flags/eg.png'], - 'er' => ['name' => 'Eritrea', 'path' => __DIR__ . '/flags/er.png'], - 'es' => ['name' => 'Spain', 'path' => __DIR__ . '/flags/es.png'], - 'ee' => ['name' => 'Estonia', 'path' => __DIR__ . '/flags/ee.png'], - 'et' => ['name' => 'Ethiopia', 'path' => __DIR__ . '/flags/et.png'], - 'fi' => ['name' => 'Finland', 'path' => __DIR__ . '/flags/fi.png'], - 'fj' => ['name' => 'Fiji', 'path' => __DIR__ . '/flags/fj.png'], - 'fr' => ['name' => 'France', 'path' => __DIR__ . '/flags/fr.png'], - 'fm' => ['name' => 'Micronesia (Federated States of)', 'path' => __DIR__ . '/flags/fm.png'], - 'ga' => ['name' => 'Gabon', 'path' => __DIR__ . '/flags/ga.png'], - 'gb' => ['name' => 'United Kingdom', 'path' => __DIR__ . '/flags/gb.png'], - 'ge' => ['name' => 'Georgia', 'path' => __DIR__ . '/flags/ge.png'], - 'gh' => ['name' => 'Ghana', 'path' => __DIR__ . '/flags/gh.png'], - 'gn' => ['name' => 'Guinea', 'path' => __DIR__ . '/flags/gn.png'], - 'gm' => ['name' => 'Gambia', 'path' => __DIR__ . '/flags/gm.png'], - 'gw' => ['name' => 'Guinea-Bissau', 'path' => __DIR__ . '/flags/gw.png'], - 'gq' => ['name' => 'Equatorial Guinea', 'path' => __DIR__ . '/flags/gq.png'], - 'gr' => ['name' => 'Greece', 'path' => __DIR__ . '/flags/gr.png'], - 'gd' => ['name' => 'Grenada', 'path' => __DIR__ . '/flags/gd.png'], - 'gt' => ['name' => 'Guatemala', 'path' => __DIR__ . '/flags/gt.png'], - 'gy' => ['name' => 'Guyana', 'path' => __DIR__ . '/flags/gy.png'], - 'hn' => ['name' => 'Honduras', 'path' => __DIR__ . '/flags/hn.png'], - 'hr' => ['name' => 'Croatia', 'path' => __DIR__ . '/flags/hr.png'], - 'ht' => ['name' => 'Haiti', 'path' => __DIR__ . '/flags/ht.png'], - 'hu' => ['name' => 'Hungary', 'path' => __DIR__ . '/flags/hu.png'], - 'id' => ['name' => 'Indonesia', 'path' => __DIR__ . '/flags/id.png'], - 'in' => ['name' => 'India', 'path' => __DIR__ . '/flags/in.png'], - 'ie' => ['name' => 'Ireland', 'path' => __DIR__ . '/flags/ie.png'], - 'ir' => ['name' => 'Iran (Islamic Republic of)', 'path' => __DIR__ . '/flags/ir.png'], - 'iq' => ['name' => 'Iraq', 'path' => __DIR__ . '/flags/iq.png'], - 'is' => ['name' => 'Iceland', 'path' => __DIR__ . '/flags/is.png'], - 'il' => ['name' => 'Israel', 'path' => __DIR__ . '/flags/il.png'], - 'it' => ['name' => 'Italy', 'path' => __DIR__ . '/flags/it.png'], - 'jm' => ['name' => 'Jamaica', 'path' => __DIR__ . '/flags/jm.png'], - 'jo' => ['name' => 'Jordan', 'path' => __DIR__ . '/flags/jo.png'], - 'jp' => ['name' => 'Japan', 'path' => __DIR__ . '/flags/jp.png'], - 'kz' => ['name' => 'Kazakhstan', 'path' => __DIR__ . '/flags/kz.png'], - 'ke' => ['name' => 'Kenya', 'path' => __DIR__ . '/flags/ke.png'], - 'kg' => ['name' => 'Kyrgyzstan', 'path' => __DIR__ . '/flags/kg.png'], - 'kh' => ['name' => 'Cambodia', 'path' => __DIR__ . '/flags/kh.png'], - 'ki' => ['name' => 'Kiribati', 'path' => __DIR__ . '/flags/ki.png'], - 'kn' => ['name' => 'Saint Kitts and Nevis', 'path' => __DIR__ . '/flags/kn.png'], - 'kr' => ['name' => 'South Korea', 'path' => __DIR__ . '/flags/kr.png'], - 'kw' => ['name' => 'Kuwait', 'path' => __DIR__ . '/flags/kw.png'], - 'la' => ['name' => 'Lao People\'s Democratic Republic', 'path' => __DIR__ . '/flags/la.png'], - 'lb' => ['name' => 'Lebanon', 'path' => __DIR__ . '/flags/lb.png'], - 'lr' => ['name' => 'Liberia', 'path' => __DIR__ . '/flags/lr.png'], - 'ly' => ['name' => 'Libya', 'path' => __DIR__ . '/flags/ly.png'], - 'lc' => ['name' => 'Saint Lucia', 'path' => __DIR__ . '/flags/lc.png'], - 'li' => ['name' => 'Liechtenstein', 'path' => __DIR__ . '/flags/li.png'], - 'lk' => ['name' => 'Sri Lanka', 'path' => __DIR__ . '/flags/lk.png'], - 'ls' => ['name' => 'Lesotho', 'path' => __DIR__ . '/flags/ls.png'], - 'lt' => ['name' => 'Lithuania', 'path' => __DIR__ . '/flags/lt.png'], - 'lu' => ['name' => 'Luxembourg', 'path' => __DIR__ . '/flags/lu.png'], - 'lv' => ['name' => 'Latvia', 'path' => __DIR__ . '/flags/lv.png'], - 'ma' => ['name' => 'Morocco', 'path' => __DIR__ . '/flags/ma.png'], - 'mc' => ['name' => 'Monaco', 'path' => __DIR__ . '/flags/mc.png'], - 'md' => ['name' => 'Moldova', 'path' => __DIR__ . '/flags/md.png'], - 'mg' => ['name' => 'Madagascar', 'path' => __DIR__ . '/flags/mg.png'], - 'mv' => ['name' => 'Maldives', 'path' => __DIR__ . '/flags/mv.png'], - 'mx' => ['name' => 'Mexico', 'path' => __DIR__ . '/flags/mx.png'], - 'mh' => ['name' => 'Marshall Islands', 'path' => __DIR__ . '/flags/mh.png'], - 'mk' => ['name' => 'North Macedonia', 'path' => __DIR__ . '/flags/mk.png'], - 'ml' => ['name' => 'Mali', 'path' => __DIR__ . '/flags/ml.png'], - 'mt' => ['name' => 'Malta', 'path' => __DIR__ . '/flags/mt.png'], - 'mm' => ['name' => 'Myanmar', 'path' => __DIR__ . '/flags/mm.png'], - 'me' => ['name' => 'Montenegro', 'path' => __DIR__ . '/flags/me.png'], - 'mn' => ['name' => 'Mongolia', 'path' => __DIR__ . '/flags/mn.png'], - 'mz' => ['name' => 'Mozambique', 'path' => __DIR__ . '/flags/mz.png'], - 'mr' => ['name' => 'Mauritania', 'path' => __DIR__ . '/flags/mr.png'], - 'mu' => ['name' => 'Mauritius', 'path' => __DIR__ . '/flags/mu.png'], - 'mw' => ['name' => 'Malawi', 'path' => __DIR__ . '/flags/mw.png'], - 'my' => ['name' => 'Malaysia', 'path' => __DIR__ . '/flags/my.png'], - 'na' => ['name' => 'Namibia', 'path' => __DIR__ . '/flags/na.png'], - 'ne' => ['name' => 'Niger', 'path' => __DIR__ . '/flags/ne.png'], - 'ng' => ['name' => 'Nigeria', 'path' => __DIR__ . '/flags/ng.png'], - 'ni' => ['name' => 'Nicaragua', 'path' => __DIR__ . '/flags/ni.png'], - 'nl' => ['name' => 'Netherlands', 'path' => __DIR__ . '/flags/nl.png'], - 'no' => ['name' => 'Norway', 'path' => __DIR__ . '/flags/no.png'], - 'np' => ['name' => 'Nepal', 'path' => __DIR__ . '/flags/np.png'], - 'nr' => ['name' => 'Nauru', 'path' => __DIR__ . '/flags/nr.png'], - 'nz' => ['name' => 'New Zealand', 'path' => __DIR__ . '/flags/nz.png'], - 'om' => ['name' => 'Oman', 'path' => __DIR__ . '/flags/om.png'], - 'pk' => ['name' => 'Pakistan', 'path' => __DIR__ . '/flags/pk.png'], - 'pa' => ['name' => 'Panama', 'path' => __DIR__ . '/flags/pa.png'], - 'pe' => ['name' => 'Peru', 'path' => __DIR__ . '/flags/pe.png'], - 'ph' => ['name' => 'Philippines', 'path' => __DIR__ . '/flags/ph.png'], - 'pw' => ['name' => 'Palau', 'path' => __DIR__ . '/flags/pw.png'], - 'pg' => ['name' => 'Papua New Guinea', 'path' => __DIR__ . '/flags/pg.png'], - 'pl' => ['name' => 'Poland', 'path' => __DIR__ . '/flags/pl.png'], - 'kp' => ['name' => 'North Korea', 'path' => __DIR__ . '/flags/kp.png'], - 'pt' => ['name' => 'Portugal', 'path' => __DIR__ . '/flags/pt.png'], - 'py' => ['name' => 'Paraguay', 'path' => __DIR__ . '/flags/py.png'], - 'qa' => ['name' => 'Qatar', 'path' => __DIR__ . '/flags/qa.png'], - 'ro' => ['name' => 'Romania', 'path' => __DIR__ . '/flags/ro.png'], - 'ru' => ['name' => 'Russia', 'path' => __DIR__ . '/flags/ru.png'], - 'rw' => ['name' => 'Rwanda', 'path' => __DIR__ . '/flags/rw.png'], - 'sa' => ['name' => 'Saudi Arabia', 'path' => __DIR__ . '/flags/sa.png'], - 'sd' => ['name' => 'Sudan', 'path' => __DIR__ . '/flags/sd.png'], - 'sn' => ['name' => 'Senegal', 'path' => __DIR__ . '/flags/sn.png'], - 'sg' => ['name' => 'Singapore', 'path' => __DIR__ . '/flags/sg.png'], - 'sb' => ['name' => 'Solomon Islands', 'path' => __DIR__ . '/flags/sb.png'], - 'sl' => ['name' => 'Sierra Leone', 'path' => __DIR__ . '/flags/sl.png'], - 'sv' => ['name' => 'El Salvador', 'path' => __DIR__ . '/flags/sv.png'], - 'sm' => ['name' => 'San Marino', 'path' => __DIR__ . '/flags/sm.png'], - 'so' => ['name' => 'Somalia', 'path' => __DIR__ . '/flags/so.png'], - 'rs' => ['name' => 'Serbia', 'path' => __DIR__ . '/flags/rs.png'], - 'ss' => ['name' => 'South Sudan', 'path' => __DIR__ . '/flags/ss.png'], - 'st' => ['name' => 'Sao Tome and Principe', 'path' => __DIR__ . '/flags/st.png'], - 'sr' => ['name' => 'Suriname', 'path' => __DIR__ . '/flags/sr.png'], - 'sk' => ['name' => 'Slovakia', 'path' => __DIR__ . '/flags/sk.png'], - 'si' => ['name' => 'Slovenia', 'path' => __DIR__ . '/flags/si.png'], - 'se' => ['name' => 'Sweden', 'path' => __DIR__ . '/flags/se.png'], - 'sz' => ['name' => 'Eswatini', 'path' => __DIR__ . '/flags/sz.png'], - 'sc' => ['name' => 'Seychelles', 'path' => __DIR__ . '/flags/sc.png'], - 'sy' => ['name' => 'Syria', 'path' => __DIR__ . '/flags/sy.png'], - 'td' => ['name' => 'Chad', 'path' => __DIR__ . '/flags/td.png'], - 'tg' => ['name' => 'Togo', 'path' => __DIR__ . '/flags/tg.png'], - 'th' => ['name' => 'Thailand', 'path' => __DIR__ . '/flags/th.png'], - 'tj' => ['name' => 'Tajikistan', 'path' => __DIR__ . '/flags/tj.png'], - 'tm' => ['name' => 'Turkmenistan', 'path' => __DIR__ . '/flags/tm.png'], - 'tl' => ['name' => 'Timor-Leste', 'path' => __DIR__ . '/flags/tl.png'], - 'to' => ['name' => 'Tonga', 'path' => __DIR__ . '/flags/to.png'], - 'tt' => ['name' => 'Trinidad and Tobago', 'path' => __DIR__ . '/flags/tt.png'], - 'tn' => ['name' => 'Tunisia', 'path' => __DIR__ . '/flags/tn.png'], - 'tr' => ['name' => 'Turkey', 'path' => __DIR__ . '/flags/tr.png'], - 'tv' => ['name' => 'Tuvalu', 'path' => __DIR__ . '/flags/tv.png'], - 'tz' => ['name' => 'Tanzania', 'path' => __DIR__ . '/flags/tz.png'], - 'ug' => ['name' => 'Uganda', 'path' => __DIR__ . '/flags/ug.png'], - 'ua' => ['name' => 'Ukraine', 'path' => __DIR__ . '/flags/ua.png'], - 'uy' => ['name' => 'Uruguay', 'path' => __DIR__ . '/flags/uy.png'], - 'us' => ['name' => 'United States', 'path' => __DIR__ . '/flags/us.png'], - 'uz' => ['name' => 'Uzbekistan', 'path' => __DIR__ . '/flags/uz.png'], - 'va' => ['name' => 'Vatican City', 'path' => __DIR__ . '/flags/va.png'], - 'vc' => ['name' => 'Saint Vincent and the Grenadines', 'path' => __DIR__ . '/flags/vc.png'], - 've' => ['name' => 'Venezuela', 'path' => __DIR__ . '/flags/ve.png'], - 'vn' => ['name' => 'Vietnam', 'path' => __DIR__ . '/flags/vn.png'], - 'vu' => ['name' => 'Vanuatu', 'path' => __DIR__ . '/flags/vu.png'], - 'ws' => ['name' => 'Samoa', 'path' => __DIR__ . '/flags/ws.png'], - 'ye' => ['name' => 'Yemen', 'path' => __DIR__ . '/flags/ye.png'], - 'za' => ['name' => 'South Africa', 'path' => __DIR__ . '/flags/za.png'], - 'zm' => ['name' => 'Zambia', 'path' => __DIR__ . '/flags/zm.png'], - 'zw' => ['name' => 'Zimbabwe', 'path' => __DIR__ . '/flags/zw.png'], + 'af' => ['name' => 'Afghanistan', 'path' => __DIR__.'/flags/af.png'], + 'ao' => ['name' => 'Angola', 'path' => __DIR__.'/flags/ao.png'], + 'al' => ['name' => 'Albania', 'path' => __DIR__.'/flags/al.png'], + 'ad' => ['name' => 'Andorra', 'path' => __DIR__.'/flags/ad.png'], + 'ae' => ['name' => 'United Arab Emirates', 'path' => __DIR__.'/flags/ae.png'], + 'ar' => ['name' => 'Argentina', 'path' => __DIR__.'/flags/ar.png'], + 'am' => ['name' => 'Armenia', 'path' => __DIR__.'/flags/am.png'], + 'ag' => ['name' => 'Antigua and Barbuda', 'path' => __DIR__.'/flags/ag.png'], + 'au' => ['name' => 'Australia', 'path' => __DIR__.'/flags/au.png'], + 'at' => ['name' => 'Austria', 'path' => __DIR__.'/flags/at.png'], + 'az' => ['name' => 'Azerbaijan', 'path' => __DIR__.'/flags/az.png'], + 'bi' => ['name' => 'Burundi', 'path' => __DIR__.'/flags/bi.png'], + 'be' => ['name' => 'Belgium', 'path' => __DIR__.'/flags/be.png'], + 'bj' => ['name' => 'Benin', 'path' => __DIR__.'/flags/bj.png'], + 'bf' => ['name' => 'Burkina Faso', 'path' => __DIR__.'/flags/bf.png'], + 'bd' => ['name' => 'Bangladesh', 'path' => __DIR__.'/flags/bd.png'], + 'bg' => ['name' => 'Bulgaria', 'path' => __DIR__.'/flags/bg.png'], + 'bh' => ['name' => 'Bahrain', 'path' => __DIR__.'/flags/bh.png'], + 'bs' => ['name' => 'Bahamas', 'path' => __DIR__.'/flags/bs.png'], + 'ba' => ['name' => 'Bosnia and Herzegovina', 'path' => __DIR__.'/flags/ba.png'], + 'by' => ['name' => 'Belarus', 'path' => __DIR__.'/flags/by.png'], + 'bz' => ['name' => 'Belize', 'path' => __DIR__.'/flags/bz.png'], + 'bo' => ['name' => 'Bolivia', 'path' => __DIR__.'/flags/bo.png'], + 'br' => ['name' => 'Brazil', 'path' => __DIR__.'/flags/br.png'], + 'bb' => ['name' => 'Barbados', 'path' => __DIR__.'/flags/bb.png'], + 'bn' => ['name' => 'Brunei Darussalam', 'path' => __DIR__.'/flags/bn.png'], + 'bt' => ['name' => 'Bhutan', 'path' => __DIR__.'/flags/bt.png'], + 'bw' => ['name' => 'Botswana', 'path' => __DIR__.'/flags/bw.png'], + 'cf' => ['name' => 'Central African Republic', 'path' => __DIR__.'/flags/cf.png'], + 'ca' => ['name' => 'Canada', 'path' => __DIR__.'/flags/ca.png'], + 'ch' => ['name' => 'Switzerland', 'path' => __DIR__.'/flags/ch.png'], + 'cl' => ['name' => 'Chile', 'path' => __DIR__.'/flags/cl.png'], + 'cn' => ['name' => 'China', 'path' => __DIR__.'/flags/cn.png'], + 'ci' => ['name' => 'Côte d\'Ivoire', 'path' => __DIR__.'/flags/ci.png'], + 'cm' => ['name' => 'Cameroon', 'path' => __DIR__.'/flags/cm.png'], + 'cd' => ['name' => 'Democratic Republic of the Congo', 'path' => __DIR__.'/flags/cd.png'], + 'cg' => ['name' => 'Republic of the Congo', 'path' => __DIR__.'/flags/cg.png'], + 'co' => ['name' => 'Colombia', 'path' => __DIR__.'/flags/co.png'], + 'km' => ['name' => 'Comoros', 'path' => __DIR__.'/flags/km.png'], + 'cv' => ['name' => 'Cape Verde', 'path' => __DIR__.'/flags/cv.png'], + 'cr' => ['name' => 'Costa Rica', 'path' => __DIR__.'/flags/cr.png'], + 'cu' => ['name' => 'Cuba', 'path' => __DIR__.'/flags/cu.png'], + 'cy' => ['name' => 'Cyprus', 'path' => __DIR__.'/flags/cy.png'], + 'cz' => ['name' => 'Czech Republic', 'path' => __DIR__.'/flags/cz.png'], + 'de' => ['name' => 'Germany', 'path' => __DIR__.'/flags/de.png'], + 'dj' => ['name' => 'Djibouti', 'path' => __DIR__.'/flags/dj.png'], + 'dm' => ['name' => 'Dominica', 'path' => __DIR__.'/flags/dm.png'], + 'dk' => ['name' => 'Denmark', 'path' => __DIR__.'/flags/dk.png'], + 'do' => ['name' => 'Dominican Republic', 'path' => __DIR__.'/flags/do.png'], + 'dz' => ['name' => 'Algeria', 'path' => __DIR__.'/flags/dz.png'], + 'ec' => ['name' => 'Ecuador', 'path' => __DIR__.'/flags/ec.png'], + 'eg' => ['name' => 'Egypt', 'path' => __DIR__.'/flags/eg.png'], + 'er' => ['name' => 'Eritrea', 'path' => __DIR__.'/flags/er.png'], + 'es' => ['name' => 'Spain', 'path' => __DIR__.'/flags/es.png'], + 'ee' => ['name' => 'Estonia', 'path' => __DIR__.'/flags/ee.png'], + 'et' => ['name' => 'Ethiopia', 'path' => __DIR__.'/flags/et.png'], + 'fi' => ['name' => 'Finland', 'path' => __DIR__.'/flags/fi.png'], + 'fj' => ['name' => 'Fiji', 'path' => __DIR__.'/flags/fj.png'], + 'fr' => ['name' => 'France', 'path' => __DIR__.'/flags/fr.png'], + 'fm' => ['name' => 'Micronesia (Federated States of)', 'path' => __DIR__.'/flags/fm.png'], + 'ga' => ['name' => 'Gabon', 'path' => __DIR__.'/flags/ga.png'], + 'gb' => ['name' => 'United Kingdom', 'path' => __DIR__.'/flags/gb.png'], + 'ge' => ['name' => 'Georgia', 'path' => __DIR__.'/flags/ge.png'], + 'gh' => ['name' => 'Ghana', 'path' => __DIR__.'/flags/gh.png'], + 'gn' => ['name' => 'Guinea', 'path' => __DIR__.'/flags/gn.png'], + 'gm' => ['name' => 'Gambia', 'path' => __DIR__.'/flags/gm.png'], + 'gw' => ['name' => 'Guinea-Bissau', 'path' => __DIR__.'/flags/gw.png'], + 'gq' => ['name' => 'Equatorial Guinea', 'path' => __DIR__.'/flags/gq.png'], + 'gr' => ['name' => 'Greece', 'path' => __DIR__.'/flags/gr.png'], + 'gd' => ['name' => 'Grenada', 'path' => __DIR__.'/flags/gd.png'], + 'gt' => ['name' => 'Guatemala', 'path' => __DIR__.'/flags/gt.png'], + 'gy' => ['name' => 'Guyana', 'path' => __DIR__.'/flags/gy.png'], + 'hn' => ['name' => 'Honduras', 'path' => __DIR__.'/flags/hn.png'], + 'hr' => ['name' => 'Croatia', 'path' => __DIR__.'/flags/hr.png'], + 'ht' => ['name' => 'Haiti', 'path' => __DIR__.'/flags/ht.png'], + 'hu' => ['name' => 'Hungary', 'path' => __DIR__.'/flags/hu.png'], + 'id' => ['name' => 'Indonesia', 'path' => __DIR__.'/flags/id.png'], + 'in' => ['name' => 'India', 'path' => __DIR__.'/flags/in.png'], + 'ie' => ['name' => 'Ireland', 'path' => __DIR__.'/flags/ie.png'], + 'ir' => ['name' => 'Iran (Islamic Republic of)', 'path' => __DIR__.'/flags/ir.png'], + 'iq' => ['name' => 'Iraq', 'path' => __DIR__.'/flags/iq.png'], + 'is' => ['name' => 'Iceland', 'path' => __DIR__.'/flags/is.png'], + 'il' => ['name' => 'Israel', 'path' => __DIR__.'/flags/il.png'], + 'it' => ['name' => 'Italy', 'path' => __DIR__.'/flags/it.png'], + 'jm' => ['name' => 'Jamaica', 'path' => __DIR__.'/flags/jm.png'], + 'jo' => ['name' => 'Jordan', 'path' => __DIR__.'/flags/jo.png'], + 'jp' => ['name' => 'Japan', 'path' => __DIR__.'/flags/jp.png'], + 'kz' => ['name' => 'Kazakhstan', 'path' => __DIR__.'/flags/kz.png'], + 'ke' => ['name' => 'Kenya', 'path' => __DIR__.'/flags/ke.png'], + 'kg' => ['name' => 'Kyrgyzstan', 'path' => __DIR__.'/flags/kg.png'], + 'kh' => ['name' => 'Cambodia', 'path' => __DIR__.'/flags/kh.png'], + 'ki' => ['name' => 'Kiribati', 'path' => __DIR__.'/flags/ki.png'], + 'kn' => ['name' => 'Saint Kitts and Nevis', 'path' => __DIR__.'/flags/kn.png'], + 'kr' => ['name' => 'South Korea', 'path' => __DIR__.'/flags/kr.png'], + 'kw' => ['name' => 'Kuwait', 'path' => __DIR__.'/flags/kw.png'], + 'la' => ['name' => 'Lao People\'s Democratic Republic', 'path' => __DIR__.'/flags/la.png'], + 'lb' => ['name' => 'Lebanon', 'path' => __DIR__.'/flags/lb.png'], + 'lr' => ['name' => 'Liberia', 'path' => __DIR__.'/flags/lr.png'], + 'ly' => ['name' => 'Libya', 'path' => __DIR__.'/flags/ly.png'], + 'lc' => ['name' => 'Saint Lucia', 'path' => __DIR__.'/flags/lc.png'], + 'li' => ['name' => 'Liechtenstein', 'path' => __DIR__.'/flags/li.png'], + 'lk' => ['name' => 'Sri Lanka', 'path' => __DIR__.'/flags/lk.png'], + 'ls' => ['name' => 'Lesotho', 'path' => __DIR__.'/flags/ls.png'], + 'lt' => ['name' => 'Lithuania', 'path' => __DIR__.'/flags/lt.png'], + 'lu' => ['name' => 'Luxembourg', 'path' => __DIR__.'/flags/lu.png'], + 'lv' => ['name' => 'Latvia', 'path' => __DIR__.'/flags/lv.png'], + 'ma' => ['name' => 'Morocco', 'path' => __DIR__.'/flags/ma.png'], + 'mc' => ['name' => 'Monaco', 'path' => __DIR__.'/flags/mc.png'], + 'md' => ['name' => 'Moldova', 'path' => __DIR__.'/flags/md.png'], + 'mg' => ['name' => 'Madagascar', 'path' => __DIR__.'/flags/mg.png'], + 'mv' => ['name' => 'Maldives', 'path' => __DIR__.'/flags/mv.png'], + 'mx' => ['name' => 'Mexico', 'path' => __DIR__.'/flags/mx.png'], + 'mh' => ['name' => 'Marshall Islands', 'path' => __DIR__.'/flags/mh.png'], + 'mk' => ['name' => 'North Macedonia', 'path' => __DIR__.'/flags/mk.png'], + 'ml' => ['name' => 'Mali', 'path' => __DIR__.'/flags/ml.png'], + 'mt' => ['name' => 'Malta', 'path' => __DIR__.'/flags/mt.png'], + 'mm' => ['name' => 'Myanmar', 'path' => __DIR__.'/flags/mm.png'], + 'me' => ['name' => 'Montenegro', 'path' => __DIR__.'/flags/me.png'], + 'mn' => ['name' => 'Mongolia', 'path' => __DIR__.'/flags/mn.png'], + 'mz' => ['name' => 'Mozambique', 'path' => __DIR__.'/flags/mz.png'], + 'mr' => ['name' => 'Mauritania', 'path' => __DIR__.'/flags/mr.png'], + 'mu' => ['name' => 'Mauritius', 'path' => __DIR__.'/flags/mu.png'], + 'mw' => ['name' => 'Malawi', 'path' => __DIR__.'/flags/mw.png'], + 'my' => ['name' => 'Malaysia', 'path' => __DIR__.'/flags/my.png'], + 'na' => ['name' => 'Namibia', 'path' => __DIR__.'/flags/na.png'], + 'ne' => ['name' => 'Niger', 'path' => __DIR__.'/flags/ne.png'], + 'ng' => ['name' => 'Nigeria', 'path' => __DIR__.'/flags/ng.png'], + 'ni' => ['name' => 'Nicaragua', 'path' => __DIR__.'/flags/ni.png'], + 'nl' => ['name' => 'Netherlands', 'path' => __DIR__.'/flags/nl.png'], + 'no' => ['name' => 'Norway', 'path' => __DIR__.'/flags/no.png'], + 'np' => ['name' => 'Nepal', 'path' => __DIR__.'/flags/np.png'], + 'nr' => ['name' => 'Nauru', 'path' => __DIR__.'/flags/nr.png'], + 'nz' => ['name' => 'New Zealand', 'path' => __DIR__.'/flags/nz.png'], + 'om' => ['name' => 'Oman', 'path' => __DIR__.'/flags/om.png'], + 'pk' => ['name' => 'Pakistan', 'path' => __DIR__.'/flags/pk.png'], + 'pa' => ['name' => 'Panama', 'path' => __DIR__.'/flags/pa.png'], + 'pe' => ['name' => 'Peru', 'path' => __DIR__.'/flags/pe.png'], + 'ph' => ['name' => 'Philippines', 'path' => __DIR__.'/flags/ph.png'], + 'pw' => ['name' => 'Palau', 'path' => __DIR__.'/flags/pw.png'], + 'pg' => ['name' => 'Papua New Guinea', 'path' => __DIR__.'/flags/pg.png'], + 'pl' => ['name' => 'Poland', 'path' => __DIR__.'/flags/pl.png'], + 'kp' => ['name' => 'North Korea', 'path' => __DIR__.'/flags/kp.png'], + 'pt' => ['name' => 'Portugal', 'path' => __DIR__.'/flags/pt.png'], + 'py' => ['name' => 'Paraguay', 'path' => __DIR__.'/flags/py.png'], + 'qa' => ['name' => 'Qatar', 'path' => __DIR__.'/flags/qa.png'], + 'ro' => ['name' => 'Romania', 'path' => __DIR__.'/flags/ro.png'], + 'ru' => ['name' => 'Russia', 'path' => __DIR__.'/flags/ru.png'], + 'rw' => ['name' => 'Rwanda', 'path' => __DIR__.'/flags/rw.png'], + 'sa' => ['name' => 'Saudi Arabia', 'path' => __DIR__.'/flags/sa.png'], + 'sd' => ['name' => 'Sudan', 'path' => __DIR__.'/flags/sd.png'], + 'sn' => ['name' => 'Senegal', 'path' => __DIR__.'/flags/sn.png'], + 'sg' => ['name' => 'Singapore', 'path' => __DIR__.'/flags/sg.png'], + 'sb' => ['name' => 'Solomon Islands', 'path' => __DIR__.'/flags/sb.png'], + 'sl' => ['name' => 'Sierra Leone', 'path' => __DIR__.'/flags/sl.png'], + 'sv' => ['name' => 'El Salvador', 'path' => __DIR__.'/flags/sv.png'], + 'sm' => ['name' => 'San Marino', 'path' => __DIR__.'/flags/sm.png'], + 'so' => ['name' => 'Somalia', 'path' => __DIR__.'/flags/so.png'], + 'rs' => ['name' => 'Serbia', 'path' => __DIR__.'/flags/rs.png'], + 'ss' => ['name' => 'South Sudan', 'path' => __DIR__.'/flags/ss.png'], + 'st' => ['name' => 'Sao Tome and Principe', 'path' => __DIR__.'/flags/st.png'], + 'sr' => ['name' => 'Suriname', 'path' => __DIR__.'/flags/sr.png'], + 'sk' => ['name' => 'Slovakia', 'path' => __DIR__.'/flags/sk.png'], + 'si' => ['name' => 'Slovenia', 'path' => __DIR__.'/flags/si.png'], + 'se' => ['name' => 'Sweden', 'path' => __DIR__.'/flags/se.png'], + 'sz' => ['name' => 'Eswatini', 'path' => __DIR__.'/flags/sz.png'], + 'sc' => ['name' => 'Seychelles', 'path' => __DIR__.'/flags/sc.png'], + 'sy' => ['name' => 'Syria', 'path' => __DIR__.'/flags/sy.png'], + 'td' => ['name' => 'Chad', 'path' => __DIR__.'/flags/td.png'], + 'tg' => ['name' => 'Togo', 'path' => __DIR__.'/flags/tg.png'], + 'th' => ['name' => 'Thailand', 'path' => __DIR__.'/flags/th.png'], + 'tj' => ['name' => 'Tajikistan', 'path' => __DIR__.'/flags/tj.png'], + 'tm' => ['name' => 'Turkmenistan', 'path' => __DIR__.'/flags/tm.png'], + 'tl' => ['name' => 'Timor-Leste', 'path' => __DIR__.'/flags/tl.png'], + 'to' => ['name' => 'Tonga', 'path' => __DIR__.'/flags/to.png'], + 'tt' => ['name' => 'Trinidad and Tobago', 'path' => __DIR__.'/flags/tt.png'], + 'tn' => ['name' => 'Tunisia', 'path' => __DIR__.'/flags/tn.png'], + 'tr' => ['name' => 'Turkey', 'path' => __DIR__.'/flags/tr.png'], + 'tv' => ['name' => 'Tuvalu', 'path' => __DIR__.'/flags/tv.png'], + 'tz' => ['name' => 'Tanzania', 'path' => __DIR__.'/flags/tz.png'], + 'ug' => ['name' => 'Uganda', 'path' => __DIR__.'/flags/ug.png'], + 'ua' => ['name' => 'Ukraine', 'path' => __DIR__.'/flags/ua.png'], + 'uy' => ['name' => 'Uruguay', 'path' => __DIR__.'/flags/uy.png'], + 'us' => ['name' => 'United States', 'path' => __DIR__.'/flags/us.png'], + 'uz' => ['name' => 'Uzbekistan', 'path' => __DIR__.'/flags/uz.png'], + 'va' => ['name' => 'Vatican City', 'path' => __DIR__.'/flags/va.png'], + 'vc' => ['name' => 'Saint Vincent and the Grenadines', 'path' => __DIR__.'/flags/vc.png'], + 've' => ['name' => 'Venezuela', 'path' => __DIR__.'/flags/ve.png'], + 'vn' => ['name' => 'Vietnam', 'path' => __DIR__.'/flags/vn.png'], + 'vu' => ['name' => 'Vanuatu', 'path' => __DIR__.'/flags/vu.png'], + 'ws' => ['name' => 'Samoa', 'path' => __DIR__.'/flags/ws.png'], + 'ye' => ['name' => 'Yemen', 'path' => __DIR__.'/flags/ye.png'], + 'za' => ['name' => 'South Africa', 'path' => __DIR__.'/flags/za.png'], + 'zm' => ['name' => 'Zambia', 'path' => __DIR__.'/flags/zm.png'], + 'zw' => ['name' => 'Zimbabwe', 'path' => __DIR__.'/flags/zw.png'], ]; diff --git a/app/config/avatars/os.php b/app/config/avatars/os.php index f500eed759..ba5ee0e1fc 100644 --- a/app/config/avatars/os.php +++ b/app/config/avatars/os.php @@ -2,9 +2,9 @@ return [ // Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php - 'AND' => __DIR__ . '/os/android.png', - 'ATV' => __DIR__ . '/os/apple-tv.png', - 'COS' => __DIR__ . '/os/chrome-os.png', + 'AND' => __DIR__.'/os/android.png', + 'ATV' => __DIR__.'/os/apple-tv.png', + 'COS' => __DIR__.'/os/chrome-os.png', /* 'AIX' => 'AIX', diff --git a/app/config/collections.php b/app/config/collections.php index c9005f8217..af68b4174e 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -16,7 +16,6 @@ $auth = Config::getParam('auth', []); * attributes => list of attributes * indexes => list of indexes */ - $commonCollections = [ 'users' => [ '$collection' => ID::custom(Database::METADATA), @@ -253,7 +252,7 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => ['datetime'], - ] + ], ], 'indexes' => [ [ @@ -410,7 +409,7 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => [], - ] + ], ], 'indexes' => [ [ @@ -1278,7 +1277,7 @@ $commonCollections = [ 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], - ] + ], ], 'stats' => [ @@ -1454,7 +1453,7 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => ['json', 'encrypt'], - ] + ], ], 'indexes' => [ [ @@ -1470,7 +1469,7 @@ $commonCollections = [ 'attributes' => ['name'], 'lengths' => [128], 'orders' => [Database::ORDER_ASC], - ] + ], ], ], @@ -1811,7 +1810,7 @@ $commonCollections = [ 'attributes' => ['topicInternalId'], 'lengths' => [], 'orders' => [], - ] + ], ], ], @@ -1924,7 +1923,7 @@ $commonCollections = [ 'orders' => [], ], ], - ] + ], ]; $projectCollections = array_merge([ @@ -2667,7 +2666,7 @@ $projectCollections = array_merge([ 'default' => false, 'array' => false, 'filters' => [], - ] + ], ], 'indexes' => [ [ @@ -2858,7 +2857,7 @@ $projectCollections = array_merge([ 'default' => '', 'array' => false, 'filters' => [], - ] + ], ], 'indexes' => [ [ @@ -2867,7 +2866,7 @@ $projectCollections = array_merge([ 'attributes' => ['deploymentId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], - ] + ], ], ], @@ -3102,7 +3101,7 @@ $projectCollections = array_merge([ 'required' => true, 'default' => null, 'array' => false, - 'filters' => [ 'encrypt' ] + 'filters' => ['encrypt'], ], [ '$id' => ID::custom('search'), @@ -3186,7 +3185,7 @@ $projectCollections = array_merge([ 'array' => false, 'filters' => [], ], - ], + ], 'indexes' => [ [ '$id' => '_key_accessedAt', @@ -3308,7 +3307,7 @@ $projectCollections = array_merge([ 'default' => null, 'array' => false, 'filters' => [], - ] + ], ], 'indexes' => [ [ @@ -3338,7 +3337,7 @@ $projectCollections = array_merge([ 'attributes' => ['search'], 'lengths' => [], 'orders' => [], - ] + ], ], ], ], $commonCollections); @@ -3748,7 +3747,7 @@ $consoleCollections = array_merge([ [ '$id' => ID::custom('_key_region_resourceType_resourceUpdatedAt'), 'type' => Database::INDEX_KEY, - 'attributes' => ['region', 'resourceType','resourceUpdatedAt'], + 'attributes' => ['region', 'resourceType', 'resourceUpdatedAt'], 'lengths' => [], 'orders' => [], ], @@ -3843,7 +3842,7 @@ $consoleCollections = array_merge([ 'default' => null, 'array' => false, 'filters' => [], - ] + ], ], 'indexes' => [ [ @@ -4185,7 +4184,7 @@ $consoleCollections = array_merge([ 'attributes' => ['projectInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], - ] + ], ], ], @@ -4312,7 +4311,7 @@ $consoleCollections = array_merge([ 'default' => null, 'array' => false, 'filters' => [], //TODO: use json filter - ] + ], ], 'indexes' => [ [ @@ -4322,7 +4321,7 @@ $consoleCollections = array_merge([ 'lengths' => [], 'orders' => [Database::ORDER_DESC], ], - ] + ], ], ], $commonCollections); @@ -4588,7 +4587,7 @@ $bucketCollections = [ 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], - ] + ], ], ]; @@ -4711,15 +4710,14 @@ $dbCollections = [ 'orders' => [Database::ORDER_ASC], ], ], - ] + ], ]; - $collections = [ 'projects' => $projectCollections, - 'console' => $consoleCollections, + 'console' => $consoleCollections, 'buckets' => $bucketCollections, - 'databases' => $dbCollections + 'databases' => $dbCollections, ]; return $collections; diff --git a/app/config/errors.php b/app/config/errors.php index 5942c6027c..8b11410996 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -299,7 +299,7 @@ return [ Exception::AVATAR_SET_NOT_FOUND => [ 'name' => Exception::AVATAR_SET_NOT_FOUND, 'description' => 'The requested avatar set could not be found.', - 'code' => 404 + 'code' => 404, ], Exception::AVATAR_NOT_FOUND => [ 'name' => Exception::AVATAR_NOT_FOUND, @@ -426,13 +426,13 @@ return [ Exception::DATABASE_NOT_FOUND => [ 'name' => Exception::DATABASE_NOT_FOUND, 'description' => 'Database not found', - 'code' => 404 + 'code' => 404, ], Exception::DATABASE_ALREADY_EXISTS => [ 'name' => Exception::DATABASE_ALREADY_EXISTS, 'description' => 'Database already exists', - 'code' => 409 + 'code' => 409, ], /** Collections */ @@ -702,5 +702,5 @@ return [ 'name' => Exception::PROVIDER_INCORRECT_TYPE, 'description' => 'Provider with the request ID is of incorrect type: ', 'code' => 400, - ] + ], ]; diff --git a/app/config/events.php b/app/config/events.php index 45bb45fbf8..4ecc651240 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -19,7 +19,7 @@ return [ '$description' => 'This event triggers when a session for a user is created.', ], 'delete' => [ - '$description' => 'This event triggers when a session for a user is deleted.' + '$description' => 'This event triggers when a session for a user is deleted.', ], ], 'recovery' => [ @@ -30,7 +30,7 @@ return [ '$description' => 'This event triggers when a recovery token for a user is created.', ], 'update' => [ - '$description' => 'This event triggers when a recovery token for a user is validated.' + '$description' => 'This event triggers when a recovery token for a user is validated.', ], ], 'verification' => [ @@ -41,7 +41,7 @@ return [ '$description' => 'This event triggers when a verification token for a user is created.', ], 'update' => [ - '$description' => 'This event triggers when a verification token for a user is validated.' + '$description' => 'This event triggers when a verification token for a user is validated.', ], ], 'targets' => [ @@ -59,7 +59,7 @@ return [ ], ], 'create' => [ - '$description' => 'This event triggers when a user is created.' + '$description' => 'This event triggers when a user is created.', ], 'delete' => [ '$description' => 'This event triggers when a user is deleted.', @@ -81,7 +81,7 @@ return [ 'prefs' => [ '$description' => 'This event triggers when a user\'s preferences is updated.', ], - ] + ], ], 'databases' => [ '$model' => Response::MODEL_DATABASE, @@ -99,10 +99,10 @@ return [ '$description' => 'This event triggers when a document is created.', ], 'delete' => [ - '$description' => 'This event triggers when a document is deleted.' + '$description' => 'This event triggers when a document is deleted.', ], 'update' => [ - '$description' => 'This event triggers when a document is updated.' + '$description' => 'This event triggers when a document is updated.', ], ], 'indexes' => [ @@ -113,8 +113,8 @@ return [ '$description' => 'This event triggers when an index is created.', ], 'delete' => [ - '$description' => 'This event triggers when an index is deleted.' - ] + '$description' => 'This event triggers when an index is deleted.', + ], ], 'attributes' => [ '$model' => Response::MODEL_ATTRIBUTE, @@ -124,28 +124,28 @@ return [ '$description' => 'This event triggers when an attribute is created.', ], 'delete' => [ - '$description' => 'This event triggers when an attribute is deleted.' - ] + '$description' => 'This event triggers when an attribute is deleted.', + ], ], 'create' => [ - '$description' => 'This event triggers when a collection is created.' + '$description' => 'This event triggers when a collection is created.', ], 'delete' => [ '$description' => 'This event triggers when a collection is deleted.', ], 'update' => [ '$description' => 'This event triggers when a collection is updated.', - ] + ], ], 'create' => [ - '$description' => 'This event triggers when a database is created.' + '$description' => 'This event triggers when a database is created.', ], 'delete' => [ '$description' => 'This event triggers when a database is deleted.', ], 'update' => [ '$description' => 'This event triggers when a database is updated.', - ] + ], ], 'buckets' => [ '$model' => Response::MODEL_BUCKET, @@ -159,21 +159,21 @@ return [ '$description' => 'This event triggers when a file is created.', ], 'delete' => [ - '$description' => 'This event triggers when a file is deleted.' + '$description' => 'This event triggers when a file is deleted.', ], 'update' => [ - '$description' => 'This event triggers when a file is updated.' + '$description' => 'This event triggers when a file is updated.', ], ], 'create' => [ - '$description' => 'This event triggers when a bucket is created.' + '$description' => 'This event triggers when a bucket is created.', ], 'delete' => [ '$description' => 'This event triggers when a bucket is deleted.', ], 'update' => [ '$description' => 'This event triggers when a bucket is updated.', - ] + ], ], 'teams' => [ '$model' => Response::MODEL_TEAM, @@ -187,17 +187,17 @@ return [ '$description' => 'This event triggers when a membership is created.', ], 'delete' => [ - '$description' => 'This event triggers when a membership is deleted.' + '$description' => 'This event triggers when a membership is deleted.', ], 'update' => [ '$description' => 'This event triggers when a membership is updated.', 'status' => [ - '$description' => 'This event triggers when a team memberships status is updated.' - ] + '$description' => 'This event triggers when a team memberships status is updated.', + ], ], ], 'create' => [ - '$description' => 'This event triggers when a team is created.' + '$description' => 'This event triggers when a team is created.', ], 'delete' => [ '$description' => 'This event triggers when a team is deleted.', @@ -207,7 +207,7 @@ return [ 'prefs' => [ '$description' => 'This event triggers when a team\'s preferences are updated.', ], - ] + ], ], 'functions' => [ '$model' => Response::MODEL_FUNCTION, @@ -221,10 +221,10 @@ return [ '$description' => 'This event triggers when a deployment is created.', ], 'delete' => [ - '$description' => 'This event triggers when a deployment is deleted.' + '$description' => 'This event triggers when a deployment is deleted.', ], 'update' => [ - '$description' => 'This event triggers when a deployment is updated.' + '$description' => 'This event triggers when a deployment is updated.', ], ], 'executions' => [ @@ -235,21 +235,21 @@ return [ '$description' => 'This event triggers when an execution is created.', ], 'delete' => [ - '$description' => 'This event triggers when an execution is deleted.' + '$description' => 'This event triggers when an execution is deleted.', ], 'update' => [ - '$description' => 'This event triggers when an execution is updated.' + '$description' => 'This event triggers when an execution is updated.', ], ], 'create' => [ - '$description' => 'This event triggers when a function is created.' + '$description' => 'This event triggers when a function is created.', ], 'delete' => [ '$description' => 'This event triggers when a function is deleted.', ], 'update' => [ '$description' => 'This event triggers when a function is updated.', - ] + ], ], 'messages' => [ '$model' => Response::MODEL_MESSAGE, @@ -269,7 +269,7 @@ return [ '$description' => 'This event triggers when a provider is updated.', ], 'delete' => [ - '$description' => 'This event triggers when a provider is deleted.' + '$description' => 'This event triggers when a provider is deleted.', ], ], 'topics' => [ @@ -280,7 +280,7 @@ return [ '$description' => 'This event triggers when a provider is created.', ], 'delete' => [ - '$description' => 'This event triggers when a provider is deleted.' + '$description' => 'This event triggers when a provider is deleted.', ], 'subscribers' => [ '$model' => Response::MODEL_SUBSCRIBER, @@ -290,7 +290,7 @@ return [ '$description' => 'This event triggers when a subscriber is created.', ], 'delete' => [ - '$description' => 'This event triggers when a subscriber is deleted.' + '$description' => 'This event triggers when a subscriber is deleted.', ], ], ], diff --git a/app/config/locale/codes.php b/app/config/locale/codes.php index 641a2a6220..ed878887ca 100644 --- a/app/config/locale/codes.php +++ b/app/config/locale/codes.php @@ -6,532 +6,531 @@ * * Source: * https://www.andiamo.co.uk/resources/iso-language-codes/ - * */ return [ [ - "code" => "af", - "name" => "Afrikaans", + 'code' => 'af', + 'name' => 'Afrikaans', ], [ - "code" => "ar-ae", - "name" => "Arabic (U.A.E.)", + 'code' => 'ar-ae', + 'name' => 'Arabic (U.A.E.)', ], [ - "code" => "ar-bh", - "name" => "Arabic (Bahrain)", + 'code' => 'ar-bh', + 'name' => 'Arabic (Bahrain)', ], [ - "code" => "ar-dz", - "name" => "Arabic (Algeria)", + 'code' => 'ar-dz', + 'name' => 'Arabic (Algeria)', ], [ - "code" => "ar-eg", - "name" => "Arabic (Egypt)", + 'code' => 'ar-eg', + 'name' => 'Arabic (Egypt)', ], [ - "code" => "ar-iq", - "name" => "Arabic (Iraq)", + 'code' => 'ar-iq', + 'name' => 'Arabic (Iraq)', ], [ - "code" => "ar-jo", - "name" => "Arabic (Jordan)", + 'code' => 'ar-jo', + 'name' => 'Arabic (Jordan)', ], [ - "code" => "ar-kw", - "name" => "Arabic (Kuwait)", + 'code' => 'ar-kw', + 'name' => 'Arabic (Kuwait)', ], [ - "code" => "ar-lb", - "name" => "Arabic (Lebanon)", + 'code' => 'ar-lb', + 'name' => 'Arabic (Lebanon)', ], [ - "code" => "ar-ly", - "name" => "Arabic (Libya)", + 'code' => 'ar-ly', + 'name' => 'Arabic (Libya)', ], [ - "code" => "ar-ma", - "name" => "Arabic (Morocco)", + 'code' => 'ar-ma', + 'name' => 'Arabic (Morocco)', ], [ - "code" => "ar-om", - "name" => "Arabic (Oman)", + 'code' => 'ar-om', + 'name' => 'Arabic (Oman)', ], [ - "code" => "ar-qa", - "name" => "Arabic (Qatar)", + 'code' => 'ar-qa', + 'name' => 'Arabic (Qatar)', ], [ - "code" => "ar-sa", - "name" => "Arabic (Saudi Arabia)", + 'code' => 'ar-sa', + 'name' => 'Arabic (Saudi Arabia)', ], [ - "code" => "ar-sy", - "name" => "Arabic (Syria)", + 'code' => 'ar-sy', + 'name' => 'Arabic (Syria)', ], [ - "code" => "ar-tn", - "name" => "Arabic (Tunisia)", + 'code' => 'ar-tn', + 'name' => 'Arabic (Tunisia)', ], [ - "code" => "ar-ye", - "name" => "Arabic (Yemen)", + 'code' => 'ar-ye', + 'name' => 'Arabic (Yemen)', ], [ - "code" => "as", - "name" => "Assamese", + 'code' => 'as', + 'name' => 'Assamese', ], [ - "code" => "az", - "name" => "Azerbaijani", + 'code' => 'az', + 'name' => 'Azerbaijani', ], [ - "code" => "be", - "name" => "Belarusian", + 'code' => 'be', + 'name' => 'Belarusian', ], [ - "code" => "bg", - "name" => "Bulgarian", + 'code' => 'bg', + 'name' => 'Bulgarian', ], [ - "code" => "bh", - "name" => "Bihari", + 'code' => 'bh', + 'name' => 'Bihari', ], [ - "code" => "bn", - "name" => "Bengali", + 'code' => 'bn', + 'name' => 'Bengali', ], [ - "code" => "bs", - "name" => "Bosnian", + 'code' => 'bs', + 'name' => 'Bosnian', ], [ - "code" => "ca", - "name" => "Catalan", + 'code' => 'ca', + 'name' => 'Catalan', ], [ - "code" => "cs", - "name" => "Czech", + 'code' => 'cs', + 'name' => 'Czech', ], [ - "code" => "cy", - "name" => "Welsh", + 'code' => 'cy', + 'name' => 'Welsh', ], [ - "code" => "da", - "name" => "Danish", + 'code' => 'da', + 'name' => 'Danish', ], [ - "code" => "de", - "name" => "German (Standard)", + 'code' => 'de', + 'name' => 'German (Standard)', ], [ - "code" => "de-at", - "name" => "German (Austria)", + 'code' => 'de-at', + 'name' => 'German (Austria)', ], [ - "code" => "de-ch", - "name" => "German (Switzerland)", + 'code' => 'de-ch', + 'name' => 'German (Switzerland)', ], [ - "code" => "de-li", - "name" => "German (Liechtenstein)", + 'code' => 'de-li', + 'name' => 'German (Liechtenstein)', ], [ - "code" => "de-lu", - "name" => "German (Luxembourg)", + 'code' => 'de-lu', + 'name' => 'German (Luxembourg)', ], [ - "code" => "el", - "name" => "Greek", + 'code' => 'el', + 'name' => 'Greek', ], [ - "code" => "en", - "name" => "English", + 'code' => 'en', + 'name' => 'English', ], [ - "code" => "en-au", - "name" => "English (Australia)", + 'code' => 'en-au', + 'name' => 'English (Australia)', ], [ - "code" => "en-bz", - "name" => "English (Belize)", + 'code' => 'en-bz', + 'name' => 'English (Belize)', ], [ - "code" => "en-ca", - "name" => "English (Canada)", + 'code' => 'en-ca', + 'name' => 'English (Canada)', ], [ - "code" => "en-gb", - "name" => "English (United Kingdom)", + 'code' => 'en-gb', + 'name' => 'English (United Kingdom)', ], [ - "code" => "en-ie", - "name" => "English (Ireland)", + 'code' => 'en-ie', + 'name' => 'English (Ireland)', ], [ - "code" => "en-jm", - "name" => "English (Jamaica)", + 'code' => 'en-jm', + 'name' => 'English (Jamaica)', ], [ - "code" => "en-nz", - "name" => "English (New Zealand)", + 'code' => 'en-nz', + 'name' => 'English (New Zealand)', ], [ - "code" => "en-tt", - "name" => "English (Trinidad)", + 'code' => 'en-tt', + 'name' => 'English (Trinidad)', ], [ - "code" => "en-us", - "name" => "English (United States)", + 'code' => 'en-us', + 'name' => 'English (United States)', ], [ - "code" => "en-za", - "name" => "English (South Africa)", + 'code' => 'en-za', + 'name' => 'English (South Africa)', ], [ - "code" => "eo", - "name" => "Esperanto", + 'code' => 'eo', + 'name' => 'Esperanto', ], [ - "code" => "es", - "name" => "Spanish (Spain)", + 'code' => 'es', + 'name' => 'Spanish (Spain)', ], [ - "code" => "es-ar", - "name" => "Spanish (Argentina)", + 'code' => 'es-ar', + 'name' => 'Spanish (Argentina)', ], [ - "code" => "es-bo", - "name" => "Spanish (Bolivia)", + 'code' => 'es-bo', + 'name' => 'Spanish (Bolivia)', ], [ - "code" => "es-cl", - "name" => "Spanish (Chile)", + 'code' => 'es-cl', + 'name' => 'Spanish (Chile)', ], [ - "code" => "es-co", - "name" => "Spanish (Colombia)", + 'code' => 'es-co', + 'name' => 'Spanish (Colombia)', ], [ - "code" => "es-cr", - "name" => "Spanish (Costa Rica)", + 'code' => 'es-cr', + 'name' => 'Spanish (Costa Rica)', ], [ - "code" => "es-do", - "name" => "Spanish (Dominican Republic)", + 'code' => 'es-do', + 'name' => 'Spanish (Dominican Republic)', ], [ - "code" => "es-ec", - "name" => "Spanish (Ecuador)", + 'code' => 'es-ec', + 'name' => 'Spanish (Ecuador)', ], [ - "code" => "es-gt", - "name" => "Spanish (Guatemala)", + 'code' => 'es-gt', + 'name' => 'Spanish (Guatemala)', ], [ - "code" => "es-hn", - "name" => "Spanish (Honduras)", + 'code' => 'es-hn', + 'name' => 'Spanish (Honduras)', ], [ - "code" => "es-mx", - "name" => "Spanish (Mexico)", + 'code' => 'es-mx', + 'name' => 'Spanish (Mexico)', ], [ - "code" => "es-ni", - "name" => "Spanish (Nicaragua)", + 'code' => 'es-ni', + 'name' => 'Spanish (Nicaragua)', ], [ - "code" => "es-pa", - "name" => "Spanish (Panama)", + 'code' => 'es-pa', + 'name' => 'Spanish (Panama)', ], [ - "code" => "es-pe", - "name" => "Spanish (Peru)", + 'code' => 'es-pe', + 'name' => 'Spanish (Peru)', ], [ - "code" => "es-pr", - "name" => "Spanish (Puerto Rico)", + 'code' => 'es-pr', + 'name' => 'Spanish (Puerto Rico)', ], [ - "code" => "es-py", - "name" => "Spanish (Paraguay)", + 'code' => 'es-py', + 'name' => 'Spanish (Paraguay)', ], [ - "code" => "es-sv", - "name" => "Spanish (El Salvador)", + 'code' => 'es-sv', + 'name' => 'Spanish (El Salvador)', ], [ - "code" => "es-uy", - "name" => "Spanish (Uruguay)", + 'code' => 'es-uy', + 'name' => 'Spanish (Uruguay)', ], [ - "code" => "es-ve", - "name" => "Spanish (Venezuela)", + 'code' => 'es-ve', + 'name' => 'Spanish (Venezuela)', ], [ - "code" => "et", - "name" => "Estonian", + 'code' => 'et', + 'name' => 'Estonian', ], [ - "code" => "eu", - "name" => "Basque", + 'code' => 'eu', + 'name' => 'Basque', ], [ - "code" => "fa", - "name" => "Farsi", + 'code' => 'fa', + 'name' => 'Farsi', ], [ - "code" => "fi", - "name" => "Finnish", + 'code' => 'fi', + 'name' => 'Finnish', ], [ - "code" => "fo", - "name" => "Faeroese", + 'code' => 'fo', + 'name' => 'Faeroese', ], [ - "code" => "fr", - "name" => "French (Standard)", + 'code' => 'fr', + 'name' => 'French (Standard)', ], [ - "code" => "fr-be", - "name" => "French (Belgium)", + 'code' => 'fr-be', + 'name' => 'French (Belgium)', ], [ - "code" => "fr-ca", - "name" => "French (Canada)", + 'code' => 'fr-ca', + 'name' => 'French (Canada)', ], [ - "code" => "fr-ch", - "name" => "French (Switzerland)", + 'code' => 'fr-ch', + 'name' => 'French (Switzerland)', ], [ - "code" => "fr-lu", - "name" => "French (Luxembourg)", + 'code' => 'fr-lu', + 'name' => 'French (Luxembourg)', ], [ - "code" => "ga", - "name" => "Irish", + 'code' => 'ga', + 'name' => 'Irish', ], [ - "code" => "gd", - "name" => "Gaelic (Scotland)", + 'code' => 'gd', + 'name' => 'Gaelic (Scotland)', ], [ - "code" => "he", - "name" => "Hebrew", + 'code' => 'he', + 'name' => 'Hebrew', ], [ - "code" => "hi", - "name" => "Hindi", + 'code' => 'hi', + 'name' => 'Hindi', ], [ - "code" => "hr", - "name" => "Croatian", + 'code' => 'hr', + 'name' => 'Croatian', ], [ - "code" => "hu", - "name" => "Hungarian", + 'code' => 'hu', + 'name' => 'Hungarian', ], [ - "code" => "id", - "name" => "Indonesian", + 'code' => 'id', + 'name' => 'Indonesian', ], [ - "code" => "is", - "name" => "Icelandic", + 'code' => 'is', + 'name' => 'Icelandic', ], [ - "code" => "it", - "name" => "Italian (Standard)", + 'code' => 'it', + 'name' => 'Italian (Standard)', ], [ - "code" => "it-ch", - "name" => "Italian (Switzerland)", + 'code' => 'it-ch', + 'name' => 'Italian (Switzerland)', ], [ - "code" => "ja", - "name" => "Japanese", + 'code' => 'ja', + 'name' => 'Japanese', ], [ - "code" => "ji", - "name" => "Yiddish", + 'code' => 'ji', + 'name' => 'Yiddish', ], [ - "code" => "ko", - "name" => "Korean", + 'code' => 'ko', + 'name' => 'Korean', ], [ - "code" => "ku", - "name" => "Kurdish", + 'code' => 'ku', + 'name' => 'Kurdish', ], [ - "code" => "lt", - "name" => "Lithuanian", + 'code' => 'lt', + 'name' => 'Lithuanian', ], [ - "code" => "lv", - "name" => "Latvian", + 'code' => 'lv', + 'name' => 'Latvian', ], [ - "code" => "mk", - "name" => "Macedonian (FYROM)", + 'code' => 'mk', + 'name' => 'Macedonian (FYROM)', ], [ - "code" => "ml", - "name" => "Malayalam", + 'code' => 'ml', + 'name' => 'Malayalam', ], [ - "code" => "ms", - "name" => "Malaysian", + 'code' => 'ms', + 'name' => 'Malaysian', ], [ - "code" => "mt", - "name" => "Maltese", + 'code' => 'mt', + 'name' => 'Maltese', ], [ - "code" => "nb", - "name" => "Norwegian (Bokmål)", + 'code' => 'nb', + 'name' => 'Norwegian (Bokmål)', ], [ - "code" => "ne", - "name" => "Nepali", + 'code' => 'ne', + 'name' => 'Nepali', ], [ - "code" => "nl", - "name" => "Dutch (Standard)", + 'code' => 'nl', + 'name' => 'Dutch (Standard)', ], [ - "code" => "nl-be", - "name" => "Dutch (Belgium)", + 'code' => 'nl-be', + 'name' => 'Dutch (Belgium)', ], [ - "code" => "nn", - "name" => "Norwegian (Nynorsk)", + 'code' => 'nn', + 'name' => 'Norwegian (Nynorsk)', ], [ - "code" => "no", - "name" => "Norwegian", + 'code' => 'no', + 'name' => 'Norwegian', ], [ - "code" => "pa", - "name" => "Punjabi", + 'code' => 'pa', + 'name' => 'Punjabi', ], [ - "code" => "pl", - "name" => "Polish", + 'code' => 'pl', + 'name' => 'Polish', ], [ - "code" => "pt", - "name" => "Portuguese (Portugal)", + 'code' => 'pt', + 'name' => 'Portuguese (Portugal)', ], [ - "code" => "pt-br", - "name" => "Portuguese (Brazil)", + 'code' => 'pt-br', + 'name' => 'Portuguese (Brazil)', ], [ - "code" => "rm", - "name" => "Rhaeto-Romanic", + 'code' => 'rm', + 'name' => 'Rhaeto-Romanic', ], [ - "code" => "ro", - "name" => "Romanian", + 'code' => 'ro', + 'name' => 'Romanian', ], [ - "code" => "ro-md", - "name" => "Romanian (Republic of Moldova)", + 'code' => 'ro-md', + 'name' => 'Romanian (Republic of Moldova)', ], [ - "code" => "ru", - "name" => "Russian", + 'code' => 'ru', + 'name' => 'Russian', ], [ - "code" => "ru-md", - "name" => "Russian (Republic of Moldova)", + 'code' => 'ru-md', + 'name' => 'Russian (Republic of Moldova)', ], [ - "code" => "sb", - "name" => "Sorbian", + 'code' => 'sb', + 'name' => 'Sorbian', ], [ - "code" => "sk", - "name" => "Slovak", + 'code' => 'sk', + 'name' => 'Slovak', ], [ - "code" => "sl", - "name" => "Slovenian", + 'code' => 'sl', + 'name' => 'Slovenian', ], [ - "code" => "sq", - "name" => "Albanian", + 'code' => 'sq', + 'name' => 'Albanian', ], [ - "code" => "sr", - "name" => "Serbian", + 'code' => 'sr', + 'name' => 'Serbian', ], [ - "code" => "sv", - "name" => "Swedish", + 'code' => 'sv', + 'name' => 'Swedish', ], [ - "code" => "sv-fi", - "name" => "Swedish (Finland)", + 'code' => 'sv-fi', + 'name' => 'Swedish (Finland)', ], [ - "code" => "th", - "name" => "Thai", + 'code' => 'th', + 'name' => 'Thai', ], [ - "code" => "tn", - "name" => "Tswana", + 'code' => 'tn', + 'name' => 'Tswana', ], [ - "code" => "tr", - "name" => "Turkish", + 'code' => 'tr', + 'name' => 'Turkish', ], [ - "code" => "ts", - "name" => "Tsonga", + 'code' => 'ts', + 'name' => 'Tsonga', ], [ - "code" => "ua", - "name" => "Ukrainian", + 'code' => 'ua', + 'name' => 'Ukrainian', ], [ - "code" => "ur", - "name" => "Urdu", + 'code' => 'ur', + 'name' => 'Urdu', ], [ - "code" => "ve", - "name" => "Venda", + 'code' => 've', + 'name' => 'Venda', ], [ - "code" => "vi", - "name" => "Vietnamese", + 'code' => 'vi', + 'name' => 'Vietnamese', ], [ - "code" => "xh", - "name" => "Xhosa", + 'code' => 'xh', + 'name' => 'Xhosa', ], [ - "code" => "zh-cn", - "name" => "Chinese (PRC)", + 'code' => 'zh-cn', + 'name' => 'Chinese (PRC)', ], [ - "code" => "zh-hk", - "name" => "Chinese (Hong Kong)", + 'code' => 'zh-hk', + 'name' => 'Chinese (Hong Kong)', ], [ - "code" => "zh-sg", - "name" => "Chinese (Singapore)", + 'code' => 'zh-sg', + 'name' => 'Chinese (Singapore)', ], [ - "code" => "zh-tw", - "name" => "Chinese (Taiwan)", + 'code' => 'zh-tw', + 'name' => 'Chinese (Taiwan)', ], [ - "code" => "zu", - "name" => "Zulu", + 'code' => 'zu', + 'name' => 'Zulu', ], ]; diff --git a/app/config/locale/languages.php b/app/config/locale/languages.php index 6272bd02a6..318ec27492 100644 --- a/app/config/locale/languages.php +++ b/app/config/locale/languages.php @@ -9,923 +9,923 @@ return [ [ - "code" => "aa", - "name" => "Afar", - "nativeName" => "Afar" + 'code' => 'aa', + 'name' => 'Afar', + 'nativeName' => 'Afar', ], [ - "code" => "ab", - "name" => "Abkhazian", - "nativeName" => "Аҧсуа" + 'code' => 'ab', + 'name' => 'Abkhazian', + 'nativeName' => 'Аҧсуа', ], [ - "code" => "af", - "name" => "Afrikaans", - "nativeName" => "Afrikaans" + 'code' => 'af', + 'name' => 'Afrikaans', + 'nativeName' => 'Afrikaans', ], [ - "code" => "ak", - "name" => "Akan", - "nativeName" => "Akana" + 'code' => 'ak', + 'name' => 'Akan', + 'nativeName' => 'Akana', ], [ - "code" => "am", - "name" => "Amharic", - "nativeName" => "አማርኛ" + 'code' => 'am', + 'name' => 'Amharic', + 'nativeName' => 'አማርኛ', ], [ - "code" => "an", - "name" => "Aragonese", - "nativeName" => "Aragonés" + 'code' => 'an', + 'name' => 'Aragonese', + 'nativeName' => 'Aragonés', ], [ - "code" => "ar", - "name" => "Arabic", - "nativeName" => "العربية" + 'code' => 'ar', + 'name' => 'Arabic', + 'nativeName' => 'العربية', ], [ - "code" => "as", - "name" => "Assamese", - "nativeName" => "অসমীয়া" + 'code' => 'as', + 'name' => 'Assamese', + 'nativeName' => 'অসমীয়া', ], [ - "code" => "av", - "name" => "Avar", - "nativeName" => "Авар" + 'code' => 'av', + 'name' => 'Avar', + 'nativeName' => 'Авар', ], [ - "code" => "ay", - "name" => "Aymara", - "nativeName" => "Aymar" + 'code' => 'ay', + 'name' => 'Aymara', + 'nativeName' => 'Aymar', ], [ - "code" => "az", - "name" => "Azerbaijani", - "nativeName" => "Azərbaycanca / آذربايجان" + 'code' => 'az', + 'name' => 'Azerbaijani', + 'nativeName' => 'Azərbaycanca / آذربايجان', ], [ - "code" => "ba", - "name" => "Bashkir", - "nativeName" => "Башҡорт" + 'code' => 'ba', + 'name' => 'Bashkir', + 'nativeName' => 'Башҡорт', ], [ - "code" => "be", - "name" => "Belarusian", - "nativeName" => "Беларуская" + 'code' => 'be', + 'name' => 'Belarusian', + 'nativeName' => 'Беларуская', ], [ - "code" => "bg", - "name" => "Bulgarian", - "nativeName" => "Български" + 'code' => 'bg', + 'name' => 'Bulgarian', + 'nativeName' => 'Български', ], [ - "code" => "bh", - "name" => "Bihari", - "nativeName" => "भोजपुरी" + 'code' => 'bh', + 'name' => 'Bihari', + 'nativeName' => 'भोजपुरी', ], [ - "code" => "bi", - "name" => "Bislama", - "nativeName" => "Bislama" + 'code' => 'bi', + 'name' => 'Bislama', + 'nativeName' => 'Bislama', ], [ - "code" => "bm", - "name" => "Bambara", - "nativeName" => "Bamanankan" + 'code' => 'bm', + 'name' => 'Bambara', + 'nativeName' => 'Bamanankan', ], [ - "code" => "bn", - "name" => "Bengali", - "nativeName" => "বাংলা" + 'code' => 'bn', + 'name' => 'Bengali', + 'nativeName' => 'বাংলা', ], [ - "code" => "bo", - "name" => "Tibetan", - "nativeName" => "བོད་ཡིག / Bod skad" + 'code' => 'bo', + 'name' => 'Tibetan', + 'nativeName' => 'བོད་ཡིག / Bod skad', ], [ - "code" => "br", - "name" => "Breton", - "nativeName" => "Brezhoneg" + 'code' => 'br', + 'name' => 'Breton', + 'nativeName' => 'Brezhoneg', ], [ - "code" => "bs", - "name" => "Bosnian", - "nativeName" => "Bosanski" + 'code' => 'bs', + 'name' => 'Bosnian', + 'nativeName' => 'Bosanski', ], [ - "code" => "ca", - "name" => "Catalan", - "nativeName" => "Català" + 'code' => 'ca', + 'name' => 'Catalan', + 'nativeName' => 'Català', ], [ - "code" => "ce", - "name" => "Chechen", - "nativeName" => "Нохчийн" + 'code' => 'ce', + 'name' => 'Chechen', + 'nativeName' => 'Нохчийн', ], [ - "code" => "ch", - "name" => "Chamorro", - "nativeName" => "Chamoru" + 'code' => 'ch', + 'name' => 'Chamorro', + 'nativeName' => 'Chamoru', ], [ - "code" => "co", - "name" => "Corsican", - "nativeName" => "Corsu" + 'code' => 'co', + 'name' => 'Corsican', + 'nativeName' => 'Corsu', ], [ - "code" => "cr", - "name" => "Cree", - "nativeName" => "Nehiyaw" + 'code' => 'cr', + 'name' => 'Cree', + 'nativeName' => 'Nehiyaw', ], [ - "code" => "cs", - "name" => "Czech", - "nativeName" => "Česky" + 'code' => 'cs', + 'name' => 'Czech', + 'nativeName' => 'Česky', ], [ - "code" => "cu", - "name" => "Old Church Slavonic / Old Bulgarian", - "nativeName" => "словѣньскъ / slověnĭskŭ" + 'code' => 'cu', + 'name' => 'Old Church Slavonic / Old Bulgarian', + 'nativeName' => 'словѣньскъ / slověnĭskŭ', ], [ - "code" => "cv", - "name" => "Chuvash", - "nativeName" => "Чăваш" + 'code' => 'cv', + 'name' => 'Chuvash', + 'nativeName' => 'Чăваш', ], [ - "code" => "cy", - "name" => "Welsh", - "nativeName" => "Cymraeg" + 'code' => 'cy', + 'name' => 'Welsh', + 'nativeName' => 'Cymraeg', ], [ - "code" => "da", - "name" => "Danish", - "nativeName" => "Dansk" + 'code' => 'da', + 'name' => 'Danish', + 'nativeName' => 'Dansk', ], [ - "code" => "de", - "name" => "German", - "nativeName" => "Deutsch" + 'code' => 'de', + 'name' => 'German', + 'nativeName' => 'Deutsch', ], [ - "code" => "dv", - "name" => "Divehi", - "nativeName" => "ދިވެހިބަސް" + 'code' => 'dv', + 'name' => 'Divehi', + 'nativeName' => 'ދިވެހިބަސް', ], [ - "code" => "dz", - "name" => "Dzongkha", - "nativeName" => "ཇོང་ཁ" + 'code' => 'dz', + 'name' => 'Dzongkha', + 'nativeName' => 'ཇོང་ཁ', ], [ - "code" => "ee", - "name" => "Ewe", - "nativeName" => "Ɛʋɛ" + 'code' => 'ee', + 'name' => 'Ewe', + 'nativeName' => 'Ɛʋɛ', ], [ - "code" => "el", - "name" => "Greek", - "nativeName" => "Ελληνικά" + 'code' => 'el', + 'name' => 'Greek', + 'nativeName' => 'Ελληνικά', ], [ - "code" => "en", - "name" => "English", - "nativeName" => "English" + 'code' => 'en', + 'name' => 'English', + 'nativeName' => 'English', ], [ - "code" => "eo", - "name" => "Esperanto", - "nativeName" => "Esperanto" + 'code' => 'eo', + 'name' => 'Esperanto', + 'nativeName' => 'Esperanto', ], [ - "code" => "es", - "name" => "Spanish", - "nativeName" => "Español" + 'code' => 'es', + 'name' => 'Spanish', + 'nativeName' => 'Español', ], [ - "code" => "et", - "name" => "Estonian", - "nativeName" => "Eesti" + 'code' => 'et', + 'name' => 'Estonian', + 'nativeName' => 'Eesti', ], [ - "code" => "eu", - "name" => "Basque", - "nativeName" => "Euskara" + 'code' => 'eu', + 'name' => 'Basque', + 'nativeName' => 'Euskara', ], [ - "code" => "fa", - "name" => "Persian", - "nativeName" => "فارسی" + 'code' => 'fa', + 'name' => 'Persian', + 'nativeName' => 'فارسی', ], [ - "code" => "ff", - "name" => "Peul", - "nativeName" => "Fulfulde" + 'code' => 'ff', + 'name' => 'Peul', + 'nativeName' => 'Fulfulde', ], [ - "code" => "fi", - "name" => "Finnish", - "nativeName" => "Suomi" + 'code' => 'fi', + 'name' => 'Finnish', + 'nativeName' => 'Suomi', ], [ - "code" => "fj", - "name" => "Fijian", - "nativeName" => "Na Vosa Vakaviti" + 'code' => 'fj', + 'name' => 'Fijian', + 'nativeName' => 'Na Vosa Vakaviti', ], [ - "code" => "fo", - "name" => "Faroese", - "nativeName" => "Føroyskt" + 'code' => 'fo', + 'name' => 'Faroese', + 'nativeName' => 'Føroyskt', ], [ - "code" => "fr", - "name" => "French", - "nativeName" => "Français" + 'code' => 'fr', + 'name' => 'French', + 'nativeName' => 'Français', ], [ - "code" => "fy", - "name" => "West Frisian", - "nativeName" => "Frysk" + 'code' => 'fy', + 'name' => 'West Frisian', + 'nativeName' => 'Frysk', ], [ - "code" => "ga", - "name" => "Irish", - "nativeName" => "Gaeilge" + 'code' => 'ga', + 'name' => 'Irish', + 'nativeName' => 'Gaeilge', ], [ - "code" => "gd", - "name" => "Scottish Gaelic", - "nativeName" => "Gàidhlig" + 'code' => 'gd', + 'name' => 'Scottish Gaelic', + 'nativeName' => 'Gàidhlig', ], [ - "code" => "gl", - "name" => "Galician", - "nativeName" => "Galego" + 'code' => 'gl', + 'name' => 'Galician', + 'nativeName' => 'Galego', ], [ - "code" => "gn", - "name" => "Guarani", - "nativeName" => "Avañe'ẽ" + 'code' => 'gn', + 'name' => 'Guarani', + 'nativeName' => "Avañe'ẽ", ], [ - "code" => "gu", - "name" => "Gujarati", - "nativeName" => "ગુજરાતી" + 'code' => 'gu', + 'name' => 'Gujarati', + 'nativeName' => 'ગુજરાતી', ], [ - "code" => "gv", - "name" => "Manx", - "nativeName" => "Gaelg" + 'code' => 'gv', + 'name' => 'Manx', + 'nativeName' => 'Gaelg', ], [ - "code" => "ha", - "name" => "Hausa", - "nativeName" => "هَوُسَ" + 'code' => 'ha', + 'name' => 'Hausa', + 'nativeName' => 'هَوُسَ', ], [ - "code" => "he", - "name" => "Hebrew", - "nativeName" => "עברית" + 'code' => 'he', + 'name' => 'Hebrew', + 'nativeName' => 'עברית', ], [ - "code" => "hi", - "name" => "Hindi", - "nativeName" => "हिन्दी / हिंदी " + 'code' => 'hi', + 'name' => 'Hindi', + 'nativeName' => 'हिन्दी / हिंदी ', ], [ - "code" => "ho", - "name" => "Hiri Motu", - "nativeName" => "Hiri Motu" + 'code' => 'ho', + 'name' => 'Hiri Motu', + 'nativeName' => 'Hiri Motu', ], [ - "code" => "hr", - "name" => "Croatian", - "nativeName" => "Hrvatski" + 'code' => 'hr', + 'name' => 'Croatian', + 'nativeName' => 'Hrvatski', ], [ - "code" => "ht", - "name" => "Haitian", - "nativeName" => "Krèyol ayisyen" + 'code' => 'ht', + 'name' => 'Haitian', + 'nativeName' => 'Krèyol ayisyen', ], [ - "code" => "hu", - "name" => "Hungarian", - "nativeName" => "Magyar" + 'code' => 'hu', + 'name' => 'Hungarian', + 'nativeName' => 'Magyar', ], [ - "code" => "hy", - "name" => "Armenian", - "nativeName" => "Հայերեն" + 'code' => 'hy', + 'name' => 'Armenian', + 'nativeName' => 'Հայերեն', ], [ - "code" => "hz", - "name" => "Herero", - "nativeName" => "Otsiherero" + 'code' => 'hz', + 'name' => 'Herero', + 'nativeName' => 'Otsiherero', ], [ - "code" => "ia", - "name" => "Interlingua", - "nativeName" => "Interlingua" + 'code' => 'ia', + 'name' => 'Interlingua', + 'nativeName' => 'Interlingua', ], [ - "code" => "id", - "name" => "Indonesian", - "nativeName" => "Bahasa Indonesia" + 'code' => 'id', + 'name' => 'Indonesian', + 'nativeName' => 'Bahasa Indonesia', ], [ - "code" => "ie", - "name" => "Interlingue", - "nativeName" => "Interlingue" + 'code' => 'ie', + 'name' => 'Interlingue', + 'nativeName' => 'Interlingue', ], [ - "code" => "ig", - "name" => "Igbo", - "nativeName" => "Igbo" + 'code' => 'ig', + 'name' => 'Igbo', + 'nativeName' => 'Igbo', ], [ - "code" => "ii", - "name" => "Sichuan Yi", - "nativeName" => "ꆇꉙ / 四川彝语" + 'code' => 'ii', + 'name' => 'Sichuan Yi', + 'nativeName' => 'ꆇꉙ / 四川彝语', ], [ - "code" => "ik", - "name" => "Inupiak", - "nativeName" => "Iñupiak" + 'code' => 'ik', + 'name' => 'Inupiak', + 'nativeName' => 'Iñupiak', ], [ - "code" => "io", - "name" => "Ido", - "nativeName" => "Ido" + 'code' => 'io', + 'name' => 'Ido', + 'nativeName' => 'Ido', ], [ - "code" => "is", - "name" => "Icelandic", - "nativeName" => "Íslenska" + 'code' => 'is', + 'name' => 'Icelandic', + 'nativeName' => 'Íslenska', ], [ - "code" => "it", - "name" => "Italian", - "nativeName" => "Italiano" + 'code' => 'it', + 'name' => 'Italian', + 'nativeName' => 'Italiano', ], [ - "code" => "iu", - "name" => "Inuktitut", - "nativeName" => "ᐃᓄᒃᑎᑐᑦ" + 'code' => 'iu', + 'name' => 'Inuktitut', + 'nativeName' => 'ᐃᓄᒃᑎᑐᑦ', ], [ - "code" => "ja", - "name" => "Japanese", - "nativeName" => "日本語" + 'code' => 'ja', + 'name' => 'Japanese', + 'nativeName' => '日本語', ], [ - "code" => "jv", - "name" => "Javanese", - "nativeName" => "Basa Jawa" + 'code' => 'jv', + 'name' => 'Javanese', + 'nativeName' => 'Basa Jawa', ], [ - "code" => "ka", - "name" => "Georgian", - "nativeName" => "ქართული" + 'code' => 'ka', + 'name' => 'Georgian', + 'nativeName' => 'ქართული', ], [ - "code" => "kg", - "name" => "Kongo", - "nativeName" => "KiKongo" + 'code' => 'kg', + 'name' => 'Kongo', + 'nativeName' => 'KiKongo', ], [ - "code" => "ki", - "name" => "Kikuyu", - "nativeName" => "Gĩkũyũ" + 'code' => 'ki', + 'name' => 'Kikuyu', + 'nativeName' => 'Gĩkũyũ', ], [ - "code" => "kj", - "name" => "Kuanyama", - "nativeName" => "Kuanyama" + 'code' => 'kj', + 'name' => 'Kuanyama', + 'nativeName' => 'Kuanyama', ], [ - "code" => "kk", - "name" => "Kazakh", - "nativeName" => "Қазақша" + 'code' => 'kk', + 'name' => 'Kazakh', + 'nativeName' => 'Қазақша', ], [ - "code" => "kl", - "name" => "Greenlandic", - "nativeName" => "Kalaallisut" + 'code' => 'kl', + 'name' => 'Greenlandic', + 'nativeName' => 'Kalaallisut', ], [ - "code" => "km", - "name" => "Khmer", - "nativeName" => "ភាសាខ្មែរ" + 'code' => 'km', + 'name' => 'Khmer', + 'nativeName' => 'ភាសាខ្មែរ', ], [ - "code" => "kn", - "name" => "Kannada", - "nativeName" => "ಕನ್ನಡ" + 'code' => 'kn', + 'name' => 'Kannada', + 'nativeName' => 'ಕನ್ನಡ', ], [ - "code" => "ko", - "name" => "Korean", - "nativeName" => "한국어" + 'code' => 'ko', + 'name' => 'Korean', + 'nativeName' => '한국어', ], [ - "code" => "kr", - "name" => "Kanuri", - "nativeName" => "Kanuri" + 'code' => 'kr', + 'name' => 'Kanuri', + 'nativeName' => 'Kanuri', ], [ - "code" => "ks", - "name" => "Kashmiri", - "nativeName" => "कश्मीरी / كشميري" + 'code' => 'ks', + 'name' => 'Kashmiri', + 'nativeName' => 'कश्मीरी / كشميري', ], [ - "code" => "ku", - "name" => "Kurdish", - "nativeName" => "Kurdî / كوردی" + 'code' => 'ku', + 'name' => 'Kurdish', + 'nativeName' => 'Kurdî / كوردی', ], [ - "code" => "kv", - "name" => "Komi", - "nativeName" => "Коми" + 'code' => 'kv', + 'name' => 'Komi', + 'nativeName' => 'Коми', ], [ - "code" => "kw", - "name" => "Cornish", - "nativeName" => "Kernewek" + 'code' => 'kw', + 'name' => 'Cornish', + 'nativeName' => 'Kernewek', ], [ - "code" => "ky", - "name" => "Kirghiz", - "nativeName" => "Kırgızca / Кыргызча" + 'code' => 'ky', + 'name' => 'Kirghiz', + 'nativeName' => 'Kırgızca / Кыргызча', ], [ - "code" => "la", - "name" => "Latin", - "nativeName" => "Latina" + 'code' => 'la', + 'name' => 'Latin', + 'nativeName' => 'Latina', ], [ - "code" => "lb", - "name" => "Luxembourgish", - "nativeName" => "Lëtzebuergesch" + 'code' => 'lb', + 'name' => 'Luxembourgish', + 'nativeName' => 'Lëtzebuergesch', ], [ - "code" => "lg", - "name" => "Ganda", - "nativeName" => "Luganda" + 'code' => 'lg', + 'name' => 'Ganda', + 'nativeName' => 'Luganda', ], [ - "code" => "li", - "name" => "Limburgian", - "nativeName" => "Limburgs" + 'code' => 'li', + 'name' => 'Limburgian', + 'nativeName' => 'Limburgs', ], [ - "code" => "ln", - "name" => "Lingala", - "nativeName" => "Lingála" + 'code' => 'ln', + 'name' => 'Lingala', + 'nativeName' => 'Lingála', ], [ - "code" => "lo", - "name" => "Laotian", - "nativeName" => "ລາວ / Pha xa lao" + 'code' => 'lo', + 'name' => 'Laotian', + 'nativeName' => 'ລາວ / Pha xa lao', ], [ - "code" => "lt", - "name" => "Lithuanian", - "nativeName" => "Lietuvių" + 'code' => 'lt', + 'name' => 'Lithuanian', + 'nativeName' => 'Lietuvių', ], [ - "code" => "lu", - "name" => "Luba-Katanga", - "nativeName" => "Tshiluba" + 'code' => 'lu', + 'name' => 'Luba-Katanga', + 'nativeName' => 'Tshiluba', ], [ - "code" => "lv", - "name" => "Latvian", - "nativeName" => "Latviešu" + 'code' => 'lv', + 'name' => 'Latvian', + 'nativeName' => 'Latviešu', ], [ - "code" => "mg", - "name" => "Malagasy", - "nativeName" => "Malagasy" + 'code' => 'mg', + 'name' => 'Malagasy', + 'nativeName' => 'Malagasy', ], [ - "code" => "mh", - "name" => "Marshallese", - "nativeName" => "Kajin Majel / Ebon" + 'code' => 'mh', + 'name' => 'Marshallese', + 'nativeName' => 'Kajin Majel / Ebon', ], [ - "code" => "mi", - "name" => "Maori", - "nativeName" => "Māori" + 'code' => 'mi', + 'name' => 'Maori', + 'nativeName' => 'Māori', ], [ - "code" => "mk", - "name" => "Macedonian", - "nativeName" => "Македонски" + 'code' => 'mk', + 'name' => 'Macedonian', + 'nativeName' => 'Македонски', ], [ - "code" => "ml", - "name" => "Malayalam", - "nativeName" => "മലയാളം" + 'code' => 'ml', + 'name' => 'Malayalam', + 'nativeName' => 'മലയാളം', ], [ - "code" => "mn", - "name" => "Mongolian", - "nativeName" => "Монгол" + 'code' => 'mn', + 'name' => 'Mongolian', + 'nativeName' => 'Монгол', ], [ - "code" => "mo", - "name" => "Moldovan", - "nativeName" => "Moldovenească" + 'code' => 'mo', + 'name' => 'Moldovan', + 'nativeName' => 'Moldovenească', ], [ - "code" => "mr", - "name" => "Marathi", - "nativeName" => "मराठी" + 'code' => 'mr', + 'name' => 'Marathi', + 'nativeName' => 'मराठी', ], [ - "code" => "ms", - "name" => "Malay", - "nativeName" => "Bahasa Melayu" + 'code' => 'ms', + 'name' => 'Malay', + 'nativeName' => 'Bahasa Melayu', ], [ - "code" => "mt", - "name" => "Maltese", - "nativeName" => "bil-Malti" + 'code' => 'mt', + 'name' => 'Maltese', + 'nativeName' => 'bil-Malti', ], [ - "code" => "my", - "name" => "Burmese", - "nativeName" => "မြန်မာစာ" + 'code' => 'my', + 'name' => 'Burmese', + 'nativeName' => 'မြန်မာစာ', ], [ - "code" => "na", - "name" => "Nauruan", - "nativeName" => "Dorerin Naoero" + 'code' => 'na', + 'name' => 'Nauruan', + 'nativeName' => 'Dorerin Naoero', ], [ - "code" => "nb", - "name" => "Norwegian Bokmål", - "nativeName" => "Norsk bokmål" + 'code' => 'nb', + 'name' => 'Norwegian Bokmål', + 'nativeName' => 'Norsk bokmål', ], [ - "code" => "nd", - "name" => "North Ndebele", - "nativeName" => "Sindebele" + 'code' => 'nd', + 'name' => 'North Ndebele', + 'nativeName' => 'Sindebele', ], [ - "code" => "ne", - "name" => "Nepali", - "nativeName" => "नेपाली" + 'code' => 'ne', + 'name' => 'Nepali', + 'nativeName' => 'नेपाली', ], [ - "code" => "ng", - "name" => "Ndonga", - "nativeName" => "Oshiwambo" + 'code' => 'ng', + 'name' => 'Ndonga', + 'nativeName' => 'Oshiwambo', ], [ - "code" => "nl", - "name" => "Dutch", - "nativeName" => "Nederlands" + 'code' => 'nl', + 'name' => 'Dutch', + 'nativeName' => 'Nederlands', ], [ - "code" => "nn", - "name" => "Norwegian Nynorsk", - "nativeName" => "Norsk nynorsk" + 'code' => 'nn', + 'name' => 'Norwegian Nynorsk', + 'nativeName' => 'Norsk nynorsk', ], [ - "code" => "nr", - "name" => "South Ndebele", - "nativeName" => "isiNdebele" + 'code' => 'nr', + 'name' => 'South Ndebele', + 'nativeName' => 'isiNdebele', ], [ - "code" => "nv", - "name" => "Navajo", - "nativeName" => "Diné bizaad" + 'code' => 'nv', + 'name' => 'Navajo', + 'nativeName' => 'Diné bizaad', ], [ - "code" => "ny", - "name" => "Chichewa", - "nativeName" => "Chi-Chewa" + 'code' => 'ny', + 'name' => 'Chichewa', + 'nativeName' => 'Chi-Chewa', ], [ - "code" => "oc", - "name" => "Occitan", - "nativeName" => "Occitan" + 'code' => 'oc', + 'name' => 'Occitan', + 'nativeName' => 'Occitan', ], [ - "code" => "oj", - "name" => "Ojibwa", - "nativeName" => "ᐊᓂᔑᓈᐯᒧᐎᓐ / Anishinaabemowin" + 'code' => 'oj', + 'name' => 'Ojibwa', + 'nativeName' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ / Anishinaabemowin', ], [ - "code" => "om", - "name" => "Oromo", - "nativeName" => "Oromoo" + 'code' => 'om', + 'name' => 'Oromo', + 'nativeName' => 'Oromoo', ], [ - "code" => "or", - "name" => "Oriya", - "nativeName" => "ଓଡ଼ିଆ" + 'code' => 'or', + 'name' => 'Oriya', + 'nativeName' => 'ଓଡ଼ିଆ', ], [ - "code" => "os", - "name" => "Ossetian / Ossetic", - "nativeName" => "Иронау" + 'code' => 'os', + 'name' => 'Ossetian / Ossetic', + 'nativeName' => 'Иронау', ], [ - "code" => "pa", - "name" => "Panjabi / Punjabi", - "nativeName" => "ਪੰਜਾਬੀ / पंजाबी / پنجابي" + 'code' => 'pa', + 'name' => 'Panjabi / Punjabi', + 'nativeName' => 'ਪੰਜਾਬੀ / पंजाबी / پنجابي', ], [ - "code" => "pi", - "name" => "Pali", - "nativeName" => "Pāli / पाऴि" + 'code' => 'pi', + 'name' => 'Pali', + 'nativeName' => 'Pāli / पाऴि', ], [ - "code" => "pl", - "name" => "Polish", - "nativeName" => "Polski" + 'code' => 'pl', + 'name' => 'Polish', + 'nativeName' => 'Polski', ], [ - "code" => "ps", - "name" => "Pashto", - "nativeName" => "پښتو" + 'code' => 'ps', + 'name' => 'Pashto', + 'nativeName' => 'پښتو', ], [ - "code" => "pt", - "name" => "Portuguese", - "nativeName" => "Português" + 'code' => 'pt', + 'name' => 'Portuguese', + 'nativeName' => 'Português', ], [ - "code" => "qu", - "name" => "Quechua", - "nativeName" => "Runa Simi" + 'code' => 'qu', + 'name' => 'Quechua', + 'nativeName' => 'Runa Simi', ], [ - "code" => "rm", - "name" => "Raeto Romance", - "nativeName" => "Rumantsch" + 'code' => 'rm', + 'name' => 'Raeto Romance', + 'nativeName' => 'Rumantsch', ], [ - "code" => "rn", - "name" => "Kirundi", - "nativeName" => "Kirundi" + 'code' => 'rn', + 'name' => 'Kirundi', + 'nativeName' => 'Kirundi', ], [ - "code" => "ro", - "name" => "Romanian", - "nativeName" => "Română" + 'code' => 'ro', + 'name' => 'Romanian', + 'nativeName' => 'Română', ], [ - "code" => "ru", - "name" => "Russian", - "nativeName" => "Русский" + 'code' => 'ru', + 'name' => 'Russian', + 'nativeName' => 'Русский', ], [ - "code" => "rw", - "name" => "Rwandi", - "nativeName" => "Kinyarwandi" + 'code' => 'rw', + 'name' => 'Rwandi', + 'nativeName' => 'Kinyarwandi', ], [ - "code" => "sa", - "name" => "Sanskrit", - "nativeName" => "संस्कृतम्" + 'code' => 'sa', + 'name' => 'Sanskrit', + 'nativeName' => 'संस्कृतम्', ], [ - "code" => "sc", - "name" => "Sardinian", - "nativeName" => "Sardu" + 'code' => 'sc', + 'name' => 'Sardinian', + 'nativeName' => 'Sardu', ], [ - "code" => "sd", - "name" => "Sindhi", - "nativeName" => "सिन्धी / सिंधी " + 'code' => 'sd', + 'name' => 'Sindhi', + 'nativeName' => 'सिन्धी / सिंधी ', ], [ - "code" => "se", - "name" => "Northern Sami", - "nativeName" => "Sámegiella" + 'code' => 'se', + 'name' => 'Northern Sami', + 'nativeName' => 'Sámegiella', ], [ - "code" => "sg", - "name" => "Sango", - "nativeName" => "Sängö" + 'code' => 'sg', + 'name' => 'Sango', + 'nativeName' => 'Sängö', ], [ - "code" => "sh", - "name" => "Serbo-Croatian", - "nativeName" => "Srpskohrvatski / Српскохрватски" + 'code' => 'sh', + 'name' => 'Serbo-Croatian', + 'nativeName' => 'Srpskohrvatski / Српскохрватски', ], [ - "code" => "si", - "name" => "Sinhalese", - "nativeName" => "සිංහල" + 'code' => 'si', + 'name' => 'Sinhalese', + 'nativeName' => 'සිංහල', ], [ - "code" => "sk", - "name" => "Slovak", - "nativeName" => "Slovenčina" + 'code' => 'sk', + 'name' => 'Slovak', + 'nativeName' => 'Slovenčina', ], [ - "code" => "sl", - "name" => "Slovenian", - "nativeName" => "Slovenščina" + 'code' => 'sl', + 'name' => 'Slovenian', + 'nativeName' => 'Slovenščina', ], [ - "code" => "sm", - "name" => "Samoan", - "nativeName" => "Gagana Samoa" + 'code' => 'sm', + 'name' => 'Samoan', + 'nativeName' => 'Gagana Samoa', ], [ - "code" => "sn", - "name" => "Shona", - "nativeName" => "chiShona" + 'code' => 'sn', + 'name' => 'Shona', + 'nativeName' => 'chiShona', ], [ - "code" => "so", - "name" => "Somalia", - "nativeName" => "Soomaaliga" + 'code' => 'so', + 'name' => 'Somalia', + 'nativeName' => 'Soomaaliga', ], [ - "code" => "sq", - "name" => "Albanian", - "nativeName" => "Shqip" + 'code' => 'sq', + 'name' => 'Albanian', + 'nativeName' => 'Shqip', ], [ - "code" => "sr", - "name" => "Serbian", - "nativeName" => "Српски" + 'code' => 'sr', + 'name' => 'Serbian', + 'nativeName' => 'Српски', ], [ - "code" => "ss", - "name" => "Swati", - "nativeName" => "SiSwati" + 'code' => 'ss', + 'name' => 'Swati', + 'nativeName' => 'SiSwati', ], [ - "code" => "st", - "name" => "Southern Sotho", - "nativeName" => "Sesotho" + 'code' => 'st', + 'name' => 'Southern Sotho', + 'nativeName' => 'Sesotho', ], [ - "code" => "su", - "name" => "Sundanese", - "nativeName" => "Basa Sunda" + 'code' => 'su', + 'name' => 'Sundanese', + 'nativeName' => 'Basa Sunda', ], [ - "code" => "sv", - "name" => "Swedish", - "nativeName" => "Svenska" + 'code' => 'sv', + 'name' => 'Swedish', + 'nativeName' => 'Svenska', ], [ - "code" => "sw", - "name" => "Swahili", - "nativeName" => "Kiswahili" + 'code' => 'sw', + 'name' => 'Swahili', + 'nativeName' => 'Kiswahili', ], [ - "code" => "ta", - "name" => "Tamil", - "nativeName" => "தமிழ்" + 'code' => 'ta', + 'name' => 'Tamil', + 'nativeName' => 'தமிழ்', ], [ - "code" => "te", - "name" => "Telugu", - "nativeName" => "తెలుగు" + 'code' => 'te', + 'name' => 'Telugu', + 'nativeName' => 'తెలుగు', ], [ - "code" => "tg", - "name" => "Tajik", - "nativeName" => "Тоҷикӣ" + 'code' => 'tg', + 'name' => 'Tajik', + 'nativeName' => 'Тоҷикӣ', ], [ - "code" => "th", - "name" => "Thai", - "nativeName" => "ไทย / Phasa Thai" + 'code' => 'th', + 'name' => 'Thai', + 'nativeName' => 'ไทย / Phasa Thai', ], [ - "code" => "ti", - "name" => "Tigrinya", - "nativeName" => "ትግርኛ" + 'code' => 'ti', + 'name' => 'Tigrinya', + 'nativeName' => 'ትግርኛ', ], [ - "code" => "tk", - "name" => "Turkmen", - "nativeName" => "Туркмен / تركمن" + 'code' => 'tk', + 'name' => 'Turkmen', + 'nativeName' => 'Туркмен / تركمن', ], [ - "code" => "tl", - "name" => "Tagalog / Filipino", - "nativeName" => "Tagalog" + 'code' => 'tl', + 'name' => 'Tagalog / Filipino', + 'nativeName' => 'Tagalog', ], [ - "code" => "tn", - "name" => "Tswana", - "nativeName" => "Setswana" + 'code' => 'tn', + 'name' => 'Tswana', + 'nativeName' => 'Setswana', ], [ - "code" => "to", - "name" => "Tonga", - "nativeName" => "Lea Faka-Tonga" + 'code' => 'to', + 'name' => 'Tonga', + 'nativeName' => 'Lea Faka-Tonga', ], [ - "code" => "tr", - "name" => "Turkish", - "nativeName" => "Türkçe" + 'code' => 'tr', + 'name' => 'Turkish', + 'nativeName' => 'Türkçe', ], [ - "code" => "ts", - "name" => "Tsonga", - "nativeName" => "Xitsonga" + 'code' => 'ts', + 'name' => 'Tsonga', + 'nativeName' => 'Xitsonga', ], [ - "code" => "tt", - "name" => "Tatar", - "nativeName" => "Tatarça" + 'code' => 'tt', + 'name' => 'Tatar', + 'nativeName' => 'Tatarça', ], [ - "code" => "tw", - "name" => "Twi", - "nativeName" => "Twi" + 'code' => 'tw', + 'name' => 'Twi', + 'nativeName' => 'Twi', ], [ - "code" => "ty", - "name" => "Tahitian", - "nativeName" => "Reo Mā`ohi" + 'code' => 'ty', + 'name' => 'Tahitian', + 'nativeName' => 'Reo Mā`ohi', ], [ - "code" => "ug", - "name" => "Uyghur", - "nativeName" => "Uyƣurqə / ئۇيغۇرچە" + 'code' => 'ug', + 'name' => 'Uyghur', + 'nativeName' => 'Uyƣurqə / ئۇيغۇرچە', ], [ - "code" => "uk", - "name" => "Ukrainian", - "nativeName" => "Українська" + 'code' => 'uk', + 'name' => 'Ukrainian', + 'nativeName' => 'Українська', ], [ - "code" => "ur", - "name" => "Urdu", - "nativeName" => "اردو" + 'code' => 'ur', + 'name' => 'Urdu', + 'nativeName' => 'اردو', ], [ - "code" => "uz", - "name" => "Uzbek", - "nativeName" => "Ўзбек" + 'code' => 'uz', + 'name' => 'Uzbek', + 'nativeName' => 'Ўзбек', ], [ - "code" => "ve", - "name" => "Venda", - "nativeName" => "Tshivenḓa" + 'code' => 've', + 'name' => 'Venda', + 'nativeName' => 'Tshivenḓa', ], [ - "code" => "vi", - "name" => "Vietnamese", - "nativeName" => "Tiếng Việt" + 'code' => 'vi', + 'name' => 'Vietnamese', + 'nativeName' => 'Tiếng Việt', ], [ - "code" => "vo", - "name" => "Volapük", - "nativeName" => "Volapük" + 'code' => 'vo', + 'name' => 'Volapük', + 'nativeName' => 'Volapük', ], [ - "code" => "wa", - "name" => "Walloon", - "nativeName" => "Walon" + 'code' => 'wa', + 'name' => 'Walloon', + 'nativeName' => 'Walon', ], [ - "code" => "wo", - "name" => "Wolof", - "nativeName" => "Wollof" + 'code' => 'wo', + 'name' => 'Wolof', + 'nativeName' => 'Wollof', ], [ - "code" => "xh", - "name" => "Xhosa", - "nativeName" => "isiXhosa" + 'code' => 'xh', + 'name' => 'Xhosa', + 'nativeName' => 'isiXhosa', ], [ - "code" => "yi", - "name" => "Yiddish", - "nativeName" => "ייִדיש" + 'code' => 'yi', + 'name' => 'Yiddish', + 'nativeName' => 'ייִדיש', ], [ - "code" => "yo", - "name" => "Yoruba", - "nativeName" => "Yorùbá" + 'code' => 'yo', + 'name' => 'Yoruba', + 'nativeName' => 'Yorùbá', ], [ - "code" => "za", - "name" => "Zhuang", - "nativeName" => "Cuengh / Tôô / 壮语" + 'code' => 'za', + 'name' => 'Zhuang', + 'nativeName' => 'Cuengh / Tôô / 壮语', ], [ - "code" => "zh", - "name" => "Chinese", - "nativeName" => "中文" + 'code' => 'zh', + 'name' => 'Chinese', + 'nativeName' => '中文', ], [ - "code" => "zu", - "name" => "Zulu", - "nativeName" => "isiZulu" - ] + 'code' => 'zu', + 'name' => 'Zulu', + 'nativeName' => 'isiZulu', + ], ]; diff --git a/app/config/locale/templates.php b/app/config/locale/templates.php index f2672c04a0..9c365813a7 100644 --- a/app/config/locale/templates.php +++ b/app/config/locale/templates.php @@ -10,6 +10,6 @@ return [ 'sms' => [ 'verification', 'login', - 'invitation' - ] + 'invitation', + ], ]; diff --git a/app/config/messagingProviders.php b/app/config/messagingProviders.php index a33665196b..1d3ba8ed60 100644 --- a/app/config/messagingProviders.php +++ b/app/config/messagingProviders.php @@ -1,300 +1,300 @@ [ - 'mailchimp' => [ - 'name' => 'Mailchimp', - 'developers' => 'https://mailchimp.com/developer/marketing/api/', - 'icon' => 'icon-mailchimp', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, + 'email' => [ + 'mailchimp' => [ + 'name' => 'Mailchimp', + 'developers' => 'https://mailchimp.com/developer/marketing/api/', + 'icon' => 'icon-mailchimp', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'mailgun' => [ + 'name' => 'Mailgun', + 'developers' => 'https://documentation.mailgun.com/', + 'icon' => 'icon-mailgun', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'mailjet' => [ + 'name' => 'Mailjet', + 'developers' => 'https://dev.mailjet.com/', + 'icon' => 'icon-mailjet', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'postmark' => [ + 'name' => 'Postmark', + 'developers' => 'https://postmarkapp.com/developer', + 'icon' => 'icon-postmark', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sendgrid' => [ + 'name' => 'Sendgrid', + 'developers' => 'https://docs.sendgrid.com/api-reference/how-to-use-the-sendgrid-v3-api/', + 'icon' => 'icon-sendgrid', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sendinblue' => [ + 'name' => 'SendinBlue', + 'developers' => 'https://developers.sendinblue.com/', + 'icon' => 'icon-sendinblue', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'mailslurp' => [ + 'name' => 'MailSlurp', + 'developers' => 'https://www.mailslurp.com/docs/', + 'icon' => 'icon-mailslurp', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'elasticemail' => [ + 'name' => 'ElasticEmail', + 'developers' => 'https://api.elasticemail.com/public/help', + 'icon' => 'icon-elasticemail', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'ses' => [ + 'name' => 'SES', + 'developers' => 'https://docs.aws.amazon.com/ses/latest/APIReference/', + 'icon' => 'icon-ses', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], ], - 'mailgun' => [ - 'name' => 'Mailgun', - 'developers' => 'https://documentation.mailgun.com/', - 'icon' => 'icon-mailgun', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, + 'sms' => [ + 'africastalking' => [ + 'name' => 'Africa\'s Talking', + 'developers' => 'https://developers.africastalking.com/', + 'icon' => 'icon-africastalking', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'clickatell' => [ + 'name' => 'Clickatell', + 'developers' => 'https://www.clickatell.com/developers/api-docs/', + 'icon' => 'icon-clickatell', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'infobip' => [ + 'name' => 'Infobip', + 'developers' => 'https://www.infobip.com/docs/', + 'icon' => 'icon-infobip', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'msg91' => [ + 'name' => 'Msg91', + 'developers' => 'https://docs.msg91.com/reference/overview', + 'icon' => 'icon-msg91', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'plivo' => [ + 'name' => 'Plivo', + 'developers' => 'https://developers.plivo.com/', + 'icon' => 'icon-plivo', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sinch' => [ + 'name' => 'Sinch', + 'developers' => 'https://developers.sinch.com/', + 'icon' => 'icon-sinch', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sms77' => [ + 'name' => 'Sms77', + 'developers' => 'https://sms77.io/docs/gateway/', + 'icon' => 'icon-sms77', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'telesign' => [ + 'name' => 'Telesign', + 'developers' => 'https://developer.telesign.com/enterprise/docs', + 'icon' => 'icon-telesign', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'textmagic' => [ + 'name' => 'TextMagic', + 'developers' => 'https://www.textmagic.com/docs/api/', + 'icon' => 'icon-twilio', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'twilio' => [ + 'name' => 'Twilio', + 'developers' => 'https://www.twilio.com/docs/sms', + 'icon' => 'icon-twilio', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'twilio-notify' => [ + 'name' => 'Twilio Notify', + 'developers' => 'https://www.twilio.com/docs/notify', + 'icon' => 'icon-twilio', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'vonage' => [ + 'name' => 'Vonage', + 'developers' => 'https://developer.nexmo.com/', + 'icon' => 'icon-vonage', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], ], - 'mailjet' => [ - 'name' => 'Mailjet', - 'developers' => 'https://dev.mailjet.com/', - 'icon' => 'icon-mailjet', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, + 'push' => [ + 'apns' => [ + 'name' => 'APNS', + 'developers' => 'https://developer.apple.com/documentation/usernotifications', + 'icon' => 'icon-apns', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'fcm' => [ + 'name' => 'FCM', + 'developers' => 'https://firebase.google.com/docs/cloud-messaging', + 'icon' => 'icon-fcm', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'one_signal' => [ + 'name' => 'OneSignal', + 'developers' => 'https://documentation.onesignal.com/docs', + 'icon' => 'icon-onesignal', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'pushbullet' => [ + 'name' => 'PushBullet', + 'developers' => 'https://docs.pushbullet.com/', + 'icon' => 'icon-pushbullet', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'pusher' => [ + 'name' => 'Pusher', + 'developers' => 'https://pusher.com/docs', + 'icon' => 'icon-pusher', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'pushwoosh' => [ + 'name' => 'Pushwoosh', + 'developers' => 'https://www.pushwoosh.com/docs/', + 'icon' => 'icon-pushwoosh', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'urban_airship' => [ + 'name' => 'Urban Airship', + 'developers' => 'https://docs.airship.com/api/', + 'icon' => 'icon-urbanairship', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'web_push' => [ + 'name' => 'WebPush', + 'developers' => 'https://developer.mozilla.org/en-US/docs/Web/API/Push_API', + 'icon' => 'icon-webpush', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], ], - 'postmark' => [ - 'name' => 'Postmark', - 'developers' => 'https://postmarkapp.com/developer', - 'icon' => 'icon-postmark', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sendgrid' => [ - 'name' => 'Sendgrid', - 'developers' => 'https://docs.sendgrid.com/api-reference/how-to-use-the-sendgrid-v3-api/', - 'icon' => 'icon-sendgrid', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sendinblue' => [ - 'name' => 'SendinBlue', - 'developers' => 'https://developers.sendinblue.com/', - 'icon' => 'icon-sendinblue', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'mailslurp' => [ - 'name' => 'MailSlurp', - 'developers' => 'https://www.mailslurp.com/docs/', - 'icon' => 'icon-mailslurp', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'elasticemail' => [ - 'name' => 'ElasticEmail', - 'developers' => 'https://api.elasticemail.com/public/help', - 'icon' => 'icon-elasticemail', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'ses' => [ - 'name' => 'SES', - 'developers' => 'https://docs.aws.amazon.com/ses/latest/APIReference/', - 'icon' => 'icon-ses', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - ], - 'sms' => [ - 'africastalking' => [ - 'name' => 'Africa\'s Talking', - 'developers' => 'https://developers.africastalking.com/', - 'icon' => 'icon-africastalking', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'clickatell' => [ - 'name' => 'Clickatell', - 'developers' => 'https://www.clickatell.com/developers/api-docs/', - 'icon' => 'icon-clickatell', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'infobip' => [ - 'name' => 'Infobip', - 'developers' => 'https://www.infobip.com/docs/', - 'icon' => 'icon-infobip', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'msg91' => [ - 'name' => 'Msg91', - 'developers' => 'https://docs.msg91.com/reference/overview', - 'icon' => 'icon-msg91', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'plivo' => [ - 'name' => 'Plivo', - 'developers' => 'https://developers.plivo.com/', - 'icon' => 'icon-plivo', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sinch' => [ - 'name' => 'Sinch', - 'developers' => 'https://developers.sinch.com/', - 'icon' => 'icon-sinch', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sms77' => [ - 'name' => 'Sms77', - 'developers' => 'https://sms77.io/docs/gateway/', - 'icon' => 'icon-sms77', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'telesign' => [ - 'name' => 'Telesign', - 'developers' => 'https://developer.telesign.com/enterprise/docs', - 'icon' => 'icon-telesign', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'textmagic' => [ - 'name' => 'TextMagic', - 'developers' => 'https://www.textmagic.com/docs/api/', - 'icon' => 'icon-twilio', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'twilio' => [ - 'name' => 'Twilio', - 'developers' => 'https://www.twilio.com/docs/sms', - 'icon' => 'icon-twilio', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'twilio-notify' => [ - 'name' => 'Twilio Notify', - 'developers' => 'https://www.twilio.com/docs/notify', - 'icon' => 'icon-twilio', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'vonage' => [ - 'name' => 'Vonage', - 'developers' => 'https://developer.nexmo.com/', - 'icon' => 'icon-vonage', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - ], - 'push' => [ - 'apns' => [ - 'name' => 'APNS', - 'developers' => 'https://developer.apple.com/documentation/usernotifications', - 'icon' => 'icon-apns', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'fcm' => [ - 'name' => 'FCM', - 'developers' => 'https://firebase.google.com/docs/cloud-messaging', - 'icon' => 'icon-fcm', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'one_signal' => [ - 'name' => 'OneSignal', - 'developers' => 'https://documentation.onesignal.com/docs', - 'icon' => 'icon-onesignal', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'pushbullet' => [ - 'name' => 'PushBullet', - 'developers' => 'https://docs.pushbullet.com/', - 'icon' => 'icon-pushbullet', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'pusher' => [ - 'name' => 'Pusher', - 'developers' => 'https://pusher.com/docs', - 'icon' => 'icon-pusher', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'pushwoosh' => [ - 'name' => 'Pushwoosh', - 'developers' => 'https://www.pushwoosh.com/docs/', - 'icon' => 'icon-pushwoosh', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'urban_airship' => [ - 'name' => 'Urban Airship', - 'developers' => 'https://docs.airship.com/api/', - 'icon' => 'icon-urbanairship', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'web_push' => [ - 'name' => 'WebPush', - 'developers' => 'https://developer.mozilla.org/en-US/docs/Web/API/Push_API', - 'icon' => 'icon-webpush', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - ] ]; diff --git a/app/config/platforms.php b/app/config/platforms.php index 56103fad4a..76dcbca50d 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -24,7 +24,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'javascript', - 'source' => \realpath(__DIR__ . '/../sdks/client-web'), + 'source' => \realpath(__DIR__.'/../sdks/client-web'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-web.git', 'gitRepoName' => 'sdk-for-web', 'gitUserName' => 'appwrite', @@ -58,7 +58,7 @@ return [ 'source' => 'https://github.com/appwrite/todo-with-svelte', 'url' => 'https://appwrite-todo-with-svelte.vercel.app/', ], - ] + ], ], [ 'key' => 'flutter', @@ -72,7 +72,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'dart', - 'source' => \realpath(__DIR__ . '/../sdks/client-flutter'), + 'source' => \realpath(__DIR__.'/../sdks/client-flutter'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-flutter.git', 'gitRepoName' => 'sdk-for-flutter', 'gitUserName' => 'appwrite', @@ -90,7 +90,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'swift', - 'source' => \realpath(__DIR__ . '/../sdks/client-apple'), + 'source' => \realpath(__DIR__.'/../sdks/client-apple'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-apple.git', 'gitRepoName' => 'sdk-for-apple', 'gitUserName' => 'appwrite', @@ -125,7 +125,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'kotlin', - 'source' => \realpath(__DIR__ . '/../sdks/client-android'), + 'source' => \realpath(__DIR__.'/../sdks/client-android'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-android.git', 'gitRepoName' => 'sdk-for-android', 'gitUserName' => 'appwrite', @@ -147,7 +147,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'graphql', - 'source' => \realpath(__DIR__ . '/../sdks/client-graphql'), + 'source' => \realpath(__DIR__.'/../sdks/client-graphql'), 'gitUrl' => '', 'gitRepoName' => '', 'gitUserName' => '', @@ -166,7 +166,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'http', - 'source' => \realpath(__DIR__ . '/../sdks/client-rest'), + 'source' => \realpath(__DIR__.'/../sdks/client-rest'), 'gitUrl' => '', 'gitRepoName' => '', 'gitUserName' => '', @@ -194,7 +194,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_CONSOLE, 'prism' => 'javascript', - 'source' => \realpath(__DIR__ . '/../sdks/console-web'), + 'source' => \realpath(__DIR__.'/../sdks/console-web'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-console.git', 'gitBranch' => 'dev', 'gitRepoName' => 'sdk-for-console', @@ -212,7 +212,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CONSOLE, 'prism' => 'bash', - 'source' => \realpath(__DIR__ . '/../sdks/console-cli'), + 'source' => \realpath(__DIR__.'/../sdks/console-cli'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-cli.git', 'gitRepoName' => 'sdk-for-cli', 'gitUserName' => 'appwrite', @@ -240,7 +240,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'javascript', - 'source' => \realpath(__DIR__ . '/../sdks/server-nodejs'), + 'source' => \realpath(__DIR__.'/../sdks/server-nodejs'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-node.git', 'gitRepoName' => 'sdk-for-node', 'gitUserName' => 'appwrite', @@ -258,7 +258,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'typescript', - 'source' => \realpath(__DIR__ . '/../sdks/server-deno'), + 'source' => \realpath(__DIR__.'/../sdks/server-deno'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-deno.git', 'gitRepoName' => 'sdk-for-deno', 'gitUserName' => 'appwrite', @@ -276,7 +276,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'php', - 'source' => \realpath(__DIR__ . '/../sdks/server-php'), + 'source' => \realpath(__DIR__.'/../sdks/server-php'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-php.git', 'gitRepoName' => 'sdk-for-php', 'gitUserName' => 'appwrite', @@ -294,7 +294,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'python', - 'source' => \realpath(__DIR__ . '/../sdks/server-python'), + 'source' => \realpath(__DIR__.'/../sdks/server-python'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-python.git', 'gitRepoName' => 'sdk-for-python', 'gitUserName' => 'appwrite', @@ -312,7 +312,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'ruby', - 'source' => \realpath(__DIR__ . '/../sdks/server-ruby'), + 'source' => \realpath(__DIR__.'/../sdks/server-ruby'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-ruby.git', 'gitRepoName' => 'sdk-for-ruby', 'gitUserName' => 'appwrite', @@ -330,7 +330,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'go', - 'source' => \realpath(__DIR__ . '/../sdks/server-go'), + 'source' => \realpath(__DIR__.'/../sdks/server-go'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-go.git', 'gitRepoName' => 'sdk-for-go', 'gitUserName' => 'appwrite', @@ -348,7 +348,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'java', - 'source' => \realpath(__DIR__ . '/../sdks/server-java'), + 'source' => \realpath(__DIR__.'/../sdks/server-java'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-java.git', 'gitRepoName' => 'sdk-for-java', 'gitUserName' => 'appwrite', @@ -366,7 +366,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'csharp', - 'source' => \realpath(__DIR__ . '/../sdks/server-dotnet'), + 'source' => \realpath(__DIR__.'/../sdks/server-dotnet'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-dotnet.git', 'gitRepoName' => 'sdk-for-dotnet', 'gitUserName' => 'appwrite', @@ -384,7 +384,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'dart', - 'source' => \realpath(__DIR__ . '/../sdks/server-dart'), + 'source' => \realpath(__DIR__.'/../sdks/server-dart'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-dart.git', 'gitRepoName' => 'sdk-for-dart', 'gitUserName' => 'appwrite', @@ -402,7 +402,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'kotlin', - 'source' => \realpath(__DIR__ . '/../sdks/server-kotlin'), + 'source' => \realpath(__DIR__.'/../sdks/server-kotlin'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-kotlin.git', 'gitRepoName' => 'sdk-for-kotlin', 'gitUserName' => 'appwrite', @@ -424,7 +424,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'swift', - 'source' => \realpath(__DIR__ . '/../sdks/server-swift'), + 'source' => \realpath(__DIR__.'/../sdks/server-swift'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-swift.git', 'gitRepoName' => 'sdk-for-swift', 'gitUserName' => 'appwrite', @@ -442,7 +442,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_SERVER, 'prism' => 'graphql', - 'source' => \realpath(__DIR__ . '/../sdks/server-graphql'), + 'source' => \realpath(__DIR__.'/../sdks/server-graphql'), 'gitUrl' => '', 'gitRepoName' => '', 'gitUserName' => '', @@ -461,7 +461,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_SERVER, 'prism' => 'http', - 'source' => \realpath(__DIR__ . '/../sdks/server-rest'), + 'source' => \realpath(__DIR__.'/../sdks/server-rest'), 'gitUrl' => '', 'gitRepoName' => '', 'gitUserName' => '', diff --git a/app/config/regions.php b/app/config/regions.php index 0dc5fab1ed..cc920bee82 100644 --- a/app/config/regions.php +++ b/app/config/regions.php @@ -5,5 +5,5 @@ return [ 'name' => 'Default', 'default' => true, 'disabled' => false, - ] + ], ]; diff --git a/app/config/roles.php b/app/config/roles.php index 4bc85f7a28..cf1827e25e 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -25,7 +25,7 @@ $member = [ 'providers.write', 'providers.read', 'messages.write', - 'messages.read' + 'messages.read', ]; $admins = [ @@ -64,7 +64,7 @@ $admins = [ 'providers.write', 'providers.read', 'messages.write', - 'messages.read' + 'messages.read', ]; return [ diff --git a/app/config/runtimes.php b/app/config/runtimes.php index c24aaa109e..d249946d05 100644 --- a/app/config/runtimes.php +++ b/app/config/runtimes.php @@ -4,8 +4,8 @@ * List of Appwrite Cloud Functions supported runtimes */ -use Utopia\App; use Appwrite\Runtimes\Runtimes; +use Utopia\App; $runtimes = new Runtimes('v2'); diff --git a/app/config/scopes.php b/app/config/scopes.php index cf00654b1e..6dbc19d4aa 100644 --- a/app/config/scopes.php +++ b/app/config/scopes.php @@ -37,7 +37,7 @@ return [ // List of publicly visible scopes 'indexes.write' => [ 'description' => 'Access to create, update, and delete your project\'s database collection\'s indexes', ], - 'documents.read' => [ + 'documents.read' => [ 'description' => 'Access to read your project\'s database documents', ], 'documents.write' => [ @@ -111,5 +111,5 @@ return [ // List of publicly visible scopes ], 'targets.write' => [ 'description' => 'Access to create, update, and delete your project\'s targets', - ] + ], ]; diff --git a/app/config/services.php b/app/config/services.php index f80431f784..ee879eff94 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -66,8 +66,8 @@ return [ 'optional' => true, 'icon' => '/images/services/databases.png', 'globalAttributes' => [ - 'databaseId' - ] + 'databaseId', + ], ], 'locale' => [ 'key' => 'locale', @@ -237,5 +237,5 @@ return [ 'tests' => false, 'optional' => true, 'icon' => '/images/services/messaging.png', - ] + ], ]; diff --git a/app/config/usage.php b/app/config/usage.php index 2179bcce54..a0d3f9f725 100644 --- a/app/config/usage.php +++ b/app/config/usage.php @@ -1,24 +1,24 @@ [ - 'period' => '1h', - 'limit' => 24, - 'factor' => 3600, - ], - '7d' => [ - 'period' => '1d', - 'limit' => 7, - 'factor' => 86400, - ], - '30d' => [ - 'period' => '1d', - 'limit' => 30, - 'factor' => 86400, - ], - '90d' => [ - 'period' => '1d', - 'limit' => 90, - 'factor' => 86400, - ], + '24h' => [ + 'period' => '1h', + 'limit' => 24, + 'factor' => 3600, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + 'factor' => 86400, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + 'factor' => 86400, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + 'factor' => 86400, + ], ]; diff --git a/app/config/variables.php b/app/config/variables.php index c04ba339e5..136ecec5de 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -14,7 +14,7 @@ return [ 'default' => 'production', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_LOCALE', @@ -23,7 +23,7 @@ return [ 'default' => 'en', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_OPTIONS_ABUSE', @@ -32,7 +32,7 @@ return [ 'default' => 'enabled', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_OPTIONS_FORCE_HTTPS', @@ -41,7 +41,7 @@ return [ 'default' => 'disabled', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_OPENSSL_KEY_V1', @@ -50,7 +50,7 @@ return [ 'default' => 'your-secret-key', 'required' => true, 'question' => 'Choose a secret API key, make sure to make a backup of your key in a secure location', - 'filter' => 'token' + 'filter' => 'token', ], [ 'name' => '_APP_DOMAIN', @@ -59,7 +59,7 @@ return [ 'default' => 'localhost', 'required' => true, 'question' => 'Enter your Appwrite hostname', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_DOMAIN_TARGET', @@ -67,8 +67,8 @@ return [ 'introduction' => '', 'default' => 'localhost', 'required' => true, - 'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.' . PHP_EOL . 'You can use the same value as used for the Appwrite hostname.', - 'filter' => 'domainTarget' + 'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.'.PHP_EOL.'You can use the same value as used for the Appwrite hostname.', + 'filter' => 'domainTarget', ], [ 'name' => '_APP_CONSOLE_WHITELIST_ROOT', @@ -77,7 +77,7 @@ return [ 'default' => 'enabled', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_CONSOLE_WHITELIST_EMAILS', @@ -86,7 +86,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], // [ // 'name' => '_APP_CONSOLE_WHITELIST_DOMAINS', @@ -103,7 +103,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_CONSOLE_ROOT_SESSION', @@ -112,7 +112,7 @@ return [ 'default' => 'disabled', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_SYSTEM_EMAIL_NAME', @@ -121,7 +121,7 @@ return [ 'default' => 'Appwrite', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_SYSTEM_EMAIL_ADDRESS', @@ -130,7 +130,7 @@ return [ 'default' => 'team@appwrite.io', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_SYSTEM_RESPONSE_FORMAT', @@ -139,7 +139,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_SYSTEM_SECURITY_EMAIL_ADDRESS', @@ -148,7 +148,7 @@ return [ 'default' => 'certs@appwrite.io', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_USAGE_STATS', @@ -157,7 +157,7 @@ return [ 'default' => 'enabled', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_LOGGING_PROVIDER', @@ -166,7 +166,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_LOGGING_CONFIG', @@ -175,7 +175,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_USAGE_AGGREGATION_INTERVAL', @@ -184,7 +184,7 @@ return [ 'default' => '30', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_USAGE_TIMESERIES_INTERVAL', @@ -193,7 +193,7 @@ return [ 'default' => '30', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_USAGE_DATABASE_INTERVAL', @@ -202,7 +202,7 @@ return [ 'default' => '900', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_WORKER_PER_CORE', @@ -211,7 +211,7 @@ return [ 'default' => 6, 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_CONSOLE_INVITES', @@ -220,7 +220,7 @@ return [ 'default' => 'enabled', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], ], ], @@ -235,7 +235,7 @@ return [ 'default' => 'redis', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_REDIS_PORT', @@ -244,7 +244,7 @@ return [ 'default' => '6379', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_REDIS_USER', @@ -253,7 +253,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_REDIS_PASS', @@ -262,7 +262,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], ], ], @@ -277,7 +277,7 @@ return [ 'default' => 'mariadb', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_DB_PORT', @@ -286,7 +286,7 @@ return [ 'default' => '3306', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_DB_SCHEMA', @@ -295,7 +295,7 @@ return [ 'default' => 'appwrite', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_DB_USER', @@ -304,7 +304,7 @@ return [ 'default' => 'user', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_DB_PASS', @@ -313,7 +313,7 @@ return [ 'default' => 'password', 'required' => false, 'question' => '', - 'filter' => 'password' + 'filter' => 'password', ], [ 'name' => '_APP_DB_ROOT_PASS', @@ -322,7 +322,7 @@ return [ 'default' => 'rootsecretpassword', 'required' => false, 'question' => '', - 'filter' => 'password' + 'filter' => 'password', ], [ 'name' => '_APP_CONNECTIONS_MAX', @@ -331,26 +331,26 @@ return [ 'default' => 251, 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], -// [ -// 'name' => '_APP_CONNECTIONS_DB_PROJECT', -// 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.', -// 'introduction' => 'TBD', -// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', -// 'required' => true, -// 'question' => '', -// 'filter' => '' -// ], -// [ -// 'name' => '_APP_CONNECTIONS_DB_CONSOLE', -// 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.', -// 'introduction' => 'TBD', -// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', -// 'required' => true, -// 'question' => '', -// 'filter' => '' -// ] + // [ + // 'name' => '_APP_CONNECTIONS_DB_PROJECT', + // 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.', + // 'introduction' => 'TBD', + // 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', + // 'required' => true, + // 'question' => '', + // 'filter' => '' + // ], + // [ + // 'name' => '_APP_CONNECTIONS_DB_CONSOLE', + // 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.', + // 'introduction' => 'TBD', + // 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', + // 'required' => true, + // 'question' => '', + // 'filter' => '' + // ] ], ], [ @@ -364,7 +364,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_SMTP_PORT', @@ -373,7 +373,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_SMTP_SECURE', @@ -382,7 +382,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_SMTP_USERNAME', @@ -391,7 +391,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_SMTP_PASSWORD', @@ -400,7 +400,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], ], ], @@ -415,7 +415,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_SMS_FROM', @@ -424,7 +424,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], ], ], @@ -439,7 +439,7 @@ return [ 'default' => '30000000', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_STORAGE_PREVIEW_LIMIT', @@ -448,7 +448,7 @@ return [ 'default' => '20000000', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_STORAGE_ANTIVIRUS', @@ -457,7 +457,7 @@ return [ 'default' => 'disabled', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_STORAGE_ANTIVIRUS_HOST', @@ -466,7 +466,7 @@ return [ 'default' => 'clamav', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_STORAGE_ANTIVIRUS_PORT', @@ -475,7 +475,7 @@ return [ 'default' => '3310', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_CONNECTIONS_STORAGE', @@ -666,7 +666,7 @@ return [ 'default' => '30000000', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_TIMEOUT', @@ -675,7 +675,7 @@ return [ 'default' => '900', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_BUILD_TIMEOUT', @@ -684,7 +684,7 @@ return [ 'default' => '900', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_CONTAINERS', @@ -693,7 +693,7 @@ return [ 'default' => '10', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_CPUS', @@ -702,7 +702,7 @@ return [ 'default' => '0', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_MEMORY', @@ -711,7 +711,7 @@ return [ 'default' => '0', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_MEMORY_SWAP', @@ -720,16 +720,16 @@ return [ 'default' => '0', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_RUNTIMES', - 'description' => "This option allows you to enable or disable runtime environments for cloud functions. Disable unused runtimes to save disk space.\n\nTo enable cloud function runtimes, pass a list of enabled environments separated by a comma.\n\nCurrently, supported environments are: " . \implode(', ', \array_keys(Config::getParam('runtimes'))), + 'description' => "This option allows you to enable or disable runtime environments for cloud functions. Disable unused runtimes to save disk space.\n\nTo enable cloud function runtimes, pass a list of enabled environments separated by a comma.\n\nCurrently, supported environments are: ".\implode(', ', \array_keys(Config::getParam('runtimes'))), 'introduction' => '0.8.0', 'default' => 'node-16.0,php-8.0,python-3.9,ruby-3.0', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_EXECUTOR_SECRET', @@ -738,7 +738,7 @@ return [ 'default' => 'your-secret-key', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_EXECUTOR_HOST', @@ -747,7 +747,7 @@ return [ 'default' => 'http://appwrite-executor/v1', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_EXECUTOR_RUNTIME_NETWORK', @@ -756,7 +756,7 @@ return [ 'default' => 'appwrite_runtimes', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_ENVS', @@ -765,7 +765,7 @@ return [ 'default' => 'node-16.0,php-7.4,python-3.9,ruby-3.0', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_INACTIVE_THRESHOLD', @@ -774,7 +774,7 @@ return [ 'default' => '60', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => 'DOCKERHUB_PULL_USERNAME', @@ -783,7 +783,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => 'DOCKERHUB_PULL_PASSWORD', @@ -792,7 +792,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => 'DOCKERHUB_PULL_EMAIL', @@ -801,7 +801,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => 'OPEN_RUNTIMES_NETWORK', @@ -810,7 +810,7 @@ return [ 'default' => 'appwrite_runtimes', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_RUNTIMES_NETWORK', @@ -819,7 +819,7 @@ return [ 'default' => 'runtimes', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_DOCKER_HUB_USERNAME', @@ -828,7 +828,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_DOCKER_HUB_PASSWORD', @@ -837,7 +837,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_FUNCTIONS_MAINTENANCE_INTERVAL', @@ -846,7 +846,7 @@ return [ 'default' => '60', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], ], ], @@ -861,7 +861,7 @@ return [ 'default' => '86400', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_MAINTENANCE_RETENTION_CACHE', @@ -870,7 +870,7 @@ return [ 'default' => '2592000', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_MAINTENANCE_RETENTION_EXECUTION', @@ -879,7 +879,7 @@ return [ 'default' => '1209600', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_MAINTENANCE_RETENTION_AUDIT', @@ -888,7 +888,7 @@ return [ 'default' => '1209600', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_MAINTENANCE_RETENTION_ABUSE', @@ -897,7 +897,7 @@ return [ 'default' => '86400', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_MAINTENANCE_RETENTION_USAGE_HOURLY', @@ -906,7 +906,7 @@ return [ 'default' => '8640000', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_MAINTENANCE_RETENTION_SCHEDULES', @@ -915,8 +915,8 @@ return [ 'default' => '86400', 'required' => false, 'question' => '', - 'filter' => '' - ] + 'filter' => '', + ], ], ], [ @@ -930,7 +930,7 @@ return [ 'default' => '10', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_GRAPHQL_MAX_COMPLEXITY', @@ -939,7 +939,7 @@ return [ 'default' => '250', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], [ 'name' => '_APP_GRAPHQL_MAX_DEPTH', @@ -948,7 +948,7 @@ return [ 'default' => '3', 'required' => false, 'question' => '', - 'filter' => '' + 'filter' => '', ], ], ], diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 46acd2efdb..8f9fc34635 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -4,6 +4,9 @@ use Ahc\Jwt\JWT; use Appwrite\Auth\Auth; use Appwrite\Auth\OAuth2\Exception as OAuth2Exception; use Appwrite\Auth\Validator\Password; +use Appwrite\Auth\Validator\PasswordDictionary; +use Appwrite\Auth\Validator\PasswordHistory; +use Appwrite\Auth\Validator\PersonalData; use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; use Appwrite\Event\Event; @@ -11,16 +14,11 @@ use Appwrite\Event\Mail; use Appwrite\Event\Phone as EventPhone; use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; -use Utopia\Validator\Host; -use Utopia\Validator\URL; use Appwrite\OpenSSL\OpenSSL; use Appwrite\Template\Template; use Appwrite\URL\URL as URLParser; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Database\Validator\Queries\Identities; -use Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use MaxMind\Db\Reader; @@ -28,23 +26,25 @@ use Utopia\App; use Utopia\Audit\Audit as EventAudit; use Utopia\Config\Config; use Utopia\Database\Database; -use Utopia\Database\Document; use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Exception\Duplicate; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Query; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; +use Utopia\Validator\Host; use Utopia\Validator\Text; +use Utopia\Validator\URL; use Utopia\Validator\WhiteList; -use Appwrite\Auth\Validator\PasswordHistory; -use Appwrite\Auth\Validator\PasswordDictionary; -use Appwrite\Auth\Validator\PersonalData; $oauthDefaultSuccess = '/auth/oauth2/success'; $oauthDefaultFailure = '/auth/oauth2/failure'; @@ -77,20 +77,19 @@ App::post('/v1/account/invite') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $email, string $password, string $name, string $code, Request $request, Response $response, Document $project, Database $dbForProject, Event $events) { - if ($project->getId() !== 'console') { throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN); } $email = \strtolower($email); - $whitelistCodes = (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null)) : []; + $whitelistCodes = (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null)) : []; if (empty($whitelistCodes)) { throw new Exception(Exception::GENERAL_CODES_DISABLED); } - if (!empty($whitelistCodes) && !\in_array($code, $whitelistCodes)) { + if (! empty($whitelistCodes) && ! \in_array($code, $whitelistCodes)) { throw new Exception(Exception::USER_INVALID_CODE); } @@ -106,7 +105,7 @@ App::post('/v1/account/invite') try { $userId = $userId == 'unique()' ? ID::unique() : $userId; - $user = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([ + $user = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([ '$id' => $userId, '$permissions' => [ Permission::read(Role::any()), @@ -127,7 +126,7 @@ App::post('/v1/account/invite') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]) + 'search' => implode(' ', [$userId, $email, $name]), ]))); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); @@ -177,11 +176,11 @@ App::post('/v1/account') $whitelistEmails = $project->getAttribute('authWhitelistEmails'); $whitelistIPs = $project->getAttribute('authWhitelistIPs'); - if (!empty($whitelistEmails) && !\in_array($email, $whitelistEmails) && !\in_array(strtoupper($email), $whitelistEmails)) { + if (! empty($whitelistEmails) && ! \in_array($email, $whitelistEmails) && ! \in_array(strtoupper($email), $whitelistEmails)) { throw new Exception(Exception::USER_EMAIL_NOT_WHITELISTED); } - if (!empty($whitelistIPs) && !\in_array($request->getIP(), $whitelistIPs)) { + if (! empty($whitelistIPs) && ! \in_array($request->getIP(), $whitelistIPs)) { throw new Exception(Exception::USER_IP_NOT_WHITELISTED); } } @@ -200,13 +199,13 @@ App::post('/v1/account') $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) { $personalDataValidator = new PersonalData($userId, $email, $name, null); - if (!$personalDataValidator->isValid($password)) { + if (! $personalDataValidator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA); } } @@ -240,7 +239,7 @@ App::post('/v1/account') 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), // Add this here to make sure it's returned in the response ]); - Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); } @@ -286,7 +285,6 @@ App::post('/v1/account/sessions/email') ->inject('geodb') ->inject('events') ->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) { - $email = \strtolower($email); $protocol = $request->getProtocol(); @@ -294,7 +292,7 @@ App::post('/v1/account/sessions/email') Query::equal('email', [$email]), ]); - if (!$profile || empty($profile->getAttribute('passwordUpdate')) || !Auth::passwordVerify($password, $profile->getAttribute('password'), $profile->getAttribute('hash'), $profile->getAttribute('hashOptions'))) { + if (! $profile || empty($profile->getAttribute('passwordUpdate')) || ! Auth::passwordVerify($password, $profile->getAttribute('password'), $profile->getAttribute('hash'), $profile->getAttribute('hashOptions'))) { throw new Exception(Exception::USER_INVALID_CREDENTIALS); } @@ -346,31 +344,26 @@ App::post('/v1/account/sessions/email') Permission::delete(Role::user($user->getId())), ])); - - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response - ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])) - ; + ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } $response - ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED) - ; + ->setStatusCode(Response::STATUS_CODE_CREATED); - $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', $expire) - ; + ->setAttribute('expire', $expire); $events ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()) - ; + ->setParam('sessionId', $session->getId()); $response->dynamic($session, Response::MODEL_SESSION); }); @@ -378,7 +371,7 @@ App::post('/v1/account/sessions/email') App::get('/v1/account/sessions/oauth2/:provider') ->desc('Create OAuth2 Session') ->groups(['api', 'account']) - ->label('error', __DIR__ . '/../../views/general/error.phtml') + ->label('error', __DIR__.'/../../views/general/error.phtml') ->label('scope', 'public') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') @@ -389,48 +382,47 @@ App::get('/v1/account/sessions/oauth2/:provider') ->label('sdk.methodType', 'webAuth') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('authProviders'), fn($node) => (!$node['mock'])))) . '.') - ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. 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']) - ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. 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']) - ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 Provider. Currently, supported providers are: '.\implode(', ', \array_keys(\array_filter(Config::getParam('authProviders'), fn ($node) => (! $node['mock'])))).'.') + ->param('success', '', fn ($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. 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']) + ->param('failure', '', fn ($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. 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']) + ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' scopes are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long.', true) ->inject('request') ->inject('response') ->inject('project') ->action(function (string $provider, string $success, string $failure, array $scopes, Request $request, Response $response, Document $project) use ($oauthDefaultSuccess, $oauthDefaultFailure) { - $protocol = $request->getProtocol(); - $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); - $providerEnabled = $project->getAttribute('authProviders', [])[$provider . 'Enabled'] ?? false; + $callback = $protocol.'://'.$request->getHostname().'/v1/account/sessions/oauth2/callback/'.$provider.'/'.$project->getId(); + $providerEnabled = $project->getAttribute('authProviders', [])[$provider.'Enabled'] ?? false; - if (!$providerEnabled) { - throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your ' . APP_NAME . ' console to continue.'); + if (! $providerEnabled) { + throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your '.APP_NAME.' console to continue.'); } - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? ''; + $appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}'; - if (!empty($appSecret) && isset($appSecret['version'])) { - $key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']); + if (! empty($appSecret) && isset($appSecret['version'])) { + $key = App::getEnv('_APP_OPENSSL_KEY_V'.$appSecret['version']); $appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key, 0, \hex2bin($appSecret['iv']), \hex2bin($appSecret['tag'])); } if (empty($appId) || empty($appSecret)) { - throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.'); + throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please configure the provider app ID and app secret key from your '.APP_NAME.' console to continue.'); } - $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); + $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); - if (!\class_exists($className)) { + if (! \class_exists($className)) { throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } if (empty($success)) { - $success = $protocol . '://' . $request->getHostname() . $oauthDefaultSuccess; + $success = $protocol.'://'.$request->getHostname().$oauthDefaultSuccess; } if (empty($failure)) { - $failure = $protocol . '://' . $request->getHostname() . $oauthDefaultFailure; + $failure = $protocol.'://'.$request->getHostname().$oauthDefaultFailure; } $oauth2 = new $className($appId, $appSecret, $callback, ['success' => $success, 'failure' => $failure], $scopes); @@ -444,7 +436,7 @@ App::get('/v1/account/sessions/oauth2/:provider') App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->desc('OAuth2 Callback') ->groups(['account']) - ->label('error', __DIR__ . '/../../views/general/error.phtml') + ->label('error', __DIR__.'/../../views/general/error.phtml') ->label('scope', 'public') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') @@ -456,27 +448,26 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->inject('request') ->inject('response') ->action(function (string $projectId, string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response) { - $domain = $request->getHostname(); $protocol = $request->getProtocol(); $response ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') ->addHeader('Pragma', 'no-cache') - ->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?' - . \http_build_query([ + ->redirect($protocol.'://'.$domain.'/v1/account/sessions/oauth2/'.$provider.'/redirect?' + .\http_build_query([ 'project' => $projectId, 'code' => $code, 'state' => $state, 'error' => $error, - 'error_description' => $error_description + 'error_description' => $error_description, ])); }); App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->desc('OAuth2 Callback') ->groups(['account']) - ->label('error', __DIR__ . '/../../views/general/error.phtml') + ->label('error', __DIR__.'/../../views/general/error.phtml') ->label('scope', 'public') ->label('origin', '*') ->label('docs', false) @@ -489,27 +480,26 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->inject('request') ->inject('response') ->action(function (string $projectId, string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response) { - $domain = $request->getHostname(); $protocol = $request->getProtocol(); $response ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') ->addHeader('Pragma', 'no-cache') - ->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?' - . \http_build_query([ + ->redirect($protocol.'://'.$domain.'/v1/account/sessions/oauth2/'.$provider.'/redirect?' + .\http_build_query([ 'project' => $projectId, 'code' => $code, 'state' => $state, 'error' => $error, - 'error_description' => $error_description + 'error_description' => $error_description, ])); }); App::get('/v1/account/sessions/oauth2/:provider/redirect') ->desc('OAuth2 Redirect') ->groups(['api', 'account', 'session']) - ->label('error', __DIR__ . '/../../views/general/error.phtml') + ->label('error', __DIR__.'/../../views/general/error.phtml') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('audits.event', 'session.create') @@ -531,18 +521,17 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->inject('geodb') ->inject('events') ->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $events) use ($oauthDefaultSuccess) { - $protocol = $request->getProtocol(); - $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); + $callback = $protocol.'://'.$request->getHostname().'/v1/account/sessions/oauth2/callback/'.$provider.'/'.$project->getId(); $defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => '']; $validateURL = new URL(); - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; - $providerEnabled = $project->getAttribute('authProviders', [])[$provider . 'Enabled'] ?? false; + $appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? ''; + $appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}'; + $providerEnabled = $project->getAttribute('authProviders', [])[$provider.'Enabled'] ?? false; - $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); + $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); - if (!\class_exists($className)) { + if (! \class_exists($className)) { throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } @@ -552,7 +541,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') /** @var Appwrite\Auth\OAuth2 $oauth2 */ $oauth2 = new $className($appId, $appSecret, $callback); - if (!empty($state)) { + if (! empty($state)) { try { $state = \array_merge($defaultState, $oauth2->parseState($state)); } catch (\Exception $exception) { @@ -562,25 +551,25 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $state = $defaultState; } - if (!$validateURL->isValid($state['success'])) { + if (! $validateURL->isValid($state['success'])) { throw new Exception(Exception::PROJECT_INVALID_SUCCESS_URL); } - if (!empty($state['failure']) && !$validateURL->isValid($state['failure'])) { + if (! empty($state['failure']) && ! $validateURL->isValid($state['failure'])) { throw new Exception(Exception::PROJECT_INVALID_FAILURE_URL); } $failure = []; - if (!empty($state['failure'])) { + if (! empty($state['failure'])) { $failure = URLParser::parse($state['failure']); } $failureRedirect = (function (string $type, ?string $message = null, ?int $code = null) use ($failure, $response) { $exception = new Exception($type, $message, $code); - if (!empty($failure)) { + if (! empty($failure)) { $query = URLParser::parseQuery($failure['query']); $query['error'] = json_encode([ 'message' => $exception->getMessage(), 'type' => $exception->getType(), - 'code' => !\is_null($code) ? $code : $exception->getCode(), + 'code' => ! \is_null($code) ? $code : $exception->getCode(), ]); $failure['query'] = URLParser::unparseQuery($query); $response->redirect(URLParser::unparse($failure), 301); @@ -589,14 +578,14 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') throw $exception; }); - if (!$providerEnabled) { - $failureRedirect(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your ' . APP_NAME . ' console to continue.'); + if (! $providerEnabled) { + $failureRedirect(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your '.APP_NAME.' console to continue.'); } - if (!empty($error)) { - $message = 'The ' . $providerName . ' OAuth2 provider returned an error: ' . $error; - if (!empty($error_description)) { - $message .= ': ' . $error_description; + if (! empty($error)) { + $message = 'The '.$providerName.' OAuth2 provider returned an error: '.$error; + if (! empty($error_description)) { + $message .= ': '.$error_description; } $failureRedirect(Exception::USER_OAUTH2_PROVIDER_ERROR, $message); } @@ -605,8 +594,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $failureRedirect(Exception::USER_OAUTH2_PROVIDER_ERROR, 'Missing OAuth2 code. Please contact the Appwrite team for additional support.'); } - if (!empty($appSecret) && isset($appSecret['version'])) { - $key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']); + if (! empty($appSecret) && isset($appSecret['version'])) { + $key = App::getEnv('_APP_OPENSSL_KEY_V'.$appSecret['version']); $appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key, 0, \hex2bin($appSecret['iv']), \hex2bin($appSecret['tag'])); } @@ -621,7 +610,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } catch (OAuth2Exception $ex) { $failureRedirect( $ex->getType(), - 'Failed to obtain access token. The ' . $providerName . ' OAuth2 provider returned an error: ' . $ex->getMessage(), + 'Failed to obtain access token. The '.$providerName.' OAuth2 provider returned an error: '.$ex->getMessage(), $ex->getCode(), ); } @@ -635,14 +624,14 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $email = $oauth2->getUserEmail($accessToken); // Check if this identity is connected to a different user - if (!$user->isEmpty()) { + if (! $user->isEmpty()) { $userId = $user->getId(); $identitiesWithMatchingEmail = $dbForProject->find('identities', [ Query::equal('providerEmail', [$email]), Query::notEqual('userId', $userId), ]); - if (!empty($identitiesWithMatchingEmail)) { + if (! empty($identitiesWithMatchingEmail)) { throw new Exception(Exception::USER_ALREADY_EXISTS); } } @@ -653,7 +642,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') if ($current) { // Delete current session of new one. $currentDocument = $dbForProject->getDocument('sessions', $current); - if (!$currentDocument->isEmpty()) { + if (! $currentDocument->isEmpty()) { $dbForProject->deleteDocument('sessions', $currentDocument->getId()); $dbForProject->deleteCachedDocument('users', $user->getId()); } @@ -664,7 +653,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') Query::equal('provider', [$provider]), Query::equal('providerUid', [$oauth2ID]), ]); - if ($session !== false && !$session->isEmpty()) { + if ($session !== false && ! $session->isEmpty()) { $user->setAttributes($dbForProject->getDocument('users', $session->getAttribute('userId'))->getArrayCopy()); } } @@ -682,7 +671,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $userWithEmail = $dbForProject->findOne('users', [ Query::equal('email', [$email]), ]); - if ($userWithEmail !== false && !$userWithEmail->isEmpty()) { + if ($userWithEmail !== false && ! $userWithEmail->isEmpty()) { $user->setAttributes($userWithEmail->getArrayCopy()); } @@ -693,7 +682,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') Query::equal('providerUid', [$oauth2ID]), ]); - if ($identity !== false && !$identity->isEmpty()) { + if ($identity !== false && ! $identity->isEmpty()) { $user = $dbForProject->getDocument('users', $identity->getAttribute('userId')); } } @@ -713,7 +702,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -740,9 +729,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]) + 'search' => implode(' ', [$userId, $email, $name]), ]); - Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); } catch (Duplicate $th) { $failureRedirect(Exception::USER_ALREADY_EXISTS); } @@ -769,7 +758,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') Query::equal('providerEmail', [$email]), Query::notEqual('userId', $user->getId()), ]); - if (!empty($identitiesWithMatchingEmail)) { + if (! empty($identitiesWithMatchingEmail)) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -787,13 +776,13 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'providerEmail' => $email, 'providerAccessToken' => $accessToken, 'providerRefreshToken' => $refreshToken, - 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry), + 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry), ])); } else { $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry)); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry)); $dbForProject->updateDocument('identities', $identity->getId(), $identity); } @@ -812,7 +801,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'providerUid' => $oauth2ID, 'providerAccessToken' => $accessToken, 'providerRefreshToken' => $refreshToken, - 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry), + 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry), 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'userAgent' => $request->getUserAgent('UNKNOWN'), 'ip' => $request->getIP(), @@ -828,8 +817,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } $user - ->setAttribute('status', true) - ; + ->setAttribute('status', true); Authorization::setRole(Role::user($user->getId())->toString()); @@ -848,10 +836,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()) - ->setPayload($response->output($session, Response::MODEL_SESSION)) - ; + ->setPayload($response->output($session, Response::MODEL_SESSION)); - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } @@ -870,10 +857,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $response ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') ->addHeader('Pragma', 'no-cache') - ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->redirect($state['success']) - ; + ->redirect($state['success']); }); App::get('/v1/account/identities') @@ -889,12 +875,11 @@ App::get('/v1/account/identities') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_IDENTITY_LIST) ->label('sdk.offline.model', '/account/identities') - ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Identities::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Identities::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('user') ->inject('dbForProject') ->action(function (array $queries, Response $response, Document $user, Database $dbForProject) { - $queries = Query::parseQueries($queries); $queries[] = Query::equal('userInternalId', [$user->getInternalId()]); @@ -944,7 +929,6 @@ App::delete('/v1/account/identities/:identityId') ->inject('response') ->inject('dbForProject') ->action(function (string $identityId, Response $response, Database $dbForProject) { - $identity = $dbForProject->getDocument('identities', $identityId); if ($identity->isEmpty()) { @@ -975,7 +959,7 @@ App::post('/v1/account/sessions/magic-url') ->label('abuse-key', 'url:{url},email:{param-email}') ->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('email', '', new Email(), 'User email.') - ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) + ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) ->inject('request') ->inject('response') ->inject('user') @@ -985,7 +969,6 @@ App::post('/v1/account/sessions/magic-url') ->inject('events') ->inject('mails') ->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $events, Mail $mails) { - if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled'); } @@ -995,7 +978,7 @@ App::post('/v1/account/sessions/magic-url') $isAppUser = Auth::isAppUser($roles); $result = $dbForProject->findOne('users', [Query::equal('email', [$email])]); - if ($result !== false && !$result->isEmpty()) { + if ($result !== false && ! $result->isEmpty()) { $user->setAttributes($result->getArrayCopy()); } else { $limit = $project->getAttribute('auths', [])['limit'] ?? 0; @@ -1012,7 +995,7 @@ App::post('/v1/account/sessions/magic-url') $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -1038,7 +1021,7 @@ App::post('/v1/account/sessions/magic-url') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email]) + 'search' => implode(' ', [$userId, $email]), ]); Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); @@ -1070,7 +1053,7 @@ App::post('/v1/account/sessions/magic-url') $dbForProject->deleteCachedDocument('users', $user->getId()); if (empty($url)) { - $url = $request->getProtocol() . '://' . $request->getHostname() . '/auth/magic-url'; + $url = $request->getProtocol().'://'.$request->getHostname().'/auth/magic-url'; } $url = Template::parseURL($url); @@ -1078,12 +1061,12 @@ App::post('/v1/account/sessions/magic-url') $url = Template::unParseURL($url); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $project->getAttribute('name')); - $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); - $subject = $locale->getText("emails.magicSession.subject"); + $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); + $subject = $locale->getText('emails.magicSession.subject'); $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; - $customTemplate = $project->getAttribute('templates', [])['email.magicSession-' . $locale->default] ?? []; - if ($smtpEnabled && !empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['email.magicSession-'.$locale->default] ?? []; + if ($smtpEnabled && ! empty($customTemplate)) { $body = $customTemplate['message'] ?? $body; $subject = $customTemplate['subject'] ?? $subject; $from = $customTemplate['senderName'] ?? $from; @@ -1091,13 +1074,13 @@ App::post('/v1/account/sessions/magic-url') $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.magicSession.hello")) + ->setParam('{{hello}}', $locale->getText('emails.magicSession.hello')) ->setParam('{{name}}', '') - ->setParam('{{body}}', $locale->getText("emails.magicSession.body")) + ->setParam('{{body}}', $locale->getText('emails.magicSession.body')) ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText("emails.magicSession.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.magicSession.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.magicSession.signature")) + ->setParam('{{footer}}', $locale->getText('emails.magicSession.footer')) + ->setParam('{{thanks}}', $locale->getText('emails.magicSession.thanks')) + ->setParam('{{signature}}', $locale->getText('emails.magicSession.signature')) ->setParam('{{project}}', $project->getAttribute('name')) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -1111,8 +1094,7 @@ App::post('/v1/account/sessions/magic-url') ->setBody($body) ->setFrom($from) ->setRecipient($user->getAttribute('email')) - ->trigger() - ; + ->trigger(); $events->setPayload( $response->output( @@ -1126,8 +1108,7 @@ App::post('/v1/account/sessions/magic-url') $response ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($token, Response::MODEL_TOKEN) - ; + ->dynamic($token, Response::MODEL_TOKEN); }); App::put('/v1/account/sessions/magic-url') @@ -1158,10 +1139,8 @@ App::put('/v1/account/sessions/magic-url') ->inject('geodb') ->inject('events') ->action(function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) { - /** @var Utopia\Database\Document $user */ - - $userFromRequest = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); + $userFromRequest = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); if ($userFromRequest->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -1169,7 +1148,7 @@ App::put('/v1/account/sessions/magic-url') $token = Auth::tokenVerify($userFromRequest->getAttribute('tokens', []), Auth::TOKEN_TYPE_MAGIC_URL, $secret); - if (!$token) { + if (! $token) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -1227,28 +1206,25 @@ App::put('/v1/account/sessions/magic-url') $events ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()) - ; + ->setParam('sessionId', $session->getId()); - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } $protocol = $request->getProtocol(); $response - ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED) - ; + ->setStatusCode(Response::STATUS_CODE_CREATED); - $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', $expire) - ; + ->setAttribute('expire', $expire); $response->dynamic($session, Response::MODEL_SESSION); }); @@ -1281,7 +1257,6 @@ App::post('/v1/account/sessions/phone') ->inject('messaging') ->inject('locale') ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, EventPhone $messaging, Locale $locale) { - if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -1291,7 +1266,7 @@ App::post('/v1/account/sessions/phone') $isAppUser = Auth::isAppUser($roles); $result = $dbForProject->findOne('users', [Query::equal('phone', [$phone])]); - if ($result !== false && !$result->isEmpty()) { + if ($result !== false && ! $result->isEmpty()) { $user->setAttributes($result->getArrayCopy()); } else { $limit = $project->getAttribute('auths', [])['limit'] ?? 0; @@ -1325,7 +1300,7 @@ App::post('/v1/account/sessions/phone') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $phone]) + 'search' => implode(' ', [$userId, $phone]), ]); Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); @@ -1356,10 +1331,10 @@ App::post('/v1/account/sessions/phone') $dbForProject->deleteCachedDocument('users', $user->getId()); - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl'); + $message = Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl'); - $customTemplate = $project->getAttribute('templates', [])['sms.login-' . $locale->default] ?? []; - if (!empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['sms.login-'.$locale->default] ?? []; + if (! empty($customTemplate)) { $message = $customTemplate['message'] ?? $message; } @@ -1383,8 +1358,7 @@ App::post('/v1/account/sessions/phone') $response ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($token, Response::MODEL_TOKEN) - ; + ->dynamic($token, Response::MODEL_TOKEN); }); App::put('/v1/account/sessions/phone') @@ -1412,8 +1386,7 @@ App::put('/v1/account/sessions/phone') ->inject('geodb') ->inject('events') ->action(function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) { - - $userFromRequest = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); + $userFromRequest = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); if ($userFromRequest->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -1421,7 +1394,7 @@ App::put('/v1/account/sessions/phone') $token = Auth::phoneTokenVerify($userFromRequest->getAttribute('tokens', []), $secret); - if (!$token) { + if (! $token) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -1477,28 +1450,25 @@ App::put('/v1/account/sessions/phone') $events ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()) - ; + ->setParam('sessionId', $session->getId()); - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } $protocol = $request->getProtocol(); $response - ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED) - ; + ->setStatusCode(Response::STATUS_CODE_CREATED); - $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', $expire) - ; + ->setAttribute('expire', $expire); $response->dynamic($session, Response::MODEL_SESSION); }); @@ -1530,14 +1500,13 @@ App::post('/v1/account/sessions/anonymous') ->inject('geodb') ->inject('events') ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Event $events) { - $protocol = $request->getProtocol(); if ('console' === $project->getId()) { throw new Exception(Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'Failed to create anonymous user'); } - if (!$user->isEmpty()) { + if (! $user->isEmpty()) { throw new Exception(Exception::USER_SESSION_ALREADY_EXISTS, 'Cannot create an anonymous user when logged in'); } @@ -1575,7 +1544,7 @@ App::post('/v1/account/sessions/anonymous') 'memberships' => null, 'search' => $userId, ]); - Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); // Create session token $duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; @@ -1602,36 +1571,33 @@ App::post('/v1/account/sessions/anonymous') Authorization::setRole(Role::user($user->getId())->toString()); - $session = $dbForProject->createDocument('sessions', $session-> setAttribute('$permissions', [ - Permission::read(Role::user($user->getId())), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ])); + $session = $dbForProject->createDocument('sessions', $session->setAttribute('$permissions', [ + Permission::read(Role::user($user->getId())), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ])); $dbForProject->deleteCachedDocument('users', $user->getId()); $events ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()) - ; + ->setParam('sessionId', $session->getId()); - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } $response - ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED) - ; + ->setStatusCode(Response::STATUS_CODE_CREATED); - $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', $expire) - ; + ->setAttribute('expire', $expire); $response->dynamic($session, Response::MODEL_SESSION); }); @@ -1654,8 +1620,6 @@ App::post('/v1/account/jwt') ->inject('user') ->inject('dbForProject') ->action(function (Response $response, Document $user, Database $dbForProject) { - - $sessions = $user->getAttribute('sessions', []); $current = new Document(); @@ -1674,13 +1638,13 @@ App::post('/v1/account/jwt') $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic(new Document(['jwt' => $jwt->encode([ - // 'uid' => 1, - // 'aud' => 'http://site.com', - // 'scopes' => ['user'], - // 'iss' => 'http://api.mysite.com', - 'userId' => $user->getId(), - 'sessionId' => $current->getId(), - ])]), Response::MODEL_JWT); + // 'uid' => 1, + // 'aud' => 'http://site.com', + // 'scopes' => ['user'], + // 'iss' => 'http://api.mysite.com', + 'userId' => $user->getId(), + 'sessionId' => $current->getId(), + ])]), Response::MODEL_JWT); }); App::get('/v1/account') @@ -1699,7 +1663,6 @@ App::get('/v1/account') ->inject('response') ->inject('user') ->action(function (Response $response, Document $user) { - $response->dynamic($user, Response::MODEL_ACCOUNT); }); @@ -1719,7 +1682,6 @@ App::get('/v1/account/prefs') ->inject('response') ->inject('user') ->action(function (Response $response, Document $user) { - $prefs = $user->getAttribute('prefs', []); $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); @@ -1742,13 +1704,12 @@ App::get('/v1/account/sessions') ->inject('locale') ->inject('project') ->action(function (Response $response, Document $user, Locale $locale, Document $project) { - $sessions = $user->getAttribute('sessions', []); $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $current = Auth::sessionVerify($sessions, Auth::$secret, $authDuration); foreach ($sessions as $key => $session) {/** @var Document $session */ - $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session->setAttribute('countryName', $countryName); $session->setAttribute('current', ($current == $session->getId()) ? true : false); @@ -1781,7 +1742,6 @@ App::get('/v1/account/logs') ->inject('geodb') ->inject('dbForProject') ->action(function (array $queries, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject) { - $queries = Query::parseQueries($queries); $grouped = Query::groupByType($queries); $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; @@ -1794,7 +1754,7 @@ App::get('/v1/account/logs') $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); @@ -1809,8 +1769,8 @@ App::get('/v1/account/logs') $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -1837,7 +1797,6 @@ App::get('/v1/account/targets') ->inject('response') ->inject('user') ->action(function (Response $response, Document $user) { - $targets = $user->getAttribute('targets', []); $response->dynamic(new Document([ @@ -1866,7 +1825,6 @@ App::get('/v1/account/sessions/:sessionId') ->inject('dbForProject') ->inject('project') ->action(function (?string $sessionId, Response $response, Document $user, Locale $locale, Database $dbForProject, Document $project) { - $sessions = $user->getAttribute('sessions', []); $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $sessionId = ($sessionId === 'current') @@ -1875,13 +1833,12 @@ App::get('/v1/account/sessions/:sessionId') foreach ($sessions as $session) {/** @var Document $session */ if ($sessionId == $session->getId()) { - $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', ($session->getAttribute('secret') == Auth::hash(Auth::$secret))) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', DateTime::formatTz(DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration))) - ; + ->setAttribute('expire', DateTime::formatTz(DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration))); return $response->dynamic($session, Response::MODEL_SESSION); } @@ -1907,7 +1864,6 @@ App::get('/v1/account/targets/:targetId') ->inject('response') ->inject('user') ->action(function (string $targetId, Response $response, Document $user) { - $target = $user->find('$id', $targetId, 'targets'); if (empty($target)) { @@ -1940,7 +1896,6 @@ App::patch('/v1/account/name') ->inject('dbForProject') ->inject('events') ->action(function (string $name, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) { - $user->setAttribute('name', $name); $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); @@ -1976,9 +1931,8 @@ App::patch('/v1/account/password') ->inject('dbForProject') ->inject('events') ->action(function (string $password, string $oldPassword, ?\DateTime $requestTimestamp, Response $response, Document $user, Document $project, Database $dbForProject, Event $events) { - // Check old password only if its an existing user. - if (!empty($user->getAttribute('passwordUpdate')) && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password + if (! empty($user->getAttribute('passwordUpdate')) && ! Auth::passwordVerify($oldPassword, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password throw new Exception(Exception::USER_INVALID_CREDENTIALS); } @@ -1987,7 +1941,7 @@ App::patch('/v1/account/password') $history = $user->getAttribute('passwordHistory', []); if ($historyLimit > 0) { $validator = new PasswordHistory($history, $user->getAttribute('hash'), $user->getAttribute('hashOptions')); - if (!$validator->isValid($password)) { + if (! $validator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED); } @@ -1997,7 +1951,7 @@ App::patch('/v1/account/password') if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) { $personalDataValidator = new PersonalData($user->getId(), $user->getAttribute('email'), $user->getAttribute('name'), $user->getAttribute('phone')); - if (!$personalDataValidator->isValid($password)) { + if (! $personalDataValidator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA); } } @@ -2044,8 +1998,8 @@ App::patch('/v1/account/email') $passwordUpdate = $user->getAttribute('passwordUpdate'); if ( - !empty($passwordUpdate) && - !Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions')) + ! empty($passwordUpdate) && + ! Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions')) ) { // Double check user password throw new Exception(Exception::USER_INVALID_CREDENTIALS); } @@ -2057,14 +2011,14 @@ App::patch('/v1/account/email') Query::equal('providerEmail', [$email]), Query::notEqual('userId', $user->getId()), ]); - if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) // After this user needs to confirm mail again - ; +; if (empty($passwordUpdate)) { $user @@ -2113,8 +2067,8 @@ App::patch('/v1/account/phone') $passwordUpdate = $user->getAttribute('passwordUpdate'); if ( - !empty($passwordUpdate) && - !Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions')) + ! empty($passwordUpdate) && + ! Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions')) ) { // Double check user password throw new Exception(Exception::USER_INVALID_CREDENTIALS); } @@ -2122,7 +2076,7 @@ App::patch('/v1/account/phone') $user ->setAttribute('phone', $phone) ->setAttribute('phoneVerification', false) // After this user needs to confirm phone number again - ; +; if (empty($passwordUpdate)) { $user @@ -2166,7 +2120,6 @@ App::patch('/v1/account/prefs') ->inject('dbForProject') ->inject('events') ->action(function (array $prefs, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) { - $user->setAttribute('prefs', $prefs); $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); @@ -2197,7 +2150,6 @@ App::patch('/v1/account/status') ->inject('dbForProject') ->inject('events') ->action(function (?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) { - $user->setAttribute('status', false); $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); @@ -2206,15 +2158,14 @@ App::patch('/v1/account/status') ->setParam('userId', $user->getId()) ->setPayload($response->output($user, Response::MODEL_ACCOUNT)); - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([])); } $protocol = $request->getProtocol(); $response - ->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) - ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ; + ->addCookie(Auth::$cookieName.'_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); $response->dynamic($user, Response::MODEL_ACCOUNT); }); @@ -2243,7 +2194,6 @@ App::delete('/v1/account/sessions/:sessionId') ->inject('events') ->inject('project') ->action(function (?string $sessionId, ?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Document $project) { - $protocol = $request->getProtocol(); $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $sessionId = ($sessionId === 'current') @@ -2265,19 +2215,16 @@ App::delete('/v1/account/sessions/:sessionId') if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too $session ->setAttribute('current', true) - ->setAttribute('countryName', $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))) - ; + ->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))); - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response - ->addHeader('X-Fallback-Cookies', \json_encode([])) - ; + ->addHeader('X-Fallback-Cookies', \json_encode([])); } $response - ->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) - ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ; + ->addCookie(Auth::$cookieName.'_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); } $dbForProject->deleteCachedDocument('users', $user->getId()); @@ -2285,8 +2232,8 @@ App::delete('/v1/account/sessions/:sessionId') $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()) - ->setPayload($response->output($session, Response::MODEL_SESSION)) - ; + ->setPayload($response->output($session, Response::MODEL_SESSION)); + return $response->noContent(); } } @@ -2340,12 +2287,12 @@ App::patch('/v1/account/sessions/:sessionId') $provider = $session->getAttribute('provider'); $refreshToken = $session->getAttribute('providerRefreshToken'); - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? ''; + $appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}'; - $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); + $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); - if (!\class_exists($className)) { + if (! \class_exists($className)) { throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } @@ -2356,7 +2303,7 @@ App::patch('/v1/account/sessions/:sessionId') $session ->setAttribute('providerAccessToken', $oauth2->getAccessToken('')) ->setAttribute('providerRefreshToken', $oauth2->getRefreshToken('')) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $oauth2->getAccessTokenExpiry(''))); $dbForProject->updateDocument('sessions', $sessionId, $session); @@ -2369,8 +2316,7 @@ App::patch('/v1/account/sessions/:sessionId') $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()) - ->setPayload($response->output($session, Response::MODEL_SESSION)) - ; + ->setPayload($response->output($session, Response::MODEL_SESSION)); return $response->dynamic($session, Response::MODEL_SESSION); } @@ -2400,29 +2346,27 @@ App::delete('/v1/account/sessions') ->inject('locale') ->inject('events') ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events) { - $protocol = $request->getProtocol(); $sessions = $user->getAttribute('sessions', []); foreach ($sessions as $session) {/** @var Document $session */ $dbForProject->deleteDocument('sessions', $session->getId()); - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([])); } $session ->setAttribute('current', false) - ->setAttribute('countryName', $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))) - ; + ->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))); if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { $session->setAttribute('current', true); $session->setAttribute('expire', DateTime::addSeconds(new \DateTime($session->getCreatedAt()), Auth::TOKEN_EXPIRATION_LOGIN_LONG)); - // If current session delete the cookies too + // If current session delete the cookies too $response - ->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName.'_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); // Use current session for events. @@ -2467,7 +2411,6 @@ App::post('/v1/account/recovery') ->inject('mails') ->inject('events') ->action(function (string $email, string $url, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Mail $mails, Event $events) { - if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); } @@ -2482,7 +2425,7 @@ App::post('/v1/account/recovery') Query::equal('email', [$email]), ]); - if (!$profile) { + if (! $profile) { throw new Exception(Exception::USER_NOT_FOUND); } @@ -2523,12 +2466,12 @@ App::post('/v1/account/recovery') $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); - $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); - $subject = $locale->getText("emails.recovery.subject"); + $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); + $subject = $locale->getText('emails.recovery.subject'); $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; - $customTemplate = $project->getAttribute('templates', [])['email.recovery-' . $locale->default] ?? []; - if ($smtpEnabled && !empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['email.recovery-'.$locale->default] ?? []; + if ($smtpEnabled && ! empty($customTemplate)) { $body = $customTemplate['message'] ?? $body; $subject = $customTemplate['subject'] ?? $subject; $from = $customTemplate['senderName'] ?? $from; @@ -2536,13 +2479,13 @@ App::post('/v1/account/recovery') $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.recovery.hello")) + ->setParam('{{hello}}', $locale->getText('emails.recovery.hello')) ->setParam('{{name}}', $profile->getAttribute('name')) - ->setParam('{{body}}', $locale->getText("emails.recovery.body")) + ->setParam('{{body}}', $locale->getText('emails.recovery.body')) ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText("emails.recovery.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.recovery.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.recovery.signature")) + ->setParam('{{footer}}', $locale->getText('emails.recovery.footer')) + ->setParam('{{thanks}}', $locale->getText('emails.recovery.thanks')) + ->setParam('{{signature}}', $locale->getText('emails.recovery.signature')) ->setParam('{{project}}', $projectName) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -2551,7 +2494,6 @@ App::post('/v1/account/recovery') $body = $body->render(); - $mails ->setRecipient($profile->getAttribute('email', '')) ->setName($profile->getAttribute('name')) @@ -2559,7 +2501,6 @@ App::post('/v1/account/recovery') ->setFrom($from) ->setSubject($subject) ->trigger(); - ; $events ->setParam('userId', $profile->getId()) @@ -2568,8 +2509,7 @@ App::post('/v1/account/recovery') ->setPayload($response->output( $recovery->setAttribute('secret', $secret), Response::MODEL_TOKEN - )) - ; + )); // Hide secret for clients $recovery->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : ''); @@ -2619,7 +2559,7 @@ App::put('/v1/account/recovery') $tokens = $profile->getAttribute('tokens', []); $recovery = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_RECOVERY, $secret); - if (!$recovery) { + if (! $recovery) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -2631,7 +2571,7 @@ App::put('/v1/account/recovery') $history = $profile->getAttribute('passwordHistory', []); if ($historyLimit > 0) { $validator = new PasswordHistory($history, $profile->getAttribute('hash'), $profile->getAttribute('hashOptions')); - if (!$validator->isValid($password)) { + if (! $validator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED); } @@ -2660,8 +2600,7 @@ App::put('/v1/account/recovery') $events ->setParam('userId', $profile->getId()) - ->setParam('tokenId', $recoveryDocument->getId()) - ; + ->setParam('tokenId', $recoveryDocument->getId()); $response->dynamic($recoveryDocument, Response::MODEL_TOKEN); }); @@ -2682,7 +2621,7 @@ App::post('/v1/account/verification') ->label('sdk.response.model', Response::MODEL_TOKEN) ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},userId:{userId}') - ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page + ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page ->inject('request') ->inject('response') ->inject('project') @@ -2692,7 +2631,6 @@ App::post('/v1/account/verification') ->inject('events') ->inject('mails') ->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $events, Mail $mails) { - if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); } @@ -2731,12 +2669,12 @@ App::post('/v1/account/verification') $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); - $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); - $subject = $locale->getText("emails.verification.subject"); + $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); + $subject = $locale->getText('emails.verification.subject'); $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; - $customTemplate = $project->getAttribute('templates', [])['email.verification-' . $locale->default] ?? []; - if ($smtpEnabled && !empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['email.verification-'.$locale->default] ?? []; + if ($smtpEnabled && ! empty($customTemplate)) { $body = $customTemplate['message'] ?? $body; $subject = $customTemplate['subject'] ?? $subject; $from = $customTemplate['senderName'] ?? $from; @@ -2744,13 +2682,13 @@ App::post('/v1/account/verification') $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.verification.hello")) + ->setParam('{{hello}}', $locale->getText('emails.verification.hello')) ->setParam('{{name}}', $user->getAttribute('name')) - ->setParam('{{body}}', $locale->getText("emails.verification.body")) + ->setParam('{{body}}', $locale->getText('emails.verification.body')) ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText("emails.verification.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.verification.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.verification.signature")) + ->setParam('{{footer}}', $locale->getText('emails.verification.footer')) + ->setParam('{{thanks}}', $locale->getText('emails.verification.thanks')) + ->setParam('{{signature}}', $locale->getText('emails.verification.signature')) ->setParam('{{project}}', $projectName) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -2765,8 +2703,7 @@ App::post('/v1/account/verification') ->setFrom($from) ->setRecipient($user->getAttribute('email')) ->setName($user->getAttribute('name') ?? '') - ->trigger() - ; + ->trigger(); $events ->setParam('userId', $user->getId()) @@ -2774,8 +2711,7 @@ App::post('/v1/account/verification') ->setPayload($response->output( $verification->setAttribute('secret', $verificationSecret), Response::MODEL_TOKEN - )) - ; + )); // Hide secret for clients $verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $verificationSecret : ''); @@ -2808,8 +2744,7 @@ App::put('/v1/account/verification') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $events) { - - $profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); + $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -2818,7 +2753,7 @@ App::put('/v1/account/verification') $tokens = $profile->getAttribute('tokens', []); $verification = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_VERIFICATION, $secret); - if (!$verification) { + if (! $verification) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -2839,8 +2774,7 @@ App::put('/v1/account/verification') $events ->setParam('userId', $userId) - ->setParam('tokenId', $verificationDocument->getId()) - ; + ->setParam('tokenId', $verificationDocument->getId()); $response->dynamic($verificationDocument, Response::MODEL_TOKEN); }); @@ -2870,7 +2804,6 @@ App::post('/v1/account/verification/phone') ->inject('project') ->inject('locale') ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events, EventPhone $messaging, Document $project, Locale $locale) { - if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED); } @@ -2907,10 +2840,10 @@ App::post('/v1/account/verification/phone') $dbForProject->deleteCachedDocument('users', $user->getId()); - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl'); + $message = Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl'); - $customTemplate = $project->getAttribute('templates', [])['sms.verification-' . $locale->default] ?? []; - if (!empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['sms.verification-'.$locale->default] ?? []; + if (! empty($customTemplate)) { $message = $customTemplate['message'] ?? $message; } @@ -2920,8 +2853,7 @@ App::post('/v1/account/verification/phone') $messaging ->setRecipient($user->getAttribute('phone')) ->setMessage($message) - ->trigger() - ; + ->trigger(); $events ->setParam('userId', $user->getId()) @@ -2929,8 +2861,7 @@ App::post('/v1/account/verification/phone') ->setPayload($response->output( $verification->setAttribute('secret', $secret), Response::MODEL_TOKEN - )) - ; + )); // Hide secret for clients $verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : ''); @@ -2963,8 +2894,7 @@ App::put('/v1/account/verification/phone') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $events) { - - $profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); + $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -2972,7 +2902,7 @@ App::put('/v1/account/verification/phone') $verification = Auth::phoneTokenVerify($user->getAttribute('tokens', []), $secret); - if (!$verification) { + if (! $verification) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -2992,8 +2922,7 @@ App::put('/v1/account/verification/phone') $events ->setParam('userId', $user->getId()) - ->setParam('tokenId', $verificationDocument->getId()) - ; + ->setParam('tokenId', $verificationDocument->getId()); $response->dynamic($verificationDocument, Response::MODEL_TOKEN); }); @@ -3032,7 +2961,7 @@ App::post('/v1/account/targets') $target = $dbForProject->getDocument('targets', $targetId); - if (!$target->isEmpty()) { + if (! $target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } @@ -3040,7 +2969,7 @@ App::post('/v1/account/targets') '$id' => $targetId, // TO DO: what permissions should be given when created a target. '$permissions' => [ - Permission::read(Role::any()) + Permission::read(Role::any()), ], 'providerId' => $providerId, 'providerInternalId' => $provider->getInternalId(), @@ -3076,7 +3005,6 @@ App::patch('/v1/account/targets/:targetId/identifier') ->inject('dbForProject') ->inject('events') ->action(function (string $targetId, string $userId, string $identifier, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -3121,7 +3049,6 @@ App::delete('/v1/account/targets/:targetId') ->inject('dbForProject') ->inject('events') ->action(function (string $targetId, string $userId, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 0be2e0d849..047d99823e 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -1,7 +1,6 @@ output($output, $quality); $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT') ->setContentType('image/png') ->file($data); unset($image); @@ -83,12 +82,12 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro $accessTokenExpiry = $gitHubSession->getAttribute('providerAccessTokenExpiry'); $refreshToken = $gitHubSession->getAttribute('providerRefreshToken'); - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? ''; + $appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}'; - $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); + $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); - if (!\class_exists($className)) { + if (! \class_exists($className)) { throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } @@ -105,13 +104,13 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro $verificationId = $oauth2->getUserID($accessToken); if (empty($verificationId)) { - throw new \Exception("Locked tokens."); // Race codition, handeled in catch + throw new \Exception('Locked tokens.'); // Race codition, handeled in catch } $gitHubSession ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $oauth2->getAccessTokenExpiry(''))); Authorization::skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession)); @@ -150,7 +149,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro return [ 'name' => $githubUser, - 'id' => $githubId + 'id' => $githubId, ]; } catch (Exception $error) { if ($logger) { @@ -177,7 +176,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); $responseCode = $logger->addLog($log); - Console::info('GitHub error log pushed with status code: ' . $responseCode); + Console::info('GitHub error log pushed with status code: '.$responseCode); } Console::warning("Failed: {$error->getMessage()}"); @@ -202,12 +201,12 @@ App::get('/v1/avatars/credit-cards/:code') ->label('sdk.description', '/docs/references/avatars/get-credit-card.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG) - ->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: ' . \implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))) . '.') + ->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: '.\implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))).'.') ->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true) ->inject('response') - ->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('credit-cards', $code, $width, $height, $quality, $response)); + ->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('credit-cards', $code, $width, $height, $quality, $response)); App::get('/v1/avatars/browsers/:code') ->desc('Get Browser Icon') @@ -267,18 +266,17 @@ App::get('/v1/avatars/image') ->param('height', 400, new Range(0, 2000), 'Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.', true) ->inject('response') ->action(function (string $url, int $width, int $height, Response $response) { - $quality = 80; $output = 'png'; $type = 'png'; - if (!\extension_loaded('imagick')) { + if (! \extension_loaded('imagick')) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); } $fetch = @\file_get_contents($url, false); - if (!$fetch) { + if (! $fetch) { throw new Exception(Exception::AVATAR_IMAGE_NOT_FOUND); } @@ -293,7 +291,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('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT') ->setContentType('image/png') ->file($data); unset($image); @@ -315,14 +313,13 @@ App::get('/v1/avatars/favicon') ->param('url', '', new URL(['http', 'https']), 'Website URL which you want to fetch the favicon from.') ->inject('response') ->action(function (string $url, Response $response) { - $width = 56; $height = 56; $quality = 80; $output = 'png'; $type = 'png'; - if (!\extension_loaded('imagick')) { + if (! \extension_loaded('imagick')) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); } @@ -344,7 +341,7 @@ App::get('/v1/avatars/favicon') \curl_close($curl); - if (!$html) { + if (! $html) { throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED); } @@ -395,7 +392,7 @@ App::get('/v1/avatars/favicon') if (empty($outputHref) || empty($outputExt)) { $default = \parse_url($url); - $outputHref = $default['scheme'] . '://' . $default['host'] . '/favicon.ico'; + $outputHref = $default['scheme'].'://'.$default['host'].'/favicon.ico'; $outputExt = 'ico'; } @@ -406,14 +403,14 @@ 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('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT') ->setContentType('image/x-icon') ->file($data); } $fetch = @\file_get_contents($outputHref, false); - if (!$fetch) { + if (! $fetch) { throw new Exception(Exception::AVATAR_ICON_NOT_FOUND); } @@ -423,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('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT') ->setContentType('image/png') ->file($data); unset($image); @@ -446,7 +443,6 @@ App::get('/v1/avatars/qr') ->param('download', false, new Boolean(true), 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true) ->inject('response') ->action(function (string $text, int $size, int $margin, bool $download, Response $response) { - $download = ($download === '1' || $download === 'true' || $download === 1 || $download === true); $options = new QROptions([ 'addQuietzone' => true, @@ -464,7 +460,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('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache ->setContentType('image/png') ->send($image->output('png', 9)); }); @@ -488,17 +484,16 @@ App::get('/v1/avatars/initials') ->inject('response') ->inject('user') ->action(function (string $name, int $width, int $height, string $background, Response $response, Document $user) { - $themes = [ ['background' => '#FFA1CE'], // Default (Pink) ['background' => '#FDC584'], // Orange ['background' => '#94DBD1'], // Green ['background' => '#A1C4FF'], // Blue ['background' => '#FFA1CE'], // Pink - ['background' => '#CBB1FC'] // Purple + ['background' => '#CBB1FC'], // Purple ]; - $name = (!empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', '')); + $name = (! empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', '')); $words = \explode(' ', \strtoupper($name)); // if there is no space, try to split by `_` underscore $words = (count($words) == 1) ? \explode('_', \strtoupper($name)) : $words; @@ -520,7 +515,7 @@ App::get('/v1/avatars/initials') // Wrap rand value to avoid out of range $rand = ($rand > \count($themes) - 1) ? $rand % \count($themes) : $rand; - $background = (!empty($background)) ? '#' . $background : $themes[$rand]['background']; + $background = (! empty($background)) ? '#'.$background : $themes[$rand]['background']; $image = new \Imagick(); $punch = new \Imagick(); @@ -529,8 +524,8 @@ App::get('/v1/avatars/initials') $punch->newImage($width, $height, 'transparent'); - $draw->setFont(__DIR__ . "/../../assets/fonts/poppins-v9-latin-500.ttf"); - $image->setFont(__DIR__ . "/../../assets/fonts/poppins-v9-latin-500.ttf"); + $draw->setFont(__DIR__.'/../../assets/fonts/poppins-v9-latin-500.ttf'); + $image->setFont(__DIR__.'/../../assets/fonts/poppins-v9-latin-500.ttf'); $draw->setFillColor(new ImagickPixel('black')); $draw->setFontSize($fontSize); @@ -542,13 +537,13 @@ App::get('/v1/avatars/initials') $punch->negateImage(true, Imagick::CHANNEL_ALPHA); $image->newImage($width, $height, $background); - $image->setImageFormat("png"); + $image->setImageFormat('png'); $image->compositeImage($punch, Imagick::COMPOSITE_COPYOPACITY, 0, 0); //$image->setImageCompressionQuality(9 - round(($quality / 100) * 9)); $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache ->setContentType('image/png') ->file($image->getImageBlob()); }); @@ -582,7 +577,7 @@ App::get('/v1/cards/cloud') throw new Exception(Exception::USER_NOT_FOUND); } - if (!$mock) { + if (! $mock) { $name = $user->getAttribute('name', 'Anonymous'); $email = $user->getAttribute('email', ''); $createdAt = new \DateTime($user->getCreatedAt()); @@ -602,9 +597,9 @@ App::get('/v1/cards/cloud') $createdAt = new \DateTime($employees[$email]['memberSince'] ?? ''); } - if (!$isEmployee && !empty($githubName)) { + if (! $isEmployee && ! empty($githubName)) { $employeeGitHub = \array_search(\strtolower($githubName), \array_map(fn ($employee) => \strtolower($employee['gitHub']) ?? '', $employees)); - if (!empty($employeeGitHub)) { + if (! empty($employeeGitHub)) { $isEmployee = true; $employeeNumber = $isEmployee ? $employees[$employeeGitHub]['spot'] : ''; $createdAt = new \DateTime($employees[$employeeGitHub]['memberSince'] ?? ''); @@ -645,20 +640,20 @@ App::get('/v1/cards/cloud') $isGolden = $isEmployee || $isHero || $isContributor; $isPlatinum = $isGolden ? false : $isPlatinum; - $memberSince = \strtoupper('Member since ' . $createdAt->format('M') . ' ' . $createdAt->format('d') . ', ' . $createdAt->format('o')); + $memberSince = \strtoupper('Member since '.$createdAt->format('M').' '.$createdAt->format('d').', '.$createdAt->format('o')); $imagePath = $isGolden ? 'front-golden.png' : ($isPlatinum ? 'front-platinum.png' : 'front.png'); - $baseImage = new \Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $imagePath); + $baseImage = new \Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$imagePath); if ($isEmployee) { - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/employee.png'); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/employee.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 793, 35); $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf'); + $text->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf'); $text->setFillColor(new \ImagickPixel('#FFFADF')); $text->setFontSize(\strlen($employeeNumber) <= 2 ? 54 : 48); $text->setFontWeight(700); @@ -666,7 +661,7 @@ App::get('/v1/cards/cloud') $hashtag = new \ImagickDraw(); $hashtag->setTextAlignment(Imagick::ALIGN_CENTER); - $hashtag->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf'); + $hashtag->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf'); $hashtag->setFillColor(new \ImagickPixel('#FFFADF')); $hashtag->setFontSize(28); $hashtag->setFontWeight(700); @@ -689,25 +684,25 @@ App::get('/v1/cards/cloud') } if ($isContributor) { - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/contributor.png'); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/contributor.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 793, 34); } if ($isHero) { - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/hero.png'); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/hero.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 793, 34); } - setlocale(LC_ALL, "en_US.utf8"); + setlocale(LC_ALL, 'en_US.utf8'); // $name = \iconv("utf-8", "ascii//TRANSLIT", $name); // $memberSince = \iconv("utf-8", "ascii//TRANSLIT", $memberSince); // $githubName = \iconv("utf-8", "ascii//TRANSLIT", $githubName); $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__ . '/../../../public/fonts/Poppins-Bold.ttf'); + $text->setFont(__DIR__.'/../../../public/fonts/Poppins-Bold.ttf'); $text->setFillColor(new \ImagickPixel('#FFFFFF')); if (\strlen($name) > 32) { @@ -726,17 +721,17 @@ App::get('/v1/cards/cloud') $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__ . '/../../../public/fonts/Inter-SemiBold.ttf'); + $text->setFont(__DIR__.'/../../../public/fonts/Inter-SemiBold.ttf'); $text->setFillColor(new \ImagickPixel($isGolden || $isPlatinum ? '#FFFFFF' : '#FFB9CC')); $text->setFontSize(27); $text->setFontWeight(600); $text->setTextKerning(1.08); $baseImage->annotateImage($text, 512, 541, 0, \strtoupper($memberSince)); - if (!empty($githubName)) { + if (! empty($githubName)) { $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__ . '/../../../public/fonts/Inter-Regular.ttf'); + $text->setFont(__DIR__.'/../../../public/fonts/Inter-Regular.ttf'); $text->setFillColor(new \ImagickPixel('#FFFFFF')); $text->setFontSize($scalingDown ? 28 : 32); $text->setFontWeight(400); @@ -744,18 +739,18 @@ App::get('/v1/cards/cloud') $baseImage->annotateImage($text, 512 + 20 + 4, 373 + ($scalingDown ? 2 : 0), 0, $githubName); - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github.png'); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $precisionFix = 5; $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 512 - ($metrics['textWidth'] / 2) - 20 - 4, 373 - ($metrics['textHeight'] - $precisionFix)); } - if (!empty($width) || !empty($height)) { + if (! empty($width) || ! empty($height)) { $baseImage->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1); } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache ->setContentType('image/png') ->file($baseImage->getImageBlob()); }); @@ -789,7 +784,7 @@ App::get('/v1/cards/cloud-back') throw new Exception(Exception::USER_NOT_FOUND); } - if (!$mock) { + if (! $mock) { $userId = $user->getId(); $email = $user->getAttribute('email', ''); @@ -809,31 +804,31 @@ App::get('/v1/cards/cloud-back') $isPlatinum = $mock === 'platinum'; } - $userId = 'UID ' . $userId; + $userId = 'UID '.$userId; $isPlatinum = $isGolden ? false : $isPlatinum; $imagePath = $isGolden ? 'back-golden.png' : ($isPlatinum ? 'back-platinum.png' : 'back.png'); - $baseImage = new \Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $imagePath); + $baseImage = new \Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$imagePath); - setlocale(LC_ALL, "en_US.utf8"); + setlocale(LC_ALL, 'en_US.utf8'); // $userId = \iconv("utf-8", "ascii//TRANSLIT", $userId); $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__ . '/../../../public/fonts/SourceCodePro-Regular.ttf'); + $text->setFont(__DIR__.'/../../../public/fonts/SourceCodePro-Regular.ttf'); $text->setFillColor(new \ImagickPixel($isGolden ? '#664A1E' : ($isPlatinum ? '#555555' : '#E8E9F0'))); $text->setFontSize(28); $text->setFontWeight(400); $baseImage->annotateImage($text, 512, 596, 0, $userId); - if (!empty($width) || !empty($height)) { + if (! empty($width) || ! empty($height)) { $baseImage->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1); } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache ->setContentType('image/png') ->file($baseImage->getImageBlob()); }); @@ -867,7 +862,7 @@ App::get('/v1/cards/cloud-og') throw new Exception(Exception::USER_NOT_FOUND); } - if (!$mock) { + if (! $mock) { $internalId = $user->getInternalId(); $bgVariation = $internalId % 3 === 0 ? '1' : ($internalId % 3 === 1 ? '2' : '3'); $cardVariation = $internalId % 3 === 0 ? '1' : ($internalId % 3 === 1 ? '2' : '3'); @@ -891,9 +886,9 @@ App::get('/v1/cards/cloud-og') $createdAt = new \DateTime($employees[$email]['memberSince'] ?? ''); } - if (!$isEmployee && !empty($githubName)) { + if (! $isEmployee && ! empty($githubName)) { $employeeGitHub = \array_search(\strtolower($githubName), \array_map(fn ($employee) => \strtolower($employee['gitHub']) ?? '', $employees)); - if (!empty($employeeGitHub)) { + if (! empty($employeeGitHub)) { $isEmployee = true; $employeeNumber = $isEmployee ? $employees[$employeeGitHub]['spot'] : ''; $createdAt = new \DateTime($employees[$employeeGitHub]['memberSince'] ?? ''); @@ -940,17 +935,17 @@ App::get('/v1/cards/cloud-og') $isGolden = $isEmployee || $isHero || $isContributor; $isPlatinum = $isGolden ? false : $isPlatinum; - $memberSince = \strtoupper('Member since ' . $createdAt->format('M') . ' ' . $createdAt->format('d') . ', ' . $createdAt->format('o')); + $memberSince = \strtoupper('Member since '.$createdAt->format('M').' '.$createdAt->format('d').', '.$createdAt->format('o')); - $baseImage = new \Imagick(__DIR__ . "/../../../public/images/cards/cloud/og-background{$bgVariation}.png"); + $baseImage = new \Imagick(__DIR__."/../../../public/images/cards/cloud/og-background{$bgVariation}.png"); $cardType = $isGolden ? '-golden' : ($isPlatinum ? '-platinum' : ''); - $image = new Imagick(__DIR__ . "/../../../public/images/cards/cloud/og-card{$cardType}{$cardVariation}.png"); + $image = new Imagick(__DIR__."/../../../public/images/cards/cloud/og-card{$cardType}{$cardVariation}.png"); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 1008 / 2 - $image->getImageWidth() / 2, 1008 / 2 - $image->getImageHeight() / 2); - $imageLogo = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/og-background-logo.png'); - $imageShadow = new Imagick(__DIR__ . "/../../../public/images/cards/cloud/og-shadow{$cardType}.png"); + $imageLogo = new Imagick(__DIR__.'/../../../public/images/cards/cloud/og-background-logo.png'); + $imageShadow = new Imagick(__DIR__."/../../../public/images/cards/cloud/og-shadow{$cardType}.png"); if ($cardVariation === '1') { $baseImage->compositeImage($imageLogo, Imagick::COMPOSITE_OVER, 32, 1008 - $imageLogo->getImageHeight() - 32); $baseImage->compositeImage($imageShadow, Imagick::COMPOSITE_OVER, -450, 700); @@ -964,19 +959,19 @@ App::get('/v1/cards/cloud-og') if ($isEmployee) { $file = $cardVariation === '3' ? 'employee-skew.png' : 'employee.png'; - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $file); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$file); $image->setGravity(Imagick::GRAVITY_CENTER); $hashtag = new \ImagickDraw(); $hashtag->setTextAlignment(Imagick::ALIGN_LEFT); - $hashtag->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf'); + $hashtag->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf'); $hashtag->setFillColor(new \ImagickPixel('#FFFADF')); $hashtag->setFontSize(20); $hashtag->setFontWeight(700); $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_LEFT); - $text->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf'); + $text->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf'); $text->setFillColor(new \ImagickPixel('#FFFADF')); $text->setFontSize(\strlen($employeeNumber) <= 1 ? 36 : 28); $text->setFontWeight(700); @@ -1050,7 +1045,7 @@ App::get('/v1/cards/cloud-og') if ($isContributor) { $file = $cardVariation === '3' ? 'contributor-skew.png' : 'contributor.png'; - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $file); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$file); $image->setGravity(Imagick::GRAVITY_CENTER); if ($cardVariation === '1') { @@ -1068,7 +1063,7 @@ App::get('/v1/cards/cloud-og') if ($isHero) { $file = $cardVariation === '3' ? 'hero-skew.png' : 'hero.png'; - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $file); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$file); $image->setGravity(Imagick::GRAVITY_CENTER); if ($cardVariation === '1') { @@ -1084,14 +1079,14 @@ App::get('/v1/cards/cloud-og') } } - setlocale(LC_ALL, "en_US.utf8"); + setlocale(LC_ALL, 'en_US.utf8'); // $name = \iconv("utf-8", "ascii//TRANSLIT", $name); // $memberSince = \iconv("utf-8", "ascii//TRANSLIT", $memberSince); // $githubName = \iconv("utf-8", "ascii//TRANSLIT", $githubName); $textName = new \ImagickDraw(); $textName->setTextAlignment(Imagick::ALIGN_CENTER); - $textName->setFont(__DIR__ . '/../../../public/fonts/Poppins-Bold.ttf'); + $textName->setFont(__DIR__.'/../../../public/fonts/Poppins-Bold.ttf'); $textName->setFillColor(new \ImagickPixel('#FFFFFF')); if (\strlen($name) > 32) { @@ -1128,7 +1123,7 @@ App::get('/v1/cards/cloud-og') $textMember = new \ImagickDraw(); $textMember->setTextAlignment(Imagick::ALIGN_CENTER); - $textMember->setFont(__DIR__ . '/../../../public/fonts/Inter-Medium.ttf'); + $textMember->setFont(__DIR__.'/../../../public/fonts/Inter-Medium.ttf'); $textMember->setFillColor(new \ImagickPixel($isGolden || $isPlatinum ? '#FFFFFF' : '#FFB9CC')); $textMember->setFontWeight(500); $textMember->setTextKerning(1.12); @@ -1158,10 +1153,10 @@ App::get('/v1/cards/cloud-og') $baseImage->drawImage($textMember); } - if (!empty($githubName)) { + if (! empty($githubName)) { $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_LEFT); - $text->setFont(__DIR__ . '/../../../public/fonts/Inter-Regular.ttf'); + $text->setFont(__DIR__.'/../../../public/fonts/Inter-Regular.ttf'); $text->setFillColor(new \ImagickPixel('#FFFFFF')); $text->setFontSize($scalingDown ? 16 : 20); $text->setFontWeight(400); @@ -1172,7 +1167,7 @@ App::get('/v1/cards/cloud-og') $group = new Imagick(); $groupWidth = $metrics['textWidth'] + 32 + 4; $group->newImage($groupWidth, $metrics['textHeight'] + 10, '#00000000'); - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github.png'); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $image->resizeImage(32, 32, Imagick::FILTER_LANCZOS, 1); $precisionFix = -1; @@ -1190,7 +1185,7 @@ App::get('/v1/cards/cloud-og') $group = new Imagick(); $groupWidth = $metrics['textWidth'] + 32 + 4; $group->newImage($groupWidth, $metrics['textHeight'] + 10, '#00000000'); - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github.png'); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $image->resizeImage(32, 32, Imagick::FILTER_LANCZOS, 1); $precisionFix = -1; @@ -1210,7 +1205,7 @@ App::get('/v1/cards/cloud-og') $text->annotation(320 + 15 + 2, 640, $githubName); $metrics = $baseImage->queryFontMetrics($text, $githubName); - $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github-skew.png'); + $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github-skew.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 512 - ($metrics['textWidth'] / 2), 518 + \strlen($githubName) * 1.3); @@ -1218,12 +1213,12 @@ App::get('/v1/cards/cloud-og') } } - if (!empty($width) || !empty($height)) { + if (! empty($width) || ! empty($height)) { $baseImage->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1); } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache ->setContentType('image/png') ->file($baseImage->getImageBlob()); }); diff --git a/app/controllers/api/console.php b/app/controllers/api/console.php index f2ea83af58..846964cad6 100644 --- a/app/controllers/api/console.php +++ b/app/controllers/api/console.php @@ -15,7 +15,6 @@ App::init() } }); - App::get('/v1/console/variables') ->desc('Get Variables') ->groups(['api', 'projects']) @@ -29,7 +28,6 @@ App::get('/v1/console/variables') ->label('sdk.response.model', Response::MODEL_CONSOLE_VARIABLES) ->inject('response') ->action(function (Response $response) { - $variables = new Document([ '_APP_DOMAIN_TARGET' => App::getEnv('_APP_DOMAIN_TARGET'), '_APP_STORAGE_LIMIT' => +App::getEnv('_APP_STORAGE_LIMIT'), @@ -40,7 +38,6 @@ App::get('/v1/console/variables') $response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES); }); - App::post('/v1/console/assistant') ->desc('Ask Query') ->groups(['api', 'assistant']) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index aa7999b844..8f1868f17e 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -17,9 +17,7 @@ use MaxMind\Db\Reader; use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; -use Utopia\Database\Adapter\MariaDB; use Utopia\Database\Database; -use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Authorization as AuthorizationException; use Utopia\Database\Exception\Duplicate as DuplicateException; @@ -46,8 +44,8 @@ use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\FloatValidator; -use Utopia\Validator\IP; use Utopia\Validator\Integer; +use Utopia\Validator\IP; use Utopia\Validator\JSON; use Utopia\Validator\Nullable; use Utopia\Validator\Range; @@ -60,6 +58,7 @@ use Utopia\Validator\WhiteList; * * * @return Document Newly created attribute document + * * @throws Exception */ function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $database, Event $events): Document @@ -82,14 +81,14 @@ function createAttribute(string $databaseId, string $collectionId, Document $att throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - if (!empty($format)) { - if (!Structure::hasFormat($format, $type)) { + if (! empty($format)) { + if (! Structure::hasFormat($format, $type)) { throw new Exception(Exception::ATTRIBUTE_FORMAT_UNSUPPORTED, "Format {$format} not available for {$type} attributes."); } } @@ -105,7 +104,7 @@ function createAttribute(string $databaseId, string $collectionId, Document $att if ($type === Database::VAR_RELATIONSHIP) { $options['side'] = Database::RELATION_SIDE_PARENT; - $relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $options['relatedCollection'] ?? ''); + $relatedCollection = $dbForProject->getDocument('database_'.$db->getInternalId(), $options['relatedCollection'] ?? ''); if ($relatedCollection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND, 'The related collection was not found.'); } @@ -113,7 +112,7 @@ function createAttribute(string $databaseId, string $collectionId, Document $att try { $attribute = new Document([ - '$id' => ID::custom($db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key), + '$id' => ID::custom($db->getInternalId().'_'.$collection->getInternalId().'_'.$key), 'key' => $key, 'databaseInternalId' => $db->getInternalId(), 'databaseId' => $db->getId(), @@ -139,13 +138,13 @@ function createAttribute(string $databaseId, string $collectionId, Document $att } catch (LimitException) { throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute limit exceeded'); } catch (\Exception $e) { - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); - $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId()); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); + $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$collection->getInternalId()); throw $e; } - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); - $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId()); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); + $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$collection->getInternalId()); if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) { $twoWayKey = $options['twoWayKey']; @@ -155,7 +154,7 @@ function createAttribute(string $databaseId, string $collectionId, Document $att try { $twoWayAttribute = new Document([ - '$id' => ID::custom($db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $twoWayKey), + '$id' => ID::custom($db->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$twoWayKey), 'key' => $twoWayKey, 'databaseInternalId' => $db->getInternalId(), 'databaseId' => $db->getId(), @@ -183,13 +182,13 @@ function createAttribute(string $databaseId, string $collectionId, Document $att $dbForProject->deleteDocument('attributes', $attribute->getId()); throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute limit exceeded'); } catch (\Exception $e) { - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId()); - $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $relatedCollection->getId()); + $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$relatedCollection->getInternalId()); throw $e; } - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId()); - $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $relatedCollection->getId()); + $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$relatedCollection->getInternalId()); } $database @@ -231,13 +230,13 @@ function updateAttribute( throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $attribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key); + $attribute = $dbForProject->getDocument('attributes', $db->getInternalId().'_'.$collection->getInternalId().'_'.$key); if ($attribute->isEmpty()) { throw new Exception(Exception::ATTRIBUTE_NOT_FOUND); @@ -263,7 +262,7 @@ function updateAttribute( throw new Exception(Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, 'Cannot set default value for array attributes'); } - $collectionId = 'database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId(); + $collectionId = 'database_'.$db->getInternalId().'_collection_'.$collection->getInternalId(); $attribute ->setAttribute('default', $default) @@ -287,18 +286,18 @@ function updateAttribute( } else { $validator = new Range($min, $max, Database::VAR_FLOAT); - if (!is_null($default)) { + if (! is_null($default)) { $default = \floatval($default); } } - if (!is_null($default) && !$validator->isValid($default)) { + if (! is_null($default) && ! $validator->isValid($default)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription()); } $options = [ 'min' => $min, - 'max' => $max + 'max' => $max, ]; $attribute->setAttribute('formatOptions', $options); @@ -314,12 +313,12 @@ function updateAttribute( } } - if (!is_null($default) && !in_array($default, $elements)) { + if (! is_null($default) && ! in_array($default, $elements)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Default value not found in elements'); } $options = [ - 'elements' => $elements + 'elements' => $elements, ]; $attribute->setAttribute('formatOptions', $options); @@ -338,13 +337,13 @@ function updateAttribute( ); if ($primaryDocumentOptions['twoWay']) { - $relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $primaryDocumentOptions['relatedCollection']); + $relatedCollection = $dbForProject->getDocument('database_'.$db->getInternalId(), $primaryDocumentOptions['relatedCollection']); - $relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey']); + $relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$primaryDocumentOptions['twoWayKey']); $relatedOptions = \array_merge($relatedAttribute->getAttribute('options'), $options); $relatedAttribute->setAttribute('options', $relatedOptions); - $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey'], $relatedAttribute); - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId()); + $dbForProject->updateDocument('attributes', $db->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$primaryDocumentOptions['twoWayKey'], $relatedAttribute); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $relatedCollection->getId()); } } else { $dbForProject->updateAttribute( @@ -356,8 +355,8 @@ function updateAttribute( ); } - $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key, $attribute); - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collection->getId()); + $dbForProject->updateDocument('attributes', $db->getInternalId().'_'.$collection->getInternalId().'_'.$key, $attribute); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collection->getId()); $events ->setContext('collection', $collection) @@ -390,7 +389,6 @@ App::post('/v1/databases') ->inject('dbForProject') ->inject('events') ->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) { - $databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId; try { @@ -420,7 +418,7 @@ App::post('/v1/databases') 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '' + 'format' => $attribute['format'] ?? '', ]); } @@ -433,7 +431,7 @@ App::post('/v1/databases') 'orders' => $index['orders'], ]); } - $dbForProject->createCollection('database_' . $database->getInternalId(), $attributes, $indexes); + $dbForProject->createCollection('database_'.$database->getInternalId(), $attributes, $indexes); } catch (DuplicateException) { throw new Exception(Exception::DATABASE_ALREADY_EXISTS); } @@ -456,15 +454,14 @@ App::get('/v1/databases') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DATABASE_LIST) - ->param('queries', [], new Databases(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Databases::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Databases(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Databases::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { - $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -505,7 +502,6 @@ App::get('/v1/databases/:databaseId') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, Response $response, Database $dbForProject) { - $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { @@ -533,7 +529,6 @@ App::get('/v1/databases/:databaseId/logs') ->inject('locale') ->inject('geodb') ->action(function (string $databaseId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { - $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { @@ -546,13 +541,13 @@ App::get('/v1/databases/:databaseId/logs') $offset = $grouped['offset'] ?? 0; $audit = new Audit($dbForProject); - $resource = 'database/' . $databaseId; + $resource = 'database/'.$databaseId; $logs = $audit->getLogsByResource($resource, $limit, $offset); $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -580,14 +575,14 @@ App::get('/v1/databases/:databaseId/logs') 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'] + 'deviceModel' => $device['deviceModel'], ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -600,7 +595,6 @@ App::get('/v1/databases/:databaseId/logs') ]), Response::MODEL_LOG_LIST); }); - App::put('/v1/databases/:databaseId') ->desc('Update Database') ->groups(['api', 'database', 'schema']) @@ -622,7 +616,6 @@ App::put('/v1/databases/:databaseId') ->inject('dbForProject') ->inject('events') ->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) { - $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { @@ -637,7 +630,7 @@ App::put('/v1/databases/:databaseId') } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. ' . $exception->getMessage()); + throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. '.$exception->getMessage()); } $events->setParam('databaseId', $database->getId()); @@ -664,19 +657,18 @@ App::delete('/v1/databases/:databaseId') ->inject('events') ->inject('deletes') ->action(function (string $databaseId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { - $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - if (!$dbForProject->deleteDocument('databases', $databaseId)) { + if (! $dbForProject->deleteDocument('databases', $databaseId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove collection from DB'); } $dbForProject->deleteCachedDocument('databases', $database->getId()); - $dbForProject->deleteCachedCollection('databases_' . $database->getInternalId()); + $dbForProject->deleteCachedCollection('databases_'.$database->getInternalId()); $deletes ->setType(DELETE_TYPE_DOCUMENT) @@ -715,10 +707,9 @@ App::post('/v1/databases/:databaseId/collections') ->inject('mode') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) { + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } @@ -728,7 +719,7 @@ App::post('/v1/databases/:databaseId/collections') $permissions = Permission::aggregate($permissions); try { - $dbForProject->createDocument('database_' . $database->getInternalId(), new Document([ + $dbForProject->createDocument('database_'.$database->getInternalId(), new Document([ '$id' => $collectionId, 'databaseInternalId' => $database->getInternalId(), 'databaseId' => $databaseId, @@ -738,9 +729,9 @@ App::post('/v1/databases/:databaseId/collections') 'name' => $name, 'search' => implode(' ', [$collectionId, $name]), ])); - $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); - $dbForProject->createCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), permissions: $permissions ?? [], documentSecurity: $documentSecurity); + $dbForProject->createCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), permissions: $permissions ?? [], documentSecurity: $documentSecurity); } catch (DuplicateException) { throw new Exception(Exception::COLLECTION_ALREADY_EXISTS); } catch (LimitException) { @@ -770,22 +761,21 @@ App::get('/v1/databases/:databaseId/collections') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_COLLECTION_LIST) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('queries', [], new Collections(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Collections::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Collections(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Collections::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -795,7 +785,7 @@ App::get('/v1/databases/:databaseId/collections') if ($cursor) { /** @var Query $cursor */ $collectionId = $cursor->getValue(); - $cursorDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $cursorDocument = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Collection '{$collectionId}' for the 'cursor' value not found."); @@ -807,8 +797,8 @@ App::get('/v1/databases/:databaseId/collections') $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ - 'collections' => $dbForProject->find('database_' . $database->getInternalId(), $queries), - 'total' => $dbForProject->count('database_' . $database->getInternalId(), $filterQueries, APP_LIMIT_COUNT), + 'collections' => $dbForProject->find('database_'.$database->getInternalId(), $queries), + 'total' => $dbForProject->count('database_'.$database->getInternalId(), $filterQueries, APP_LIMIT_COUNT), ]), Response::MODEL_COLLECTION_LIST); }); @@ -830,14 +820,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId') ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode) { + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -866,14 +855,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') ->inject('locale') ->inject('geodb') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { - - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collectionDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); - $collection = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $collectionDocument->getInternalId()); + $collectionDocument = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getCollection('database_'.$database->getInternalId().'_collection_'.$collectionDocument->getInternalId()); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -885,13 +873,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') $offset = $grouped['offset'] ?? 0; $audit = new Audit($dbForProject); - $resource = 'database/' . $databaseId . '/collection/' . $collectionId; + $resource = 'database/'.$databaseId.'/collection/'.$collectionId; $logs = $audit->getLogsByResource($resource, $limit, $offset); $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -919,14 +907,14 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'] + 'deviceModel' => $device['deviceModel'], ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -939,7 +927,6 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') ]), Response::MODEL_LOG_LIST); }); - App::put('/v1/databases/:databaseId/collections/:collectionId') ->alias('/v1/database/collections/:collectionId', ['databaseId' => 'default']) ->desc('Update Collection') @@ -966,14 +953,13 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->inject('mode') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) { + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -987,17 +973,17 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') $enabled ??= $collection->getAttribute('enabled', true); try { - $collection = $dbForProject->updateDocument('database_' . $database->getInternalId(), $collectionId, $collection + $collection = $dbForProject->updateDocument('database_'.$database->getInternalId(), $collectionId, $collection ->setAttribute('name', $name) ->setAttribute('$permissions', $permissions) ->setAttribute('documentSecurity', $documentSecurity) ->setAttribute('enabled', $enabled) ->setAttribute('search', implode(' ', [$collectionId, $name]))); - $dbForProject->updateCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $permissions, $documentSecurity); + $dbForProject->updateCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $permissions, $documentSecurity); } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. ' . $exception->getMessage()); + throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. '.$exception->getMessage()); } $events @@ -1030,24 +1016,23 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->inject('events') ->inject('deletes') ->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode, Event $events, Delete $deletes) { + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - if (!$dbForProject->deleteDocument('database_' . $database->getInternalId(), $collectionId)) { + if (! $dbForProject->deleteDocument('database_'.$database->getInternalId(), $collectionId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove collection from DB'); } - $dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId()); + $dbForProject->deleteCachedCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId()); $deletes ->setType(DELETE_TYPE_DOCUMENT) @@ -1090,10 +1075,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - // Ensure attribute default is within required size $validator = new Text($size, 0); - if (!is_null($default) && !$validator->isValid($default)) { + if (! is_null($default) && ! $validator->isValid($default)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription()); } @@ -1144,7 +1128,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_STRING, @@ -1178,7 +1161,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') - ->param('elements', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE, min: 0), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' elements are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.') + ->param('elements', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE, min: 0), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' elements are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Text(0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) @@ -1187,7 +1170,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - // use length of longest string as attribute size $size = 0; foreach ($elements as $element) { @@ -1198,7 +1180,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') $size = ($length > $size) ? $length : $size; } - if (!is_null($default) && !in_array($default, $elements)) { + if (! is_null($default) && ! in_array($default, $elements)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Default value not found in elements'); } @@ -1244,7 +1226,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_STRING, @@ -1286,7 +1267,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_STRING, @@ -1330,7 +1310,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - // Ensure attribute default is within range $min = (is_null($min)) ? PHP_INT_MIN : \intval($min); $max = (is_null($max)) ? PHP_INT_MAX : \intval($max); @@ -1341,7 +1320,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege $validator = new Range($min, $max, Database::VAR_INTEGER); - if (!is_null($default) && !$validator->isValid($default)) { + if (! is_null($default) && ! $validator->isValid($default)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription()); } @@ -1363,7 +1342,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege $formatOptions = $attribute->getAttribute('formatOptions', []); - if (!empty($formatOptions)) { + if (! empty($formatOptions)) { $attribute->setAttribute('min', \intval($formatOptions['min'])); $attribute->setAttribute('max', \intval($formatOptions['max'])); } @@ -1401,7 +1380,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - // Ensure attribute default is within range $min = (is_null($min)) ? -PHP_FLOAT_MAX : \floatval($min); $max = (is_null($max)) ? PHP_FLOAT_MAX : \floatval($max); @@ -1411,13 +1389,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' } // Ensure default value is a float - if (!is_null($default)) { + if (! is_null($default)) { $default = \floatval($default); } $validator = new Range($min, $max, Database::VAR_FLOAT); - if (!is_null($default) && !$validator->isValid($default)) { + if (! is_null($default) && ! $validator->isValid($default)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription()); } @@ -1437,7 +1415,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' $formatOptions = $attribute->getAttribute('formatOptions', []); - if (!empty($formatOptions)) { + if (! empty($formatOptions)) { $attribute->setAttribute('min', \floatval($formatOptions['min'])); $attribute->setAttribute('max', \floatval($formatOptions['max'])); } @@ -1473,7 +1451,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_BOOLEAN, @@ -1514,7 +1491,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - $filters[] = 'datetime'; $attribute = createAttribute($databaseId, $collectionId, new Document([ @@ -1593,7 +1569,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati 'twoWay' => $twoWay, 'twoWayKey' => $twoWayKey, 'onDelete' => $onDelete, - ] + ], ]), $response, $dbForProject, @@ -1626,18 +1602,17 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_LIST) ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') - ->param('queries', [], new Attributes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Attributes::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Attributes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Attributes::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject) { - - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -1653,7 +1628,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') if ($cursor) { $attributeId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn() => $dbForProject->find('attributes', [ + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('attributes', [ Query::equal('collectionId', [$collectionId]), Query::equal('databaseId', [$databaseId]), Query::equal('key', [$attributeId]), @@ -1694,27 +1669,26 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') Response::MODEL_ATTRIBUTE_IP, Response::MODEL_ATTRIBUTE_DATETIME, Response::MODEL_ATTRIBUTE_RELATIONSHIP, - Response::MODEL_ATTRIBUTE_STRING])// needs to be last, since its condition would dominate any other string attribute + Response::MODEL_ATTRIBUTE_STRING, ])// needs to be last, since its condition would dominate any other string attribute ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) { - - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $attribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $collection->getInternalId() . '_' . $key); + $attribute = $dbForProject->getDocument('attributes', $database->getInternalId().'_'.$collection->getInternalId().'_'.$key); if ($attribute->isEmpty()) { throw new Exception(Exception::ATTRIBUTE_NOT_FOUND); @@ -1770,7 +1744,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin ->inject('dbForProject') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) { - $attribute = updateAttribute( databaseId: $databaseId, collectionId: $collectionId, @@ -1842,7 +1815,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/enum/ ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') - ->param('elements', null, new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' elements are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.') + ->param('elements', null, new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' elements are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Text(0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.') ->inject('response') @@ -1984,7 +1957,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/integ $formatOptions = $attribute->getAttribute('formatOptions', []); - if (!empty($formatOptions)) { + if (! empty($formatOptions)) { $attribute->setAttribute('min', \intval($formatOptions['min'])); $attribute->setAttribute('max', \intval($formatOptions['max'])); } @@ -2033,7 +2006,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/float $formatOptions = $attribute->getAttribute('formatOptions', []); - if (!empty($formatOptions)) { + if (! empty($formatOptions)) { $attribute->setAttribute('min', \floatval($formatOptions['min'])); $attribute->setAttribute('max', \floatval($formatOptions['max'])); } @@ -2157,7 +2130,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/ type: Database::VAR_RELATIONSHIP, required: false, options: [ - 'onDelete' => $onDelete + 'onDelete' => $onDelete, ] ); @@ -2194,19 +2167,18 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - - $db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $attribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key); + $attribute = $dbForProject->getDocument('attributes', $db->getInternalId().'_'.$collection->getInternalId().'_'.$key); if ($attribute->isEmpty()) { throw new Exception(Exception::ATTRIBUTE_NOT_FOUND); @@ -2217,19 +2189,19 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key $attribute = $dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'deleting')); } - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); - $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId()); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); + $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$collection->getInternalId()); if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) { $options = $attribute->getAttribute('options'); if ($options['twoWay']) { - $relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $options['relatedCollection']); + $relatedCollection = $dbForProject->getDocument('database_'.$db->getInternalId(), $options['relatedCollection']); if ($relatedCollection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']); + $relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$options['twoWayKey']); if ($relatedAttribute->isEmpty()) { throw new Exception(Exception::ATTRIBUTE_NOT_FOUND); @@ -2239,8 +2211,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key $dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'deleting')); } - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $options['relatedCollection']); - $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $options['relatedCollection']); + $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$relatedCollection->getInternalId()); } } @@ -2300,21 +2272,20 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', null, new Key(), 'Index Key.') ->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL, Database::INDEX_ARRAY]), 'Index type.') - ->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.') - ->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true) + ->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' attributes are allowed, each 32 characters long.') + ->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' orders are allowed.', true) ->inject('response') ->inject('dbForProject') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - - $db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -2322,7 +2293,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') $count = $dbForProject->count('indexes', [ Query::equal('collectionInternalId', [$collection->getInternalId()]), - Query::equal('databaseInternalId', [$db->getInternalId()]) + Query::equal('databaseInternalId', [$db->getInternalId()]), ], 61); $limit = $dbForProject->getLimitForIndexes(); @@ -2332,7 +2303,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') } // Convert Document[] to array of attribute metadata - $oldAttributes = \array_map(fn($a) => $a->getArrayCopy(), $collection->getAttribute('attributes')); + $oldAttributes = \array_map(fn ($a) => $a->getArrayCopy(), $collection->getAttribute('attributes')); $oldAttributes[] = [ 'key' => '$id', @@ -2341,7 +2312,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'required' => true, 'array' => false, 'default' => null, - 'size' => 36 + 'size' => 36, ]; $oldAttributes[] = [ @@ -2352,7 +2323,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'required' => false, 'array' => false, 'default' => null, - 'size' => 0 + 'size' => 0, ]; $oldAttributes[] = [ @@ -2363,7 +2334,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'required' => false, 'array' => false, 'default' => null, - 'size' => 0 + 'size' => 0, ]; // lengths hidden by default @@ -2374,7 +2345,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') $attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key')); if ($attributeIndex === false) { - throw new Exception(Exception::ATTRIBUTE_UNKNOWN, 'Unknown attribute: ' . $attribute); + throw new Exception(Exception::ATTRIBUTE_UNKNOWN, 'Unknown attribute: '.$attribute); } $attributeStatus = $oldAttributes[$attributeIndex]['status']; @@ -2382,12 +2353,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') $attributeSize = $oldAttributes[$attributeIndex]['size']; if ($attributeType === Database::VAR_RELATIONSHIP) { - throw new Exception(Exception::ATTRIBUTE_TYPE_INVALID, 'Cannot create an index for a relationship attribute: ' . $oldAttributes[$attributeIndex]['key']); + throw new Exception(Exception::ATTRIBUTE_TYPE_INVALID, 'Cannot create an index for a relationship attribute: '.$oldAttributes[$attributeIndex]['key']); } // ensure attribute is available if ($attributeStatus !== 'available') { - throw new Exception(Exception::ATTRIBUTE_NOT_AVAILABLE, 'Attribute not available: ' . $oldAttributes[$attributeIndex]['key']); + throw new Exception(Exception::ATTRIBUTE_NOT_AVAILABLE, 'Attribute not available: '.$oldAttributes[$attributeIndex]['key']); } // set attribute size as index length only for strings @@ -2395,7 +2366,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') } $index = new Document([ - '$id' => ID::custom($db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key), + '$id' => ID::custom($db->getInternalId().'_'.$collection->getInternalId().'_'.$key), 'key' => $key, 'status' => 'processing', // processing, available, failed, deleting, stuck 'databaseInternalId' => $db->getInternalId(), @@ -2409,7 +2380,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ]); $validator = new IndexValidator($dbForProject->getAdapter()->getMaxIndexLength()); - if (!$validator->isValid($collection->setAttribute('indexes', $index, Document::SET_TYPE_APPEND))) { + if (! $validator->isValid($collection->setAttribute('indexes', $index, Document::SET_TYPE_APPEND))) { throw new Exception(Exception::INDEX_INVALID, $validator->getDescription()); } @@ -2419,7 +2390,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') throw new Exception(Exception::INDEX_ALREADY_EXISTS); } - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); $database ->setType(DATABASE_TYPE_CREATE_INDEX) @@ -2453,18 +2424,17 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') ->label('sdk.response.model', Response::MODEL_INDEX_LIST) ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') - ->param('queries', [], new Indexes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Indexes::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Indexes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Indexes::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject) { - - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -2473,17 +2443,17 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') $queries = Query::parseQueries($queries); \array_push($queries, Query::equal('collectionId', [$collectionId]), Query::equal('databaseId', [$databaseId])); - // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); - $cursor = reset($cursor); + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); if ($cursor) { $indexId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn() => $dbForProject->find('indexes', [ + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('indexes', [ Query::equal('collectionId', [$collectionId]), Query::equal('databaseId', [$databaseId]), Query::equal('key', [$indexId]), - Query::limit(1) + Query::limit(1), ])); if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { @@ -2518,13 +2488,12 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) { - - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -2538,7 +2507,6 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') $response->dynamic($index, Response::MODEL_INDEX); }); - App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->alias('/v1/database/collections/:collectionId/indexes/:key', ['databaseId' => 'default']) ->desc('Delete Index') @@ -2561,19 +2529,18 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - - $db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $index = $dbForProject->getDocument('indexes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key); + $index = $dbForProject->getDocument('indexes', $db->getInternalId().'_'.$collection->getInternalId().'_'.$key); if (empty($index->getId())) { throw new Exception(Exception::INDEX_NOT_FOUND); @@ -2584,7 +2551,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') $index = $dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'deleting')); } - $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); + $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); $database ->setType(DATABASE_TYPE_DELETE_INDEX) @@ -2634,7 +2601,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->inject('events') ->inject('mode') ->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $events, string $mode) { - $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array if (empty($data)) { @@ -2645,16 +2611,16 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, '$id is not allowed for creating new documents, try update instead'); } - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { + if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } } @@ -2671,7 +2637,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') // Add permissions for current the user if none were provided. if (\is_null($permissions)) { $permissions = []; - if (!empty($user->getId())) { + if (! empty($user->getId())) { foreach ($allowedPermissions as $permission) { $permissions[] = (new Permission($permission, 'user', $user->getId()))->toString(); } @@ -2680,7 +2646,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') // Users can only manage their own roles, API keys and Admin users can manage any $roles = Authorization::getRoles(); - if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { + if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -2692,8 +2658,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); + if (! Authorization::isRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')'); } } } @@ -2709,20 +2675,20 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $validator = new Authorization($permission); $valid = $validator->isValid($collection->getPermissionsByType($permission)); - if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$valid) { + if (($permission === Database::PERMISSION_UPDATE && ! $documentSecurity) || ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } if ($permission === Database::PERMISSION_UPDATE) { $valid = $valid || $validator->isValid($document->getUpdate()); - if ($documentSecurity && !$valid) { + if ($documentSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } } $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -2742,21 +2708,21 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) ); foreach ($relations as &$relation) { if ( \is_array($relation) && \array_values($relation) !== $relation - && !isset($relation['$id']) + && ! isset($relation['$id']) ) { $relation['$id'] = ID::unique(); $relation = new Document($relation); } if ($relation instanceof Document) { $current = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId()) + fn () => $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId(), $relation->getId()) ); if ($current->isEmpty()) { @@ -2786,46 +2752,46 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $checkPermissions($collection, $document, Database::PERMISSION_CREATE); - try { - $document = $dbForProject->createDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $document); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); - } catch (DuplicateException $exception) { - throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); - } + try { + $document = $dbForProject->createDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $document); + } catch (StructureException $exception) { + throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); + } catch (DuplicateException $exception) { + throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); + } - // Add $collectionId and $databaseId for all documents - $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { - $document->setAttribute('$databaseId', $database->getId()); - $document->setAttribute('$collectionId', $collection->getId()); + // Add $collectionId and $databaseId for all documents + $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { + $document->setAttribute('$databaseId', $database->getId()); + $document->setAttribute('$collectionId', $collection->getId()); - $relationships = \array_filter( - $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP - ); - - foreach ($relationships as $relationship) { - $related = $document->getAttribute($relationship->getAttribute('key')); - - if (empty($related)) { - continue; - } - if (!\is_array($related)) { - $related = [$related]; - } - - $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + $relationships = \array_filter( + $collection->getAttribute('attributes', []), + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); - foreach ($related as $relation) { - if ($relation instanceof Document) { - $processDocument($relatedCollection, $relation); + foreach ($relationships as $relationship) { + $related = $document->getAttribute($relationship->getAttribute('key')); + + if (empty($related)) { + continue; + } + if (! \is_array($related)) { + $related = [$related]; + } + + $relatedCollectionId = $relationship->getAttribute('relatedCollection'); + $relatedCollection = Authorization::skip( + fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) + ); + + foreach ($related as $relation) { + if ($relation instanceof Document) { + $processDocument($relatedCollection, $relation); + } } } - } - }; + }; $processDocument($collection, $document); @@ -2856,37 +2822,36 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('sdk.offline.model', '/databases/{databaseId}/collections/{collectionId}/documents') ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') - ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) + ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, string $mode) { + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - if (!$collection->getAttribute('documentSecurity', false)) { + if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if (! $collection->getAttribute('documentSecurity', false)) { $validator = new Authorization(Database::PERMISSION_READ); - if (!$validator->isValid($collection->getRead())) { + if (! $validator->isValid($collection->getRead())) { $collection = new Document(); } } } - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { + if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } // Validate queries $queriesValidator = new Documents($collection->getAttribute('attributes'), $collection->getAttribute('indexes')); $validQueries = $queriesValidator->isValid($queries); - if (!$validQueries) { + if (! $validQueries) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $queriesValidator->getDescription()); } @@ -2898,7 +2863,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') if ($cursor) { $documentId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Document '{$documentId}' for the 'cursor' value not found."); @@ -2909,8 +2874,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $filterQueries = Query::groupByType($queries)['filters']; - $documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries); - $total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT); + $documents = $dbForProject->find('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $queries); + $total = $dbForProject->count('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT); // Add $collectionId and $databaseId for all documents $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database): bool { @@ -2924,7 +2889,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -2933,18 +2898,18 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') if (empty($related)) { continue; } - if (!\is_array($related)) { + if (! \is_array($related)) { $relations = [$related]; } else { $relations = $related; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)); + $relatedCollection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId)); foreach ($relations as $index => $doc) { if ($doc instanceof Document) { - if (!$processDocument($relatedCollection, $doc)) { + if (! $processDocument($relatedCollection, $doc)) { unset($relations[$index]); } } @@ -2961,9 +2926,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') }; // The linter is forcing this indentation - foreach ($documents as $document) { - $processDocument($collection, $document); - } + foreach ($documents as $document) { + $processDocument($collection, $document); + } $response->dynamic(new Document([ 'total' => $total, @@ -2993,17 +2958,16 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, string $mode) { + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { + if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } } @@ -3011,13 +2975,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen // Validate queries $queriesValidator = new DocumentQueriesValidator($collection->getAttribute('attributes')); $validQueries = $queriesValidator->isValid($queries); - if (!$validQueries) { + if (! $validQueries) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $queriesValidator->getDescription()); } $queries = Query::parseQueries($queries); - $document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries); + $document = $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId, $queries); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3034,7 +2998,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3043,13 +3007,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen if (empty($related)) { continue; } - if (!\is_array($related)) { + if (! \is_array($related)) { $related = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3086,20 +3050,19 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->inject('locale') ->inject('geodb') ->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { - - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId); + $document = $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3111,13 +3074,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen $offset = $grouped['offset'] ?? 0; $audit = new Audit($dbForProject); - $resource = 'database/' . $databaseId . '/collection/' . $collectionId . '/document/' . $document->getId(); + $resource = 'database/'.$databaseId.'/collection/'.$collectionId.'/document/'.$document->getId(); $logs = $audit->getLogsByResource($resource, $limit, $offset); $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -3145,14 +3108,14 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'] + 'deviceModel' => $device['deviceModel'], ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -3195,30 +3158,29 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->inject('events') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events, string $mode) { - $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array if (empty($data) && \is_null($permissions)) { throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD); } - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { + if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } } // Read permission should not be required for update /** @var Document $document */ - $document = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); + $document = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId)); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3233,7 +3195,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum // Users can only manage their own roles, API keys and Admin users can manage any $roles = Authorization::getRoles(); - if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) { + if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles) && ! \is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -3245,8 +3207,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); + if (! Authorization::isRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')'); } } } @@ -3266,7 +3228,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $setCollection = (function (Document $collection, Document $document) use (&$setCollection, $dbForProject, $database) { $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3286,7 +3248,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) ); foreach ($relations as &$relation) { @@ -3294,14 +3256,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum if ( \is_array($relation) && \array_values($relation) !== $relation - && !isset($relation['$id']) + && ! isset($relation['$id']) ) { $relation['$id'] = ID::unique(); $relation = new Document($relation); } if ($relation instanceof Document) { - $oldDocument = Authorization::skip(fn() => $dbForProject->getDocument( - 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), + $oldDocument = Authorization::skip(fn () => $dbForProject->getDocument( + 'database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId(), $relation->getId() )); $relation->removeAttribute('$collectionId'); @@ -3309,7 +3271,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum // Attribute $collection is required for Utopia. $relation->setAttribute( '$collection', - 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId() + 'database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId() ); if ($oldDocument->isEmpty()) { @@ -3334,8 +3296,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum try { $document = $dbForProject->withRequestTimestamp( $requestTimestamp, - fn() => $dbForProject->updateDocument( - 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), + fn () => $dbForProject->updateDocument( + 'database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $document->getId(), $newDocument ) @@ -3355,7 +3317,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3364,13 +3326,13 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum if (empty($related)) { continue; } - if (!\is_array($related)) { + if (! \is_array($related)) { $related = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3422,23 +3384,22 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->inject('deletes') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events, Delete $deletes, string $mode) { + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { + if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } } // Read permission should not be required for delete - $document = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); + $document = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId)); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3449,18 +3410,18 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu $validator = new Authorization(Database::PERMISSION_DELETE); $valid = $validator->isValid($collection->getDelete()); - if (!$documentSecurity && !$valid) { + if (! $documentSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } $valid = $valid || $validator->isValid($document->getDelete()); - if ($documentSecurity && !$valid) { + if ($documentSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3469,13 +3430,13 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu if (empty($related)) { continue; } - if (!\is_array($related)) { + if (! \is_array($related)) { $related = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3491,10 +3452,10 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu $checkPermissions($collection, $document); - Authorization::skip(fn() => $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) { + Authorization::skip(fn () => $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) { try { $dbForProject->deleteDocument( - 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), + 'database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId ); } catch (RestrictedException) { @@ -3503,7 +3464,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu })); $dbForProject->deleteCachedDocument( - 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), + 'database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId ); @@ -3514,7 +3475,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3523,13 +3484,13 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu if (empty($related)) { continue; } - if (!\is_array($related)) { + if (! \is_array($related)) { $related = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3571,7 +3532,6 @@ App::get('/v1/databases/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { - $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -3605,23 +3565,23 @@ App::get('/v1/databases/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, - 'databasesTotal' => $usage[$metrics[0]], + 'databasesTotal' => $usage[$metrics[0]], 'collectionsTotal' => $usage[$metrics[1]], - 'documentsTotal' => $usage[$metrics[2]], + 'documentsTotal' => $usage[$metrics[2]], ]), Response::MODEL_USAGE_DATABASES); }); @@ -3640,8 +3600,7 @@ App::get('/v1/databases/:databaseId/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $range, Response $response, Database $dbForProject) { - - $database = $dbForProject->getDocument('databases', $databaseId); + $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -3679,23 +3638,23 @@ App::get('/v1/databases/:databaseId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, - 'collectionsTotal' => $usage[$metrics[0]], - 'documentsTotal' => $usage[$metrics[1]], + 'collectionsTotal' => $usage[$metrics[0]], + 'documentsTotal' => $usage[$metrics[1]], ]), Response::MODEL_USAGE_DATABASE); }); @@ -3716,10 +3675,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $range, string $collectionId, Response $response, Database $dbForProject) { - - $database = $dbForProject->getDocument('databases', $databaseId); - $collectionDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); - $collection = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $collectionDocument->getInternalId()); + $database = $dbForProject->getDocument('databases', $databaseId); + $collectionDocument = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getCollection('database_'.$database->getInternalId().'_collection_'.$collectionDocument->getInternalId()); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -3756,21 +3714,21 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, - 'documentsTotal' => $usage[$metrics[0]], + 'documentsTotal' => $usage[$metrics[0]], ]), Response::MODEL_USAGE_COLLECTION); }); diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 81500f1d27..b7baf560bb 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -9,40 +9,40 @@ use Appwrite\Event\Func; use Appwrite\Event\Usage; use Appwrite\Event\Validator\Event as ValidatorEvent; use Appwrite\Extend\Exception; +use Appwrite\Task\Validator\Cron; use Appwrite\Utopia\Database\Validator\CustomId; +use Appwrite\Utopia\Database\Validator\Queries\Deployments; +use Appwrite\Utopia\Database\Validator\Queries\Executions; +use Appwrite\Utopia\Database\Validator\Queries\Functions; +use Appwrite\Utopia\Response; +use Executor\Executor; +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\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Roles; use Utopia\Database\Validator\UID; use Utopia\Storage\Device; use Utopia\Storage\Validator\File; use Utopia\Storage\Validator\FileExt; use Utopia\Storage\Validator\FileSize; use Utopia\Storage\Validator\Upload; -use Appwrite\Utopia\Response; use Utopia\Swoole\Request; -use Appwrite\Task\Validator\Cron; -use Appwrite\Utopia\Database\Validator\Queries\Deployments; -use Appwrite\Utopia\Database\Validator\Queries\Executions; -use Appwrite\Utopia\Database\Validator\Queries\Functions; -use Utopia\App; -use Utopia\Database\Database; -use Utopia\Database\Document; -use Utopia\Database\DateTime; -use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Validator\ArrayList; -use Utopia\Validator\Text; -use Utopia\Validator\Range; -use Utopia\Validator\WhiteList; -use Utopia\Config\Config; -use Executor\Executor; -use Utopia\CLI\Console; -use Utopia\Database\Validator\Roles; use Utopia\Validator\Boolean; -use Utopia\Database\Exception\Duplicate as DuplicateException; +use Utopia\Validator\Range; +use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; -include_once __DIR__ . '/../shared/api.php'; +include_once __DIR__.'/../shared/api.php'; App::post('/v1/functions') ->groups(['api', 'functions']) @@ -60,9 +60,9 @@ App::post('/v1/functions') ->label('sdk.response.model', Response::MODEL_FUNCTION) ->param('functionId', '', new CustomId(), 'Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Function name. Max length: 128 chars.') - ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) + ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 64 characters long.', true) ->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.') - ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true) + ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.', true) ->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.', true) ->param('enabled', true, new Boolean(), 'Is function enabled?', true) @@ -73,7 +73,6 @@ App::post('/v1/functions') ->inject('events') ->inject('dbForConsole') ->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance, Database $dbForConsole) { - $functionId = ($functionId == 'unique()') ? ID::unique() : $functionId; $function = $dbForProject->createDocument('functions', new Document([ '$id' => $functionId, @@ -87,18 +86,18 @@ App::post('/v1/functions') 'schedule' => $schedule, 'scheduleInternalId' => '', 'timeout' => $timeout, - 'search' => implode(' ', [$functionId, $name, $runtime]) + 'search' => implode(' ', [$functionId, $name, $runtime]), ])); $schedule = Authorization::skip( - fn() => $dbForConsole->createDocument('schedules', new Document([ + fn () => $dbForConsole->createDocument('schedules', new Document([ 'region' => App::getEnv('_APP_REGION', 'default'), // Todo replace with projects region 'resourceType' => 'function', 'resourceId' => $function->getId(), 'resourceInternalId' => $function->getInternalId(), 'resourceUpdatedAt' => DateTime::now(), 'projectId' => $project->getId(), - 'schedule' => $function->getAttribute('schedule'), + 'schedule' => $function->getAttribute('schedule'), 'active' => false, ])) ); @@ -125,15 +124,14 @@ App::get('/v1/functions') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_FUNCTION_LIST) - ->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Functions::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Functions::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { - $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -173,17 +171,17 @@ App::get('/v1/functions/runtimes') ->label('sdk.response.model', Response::MODEL_RUNTIME_LIST) ->inject('response') ->action(function (Response $response) { - $runtimes = Config::getParam('runtimes'); $runtimes = array_map(function ($key) use ($runtimes) { $runtimes[$key]['$id'] = $key; + return $runtimes[$key]; }, array_keys($runtimes)); $response->dynamic(new Document([ 'total' => count($runtimes), - 'runtimes' => $runtimes + 'runtimes' => $runtimes, ]), Response::MODEL_RUNTIME_LIST); }); @@ -226,7 +224,6 @@ App::get('/v1/functions/:functionId/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $functionId, string $range, Response $response, Database $dbForProject) { - $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -270,18 +267,18 @@ App::get('/v1/functions/:functionId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, @@ -309,7 +306,6 @@ App::get('/v1/functions/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { - $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -348,18 +344,18 @@ App::get('/v1/functions/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, 'functionsTotal' => $usage[$metrics[0]], @@ -389,8 +385,8 @@ App::put('/v1/functions/:functionId') ->label('sdk.response.model', Response::MODEL_FUNCTION) ->param('functionId', '', new UID(), 'Function ID.') ->param('name', '', new Text(128), 'Function name. Max length: 128 chars.') - ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) - ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true) + ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 64 characters long.', true) + ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.', true) ->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true) ->param('enabled', true, new Boolean(), 'Is function enabled?', true) @@ -401,7 +397,6 @@ App::put('/v1/functions/:functionId') ->inject('events') ->inject('dbForConsole') ->action(function (string $functionId, string $name, array $execute, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance, Database $dbForConsole) { - $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -424,7 +419,7 @@ App::put('/v1/functions/:functionId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); + ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $eventsInstance->setParam('functionId', $function->getId()); @@ -454,7 +449,6 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') ->inject('events') ->inject('dbForConsole') ->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Document $project, Event $events, Database $dbForConsole) { - $function = $dbForProject->getDocument('functions', $functionId); $deployment = $dbForProject->getDocument('deployments', $deploymentId); $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')); @@ -484,7 +478,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); + ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $events @@ -515,14 +509,13 @@ App::delete('/v1/functions/:functionId') ->inject('project') ->inject('dbForConsole') ->action(function (string $functionId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Document $project, Database $dbForConsole) { - $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } - if (!$dbForProject->deleteDocument('functions', $function->getId())) { + if (! $dbForProject->deleteDocument('functions', $function->getId())) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove function from DB'); } @@ -570,7 +563,6 @@ App::post('/v1/functions/:functionId/deployments') ->inject('deviceLocal') ->inject('dbForConsole') ->action(function (string $functionId, string $entrypoint, mixed $code, bool $activate, Request $request, Response $response, Database $dbForProject, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal, Database $dbForConsole) { - $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -597,7 +589,7 @@ App::post('/v1/functions/:functionId/deployments') $fileTmpName = (\is_array($file['tmp_name']) && isset($file['tmp_name'][0])) ? $file['tmp_name'][0] : $file['tmp_name']; $fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size']; - if (!$fileExt->isValid($file['name'])) { // Check if file type is allowed + if (! $fileExt->isValid($file['name'])) { // Check if file type is allowed throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED); } @@ -606,7 +598,7 @@ App::post('/v1/functions/:functionId/deployments') $chunk = 1; $chunks = 1; - if (!empty($contentRange)) { + if (! empty($contentRange)) { $start = $request->getContentRangeStart(); $end = $request->getContentRangeEnd(); $fileSize = $request->getContentRangeSize(); @@ -627,21 +619,21 @@ App::post('/v1/functions/:functionId/deployments') } } - if (!$fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit + if (! $fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE); } - if (!$upload->isValid($fileTmpName)) { + if (! $upload->isValid($fileTmpName)) { throw new Exception(Exception::STORAGE_INVALID_FILE); } // Save to storage $fileSize ??= $deviceLocal->getFileSize($fileTmpName); - $path = $deviceFunctions->getPath($deploymentId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION)); + $path = $deviceFunctions->getPath($deploymentId.'.'.\pathinfo($fileName, PATHINFO_EXTENSION)); $deployment = $dbForProject->getDocument('deployments', $deploymentId); $metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)]; - if (!$deployment->isEmpty()) { + if (! $deployment->isEmpty()) { $chunks = $deployment->getAttribute('chunksTotal', 1); $metadata = $deployment->getAttribute('metadata', []); if ($chunk === -1) { @@ -663,7 +655,7 @@ App::post('/v1/functions/:functionId/deployments') $activeDeployments = $dbForProject->find('deployments', [ Query::equal('activate', [true]), Query::equal('resourceId', [$functionId]), - Query::equal('resourceType', ['functions']) + Query::equal('resourceType', ['functions']), ]); foreach ($activeDeployments as $activeDeployment) { @@ -755,12 +747,11 @@ App::get('/v1/functions/:functionId/deployments') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DEPLOYMENT_LIST) ->param('functionId', '', new UID(), 'Function ID.') - ->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Deployments::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject) { - $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -769,7 +760,7 @@ App::get('/v1/functions/:functionId/deployments') $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -827,7 +818,6 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId') ->inject('response') ->inject('dbForProject') ->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject) { - $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -873,7 +863,6 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') ->inject('events') ->inject('deviceFunctions') ->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Device $deviceFunctions) { - $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { throw new Exception(Exception::FUNCTION_NOT_FOUND); @@ -889,7 +878,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') } if ($deviceFunctions->delete($deployment->getAttribute('path', ''))) { - if (!$dbForProject->deleteDocument('deployments', $deployment->getId())) { + if (! $dbForProject->deleteDocument('deployments', $deployment->getId())) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove deployment from DB'); } } @@ -933,7 +922,6 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') ->inject('project') ->inject('events') ->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) { - $function = $dbForProject->getDocument('functions', $functionId); $deployment = $dbForProject->getDocument('deployments', $deploymentId); @@ -998,11 +986,10 @@ App::post('/v1/functions/:functionId/executions') ->inject('queueForFunctions') ->inject('queueForUsage') ->action(function (string $functionId, string $data, bool $async, Response $response, Document $project, Database $dbForProject, Document $user, Event $events, string $mode, Func $queueForFunctions, Usage $queueForUsage) { - $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty() || !$function->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($function->isEmpty() || ! $function->getAttribute('enabled')) { + if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } } @@ -1012,7 +999,7 @@ App::post('/v1/functions/:functionId/executions') $runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null; if (\is_null($runtime)) { - throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); + throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "'.$function->getAttribute('runtime', '').'" is not supported'); } $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', ''))); @@ -1037,7 +1024,7 @@ App::post('/v1/functions/:functionId/executions') $validator = new Authorization('execute'); - if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function + if (! $validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription()); } @@ -1046,7 +1033,7 @@ App::post('/v1/functions/:functionId/executions') /** @var Document $execution */ $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', new Document([ '$id' => $executionId, - '$permissions' => !$user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [], + '$permissions' => ! $user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [], 'functionInternalId' => $function->getInternalId(), 'functionId' => $function->getId(), 'deploymentInternalId' => $deployment->getInternalId(), @@ -1061,7 +1048,7 @@ App::post('/v1/functions/:functionId/executions') ]))); $jwt = ''; // initialize - if (!$user->isEmpty()) { // If userId exists, generate a JWT for function + if (! $user->isEmpty()) { // If userId exists, generate a JWT for function $sessions = $user->getAttribute('sessions', []); $current = new Document(); @@ -1072,7 +1059,7 @@ App::post('/v1/functions/:functionId/executions') } } - if (!$current->isEmpty()) { + if (! $current->isEmpty()) { $jwtObj = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. $jwt = $jwtObj->encode([ 'userId' => $user->getId(), @@ -1104,6 +1091,7 @@ App::post('/v1/functions/:functionId/executions') $vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { $carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? ''; + return $carry; }, []); @@ -1145,13 +1133,13 @@ App::post('/v1/functions/:functionId/executions') * Sync execution compute usage from */ $queueForUsage - ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($executionResponse['duration'] * 1000))// per project - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($executionResponse['duration'] * 1000))// per function - ; + ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int) ($executionResponse['duration'] * 1000))// per project + ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int) ($executionResponse['duration'] * 1000))// per function +; } catch (\Throwable $th) { $interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt())); $execution - ->setAttribute('duration', (float)$interval->format('%s.%f')) + ->setAttribute('duration', (float) $interval->format('%s.%f')) ->setAttribute('status', 'failed') ->setAttribute('statusCode', $th->getCode()) ->setAttribute('stderr', $th->getMessage()); @@ -1164,7 +1152,7 @@ App::post('/v1/functions/:functionId/executions') $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); - if (!$isPrivilegedUser && !$isAppUser) { + if (! $isPrivilegedUser && ! $isAppUser) { $execution->setAttribute('stdout', ''); $execution->setAttribute('stderr', ''); } @@ -1186,24 +1174,23 @@ App::get('/v1/functions/:functionId/executions') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_EXECUTION_LIST) ->param('functionId', '', new UID(), 'Function ID.') - ->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Executions::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') ->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { - $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty() || !$function->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($function->isEmpty() || ! $function->getAttribute('enabled')) { + if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } } $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -1233,10 +1220,11 @@ App::get('/v1/functions/:functionId/executions') $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); - if (!$isPrivilegedUser && !$isAppUser) { + if (! $isPrivilegedUser && ! $isAppUser) { $results = array_map(function ($execution) { $execution->setAttribute('stdout', ''); $execution->setAttribute('stderr', ''); + return $execution; }, $results); } @@ -1264,11 +1252,10 @@ App::get('/v1/functions/:functionId/executions/:executionId') ->inject('dbForProject') ->inject('mode') ->action(function (string $functionId, string $executionId, Response $response, Database $dbForProject, string $mode) { - $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty() || !$function->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($function->isEmpty() || ! $function->getAttribute('enabled')) { + if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } } @@ -1286,7 +1273,7 @@ App::get('/v1/functions/:functionId/executions/:executionId') $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); - if (!$isPrivilegedUser && !$isAppUser) { + if (! $isPrivilegedUser && ! $isAppUser) { $execution->setAttribute('stdout', ''); $execution->setAttribute('stderr', ''); } @@ -1310,7 +1297,7 @@ App::post('/v1/functions/:functionId/variables') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_VARIABLE) ->param('functionId', '', new UID(), 'Function unique ID.', false) - ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false) + ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: '.Database::LENGTH_KEY.' chars.', false) ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false) ->inject('response') ->inject('dbForProject') @@ -1348,7 +1335,7 @@ App::post('/v1/functions/:functionId/variables') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); + ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $dbForProject->deleteCachedDocument('functions', $function->getId()); @@ -1357,7 +1344,7 @@ App::post('/v1/functions/:functionId/variables') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); + ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $response @@ -1447,7 +1434,6 @@ App::put('/v1/functions/:functionId/variables/:variableId') ->inject('dbForProject') ->inject('dbForConsole') ->action(function (string $functionId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject, Database $dbForConsole) { - $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -1466,8 +1452,7 @@ App::put('/v1/functions/:functionId/variables/:variableId') $variable ->setAttribute('key', $key) ->setAttribute('value', $value ?? $variable->getAttribute('value')) - ->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key])) - ; + ->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key])); try { $dbForProject->updateDocument('variables', $variable->getId(), $variable); @@ -1479,7 +1464,7 @@ App::put('/v1/functions/:functionId/variables/:variableId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); + ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $dbForProject->deleteCachedDocument('functions', $function->getId()); @@ -1488,7 +1473,7 @@ App::put('/v1/functions/:functionId/variables/:variableId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); + ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $response->dynamic($variable, Response::MODEL_VARIABLE); @@ -1533,7 +1518,7 @@ App::delete('/v1/functions/:functionId/variables/:variableId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); + ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $dbForProject->deleteCachedDocument('functions', $function->getId()); @@ -1542,7 +1527,7 @@ App::delete('/v1/functions/:functionId/variables/:variableId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); + ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $response->noContent(); diff --git a/app/controllers/api/graphql.php b/app/controllers/api/graphql.php index 8ee3b5ac47..b4eb5ef620 100644 --- a/app/controllers/api/graphql.php +++ b/app/controllers/api/graphql.php @@ -42,11 +42,11 @@ App::get('/v1/graphql') 'query' => $query, ]; - if (!empty($operationName)) { + if (! empty($operationName)) { $query['operationName'] = $operationName; } - if (!empty($variables)) { + if (! empty($variables)) { $query['variables'] = \json_decode($variables, true); } @@ -150,10 +150,11 @@ App::post('/v1/graphql') /** * Execute a GraphQL request * - * @param GQLSchema $schema - * @param Adapter $promiseAdapter - * @param array $query + * @param GQLSchema $schema + * @param Adapter $promiseAdapter + * @param array $query * @return array + * * @throws Exception */ function execute( @@ -165,7 +166,7 @@ function execute( $maxComplexity = App::getEnv('_APP_GRAPHQL_MAX_COMPLEXITY', 250); $maxDepth = App::getEnv('_APP_GRAPHQL_MAX_DEPTH', 3); - if (!empty($query) && !isset($query[0])) { + if (! empty($query) && ! isset($query[0])) { $query = [$query]; } if (empty($query)) { @@ -224,7 +225,7 @@ function execute( /** * Parse an "application/graphql" type request * - * @param Request $request + * @param Request $request * @return array */ function parseGraphql(Request $request): array @@ -235,8 +236,8 @@ function parseGraphql(Request $request): array /** * Parse an "multipart/form-data" type request * - * @param array $query - * @param Request $request + * @param array $query + * @param Request $request * @return array */ function parseMultipart(array $query, Request $request): array @@ -248,7 +249,7 @@ function parseMultipart(array $query, Request $request): array foreach ($locations as $location) { $items = &$operations; foreach (\explode('.', $location) as $key) { - if (!isset($items[$key]) || !\is_array($items[$key])) { + if (! isset($items[$key]) || ! \is_array($items[$key])) { $items[$key] = []; } $items = &$items[$key]; @@ -276,7 +277,7 @@ function parseMultipart(array $query, Request $request): array function processResult($result, $debugFlags): array { // Only one query, return the result - if (!isset($result[1])) { + if (! isset($result[1])) { return $result[0]->toArray($debugFlags); } diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index d6a2612f32..4cac066cc6 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -28,11 +28,10 @@ App::get('/v1/health') ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') ->action(function (Response $response) { - $output = [ 'name' => 'http', 'status' => 'pass', - 'ping' => 0 + 'ping' => 0, ]; $response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS); @@ -47,7 +46,7 @@ App::get('/v1/health/version') ->label('sdk.response.model', Response::MODEL_HEALTH_VERSION) ->inject('response') ->action(function (Response $response) { - $response->dynamic(new Document([ 'version' => APP_VERSION_STABLE ]), Response::MODEL_HEALTH_VERSION); + $response->dynamic(new Document(['version' => APP_VERSION_STABLE]), Response::MODEL_HEALTH_VERSION); }); App::get('/v1/health/db') @@ -64,7 +63,6 @@ App::get('/v1/health/db') ->inject('response') ->inject('pools') ->action(function (Response $response, Group $pools) { - $output = []; $configs = [ @@ -81,22 +79,22 @@ App::get('/v1/health/db') if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } else { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } } @@ -122,7 +120,6 @@ App::get('/v1/health/cache') ->inject('response') ->inject('pools') ->action(function (Response $response, Group $pools) { - $output = []; $configs = [ @@ -138,22 +135,22 @@ App::get('/v1/health/cache') if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } else { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } } @@ -179,7 +176,6 @@ App::get('/v1/health/queue') ->inject('response') ->inject('pools') ->action(function (Response $response, Group $pools) { - $output = []; $configs = [ @@ -195,22 +191,22 @@ App::get('/v1/health/queue') if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } else { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } } @@ -236,7 +232,6 @@ App::get('/v1/health/pubsub') ->inject('response') ->inject('pools') ->action(function (Response $response, Group $pools) { - $output = []; $configs = [ @@ -252,22 +247,22 @@ App::get('/v1/health/pubsub') if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } else { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key . " ($database)", + 'name' => $key." ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]); } } @@ -292,7 +287,6 @@ App::get('/v1/health/time') ->label('sdk.response.model', Response::MODEL_HEALTH_TIME) ->inject('response') ->action(function (Response $response) { - /* * Code from: @see https://www.beliefmedia.com.au/query-ntp-time-server */ @@ -305,7 +299,7 @@ App::get('/v1/health/time') \socket_connect($sock, $host, 123); /* Send request */ - $msg = "\010" . \str_repeat("\0", 47); + $msg = "\010".\str_repeat("\0", 47); \socket_send($sock, $msg, \strlen($msg), 0); @@ -330,7 +324,7 @@ App::get('/v1/health/time') $output = [ 'remoteTime' => $timestamp, 'localTime' => \time(), - 'diff' => $diff + 'diff' => $diff, ]; $response->dynamic(new Document($output), Response::MODEL_HEALTH_TIME); @@ -349,8 +343,7 @@ App::get('/v1/health/queue/webhooks') ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') ->action(function (Response $response) { - - $response->dynamic(new Document([ 'size' => Resque::size(Event::WEBHOOK_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); + $response->dynamic(new Document(['size' => Resque::size(Event::WEBHOOK_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE); }, ['response']); App::get('/v1/health/queue/logs') @@ -366,8 +359,7 @@ App::get('/v1/health/queue/logs') ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') ->action(function (Response $response) { - - $response->dynamic(new Document([ 'size' => Resque::size(Event::AUDITS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); + $response->dynamic(new Document(['size' => Resque::size(Event::AUDITS_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE); }, ['response']); App::get('/v1/health/queue/certificates') @@ -383,8 +375,7 @@ App::get('/v1/health/queue/certificates') ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') ->action(function (Response $response) { - - $response->dynamic(new Document([ 'size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); + $response->dynamic(new Document(['size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE); }, ['response']); App::get('/v1/health/queue/functions') @@ -402,7 +393,7 @@ App::get('/v1/health/queue/functions') ->inject('response') ->action(function (Connection $queue, Response $response) { $client = new Client(Event::FUNCTIONS_QUEUE_NAME, $queue); - $response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); + $response->dynamic(new Document(['size' => $client->sumProcessingJobs()]), Response::MODEL_HEALTH_QUEUE); }, ['response']); App::get('/v1/health/storage/local') @@ -418,31 +409,30 @@ App::get('/v1/health/storage/local') ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') ->action(function (Response $response) { - $checkStart = \microtime(true); foreach ( [ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES + 'Uploads' => APP_STORAGE_UPLOADS, + 'Cache' => APP_STORAGE_CACHE, + 'Config' => APP_STORAGE_CONFIG, + 'Certs' => APP_STORAGE_CERTIFICATES, ] as $key => $volume ) { $device = new Local($volume); - if (!\is_readable($device->getRoot())) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device ' . $key . ' dir is not readable'); + if (! \is_readable($device->getRoot())) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device '.$key.' dir is not readable'); } - if (!\is_writable($device->getRoot())) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device ' . $key . ' dir is not writable'); + if (! \is_writable($device->getRoot())) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device '.$key.' dir is not writable'); } } $output = [ 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + 'ping' => \round((\microtime(true) - $checkStart) / 1000), ]; $response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS); @@ -461,10 +451,9 @@ App::get('/v1/health/anti-virus') ->label('sdk.response.model', Response::MODEL_HEALTH_ANTIVIRUS) ->inject('response') ->action(function (Response $response) { - $output = [ 'status' => '', - 'version' => '' + 'version' => '', ]; if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'disabled') { // Check if scans are enabled @@ -499,7 +488,6 @@ App::get('/v1/health/stats') // Currently only used internally ->inject('register') ->inject('deviceFiles') ->action(function (Response $response, Registry $register, Device $deviceFiles) { - $cache = $register->get('cache'); $cacheStats = $cache->info(); @@ -507,7 +495,7 @@ App::get('/v1/health/stats') // Currently only used internally $response ->json([ 'storage' => [ - 'used' => Storage::human($deviceFiles->getDirectorySize($deviceFiles->getRoot() . '/')), + 'used' => Storage::human($deviceFiles->getDirectorySize($deviceFiles->getRoot().'/')), 'partitionTotal' => Storage::human($deviceFiles->getPartitionTotalSpace()), 'partitionFree' => Storage::human($deviceFiles->getPartitionFreeSpace()), ], diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index 29b4932543..5fd423349a 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -1,7 +1,7 @@ getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); - $output['continent'] = $locale->getText('continents.' . strtolower($record['continent']['code']), $locale->getText('locale.country.unknown')); + $output['country'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output['continent'] = $locale->getText('continents.'.strtolower($record['continent']['code']), $locale->getText('locale.country.unknown')); $output['continentCode'] = $record['continent']['code']; $output['eu'] = (\in_array($record['country']['iso_code'], $eu)) ? true : false; @@ -62,9 +62,9 @@ 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', 'public, max-age='.$time) + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time).' GMT') // 45 days cache +; $response->dynamic(new Document($output), Response::MODEL_LOCALE); }); @@ -111,7 +111,7 @@ App::get('/v1/locale/countries') foreach ($list as $value) { $output[] = new Document([ - 'name' => $locale->getText('countries.' . strtolower($value)), + 'name' => $locale->getText('countries.'.strtolower($value)), 'code' => $value, ]); } @@ -143,9 +143,9 @@ App::get('/v1/locale/countries/eu') $output = []; foreach ($eu as $code) { - if ($locale->getText('countries.' . strtolower($code), false) !== false) { + if ($locale->getText('countries.'.strtolower($code), false) !== false) { $output[] = new Document([ - 'name' => $locale->getText('countries.' . strtolower($code)), + 'name' => $locale->getText('countries.'.strtolower($code)), 'code' => $code, ]); } @@ -180,11 +180,11 @@ App::get('/v1/locale/countries/phones') \asort($list); foreach ($list as $code => $name) { - if ($locale->getText('countries.' . strtolower($code), false) !== false) { + if ($locale->getText('countries.'.strtolower($code), false) !== false) { $output[] = new Document([ - 'code' => '+' . $list[$code], + 'code' => '+'.$list[$code], 'countryCode' => $code, - 'countryName' => $locale->getText('countries.' . strtolower($code)), + 'countryName' => $locale->getText('countries.'.strtolower($code)), ]); } } @@ -212,7 +212,7 @@ App::get('/v1/locale/continents') foreach ($list as $value) { $output[] = new Document([ - 'name' => $locale->getText('continents.' . strtolower($value)), + 'name' => $locale->getText('continents.'.strtolower($value)), 'code' => $value, ]); } @@ -246,7 +246,6 @@ App::get('/v1/locale/currencies') $response->dynamic(new Document(['currencies' => $list, 'total' => \count($list)]), Response::MODEL_CURRENCY_LIST); }); - App::get('/v1/locale/languages') ->desc('List Languages') ->groups(['api', 'locale']) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 1ff95fbeea..a2d7cc6419 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -25,35 +25,35 @@ App::get('/v1/messaging/providers') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER_LIST) - ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Providers::ALLOWED_ATTRIBUTES), true) ->inject('dbForProject') ->inject('response') ->action(function (array $queries, Database $dbForProject, Response $response) { - $queries = Query::parseQueries($queries); + $queries = Query::parseQueries($queries); - // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); - $cursor = reset($cursor); + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); - if ($cursor) { - $providerId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ - Query::equal('$id', [$providerId]), - Query::limit(1), - ])); + if ($cursor) { + $providerId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ + Query::equal('$id', [$providerId]), + Query::limit(1), + ])); - if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { - throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); - } + if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); + } - $cursor->setValue($cursorDocument[0]); - } + $cursor->setValue($cursorDocument[0]); + } - $filterQueries = Query::groupByType($queries)['filters']; - $response->dynamic(new Document([ - 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), - 'indexes' => $dbForProject->find('providers', $queries), - ]), Response::MODEL_PROVIDER_LIST); + $filterQueries = Query::groupByType($queries)['filters']; + $response->dynamic(new Document([ + 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), + 'indexes' => $dbForProject->find('providers', $queries), + ]), Response::MODEL_PROVIDER_LIST); }); App::get('/v1/messaging/providers/:id') @@ -71,13 +71,13 @@ App::get('/v1/messaging/providers/:id') ->inject('dbForProject') ->inject('response') ->action(function (string $id, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } - $response->dynamic($provider, Response::MODEL_PROVIDER); + $response->dynamic($provider, Response::MODEL_PROVIDER); }); /** @@ -101,18 +101,18 @@ App::post('/v1/messaging/providers/mailgun') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'mailgun', - 'type' => 'email', - 'credentials' => [ - 'apiKey' => $apiKey, - 'domain' => $domain, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'mailgun', + 'type' => 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + 'domain' => $domain, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/mailgun') @@ -134,39 +134,39 @@ App::patch('/v1/messaging/providers/:id/mailgun') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'mailgun') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'mailgun') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($apiKey || $domain) { - // Check if all five variables are present - if ($apiKey && $domain) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'domain' => $domain - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($apiKey || $domain) { + // Check if all five variables are present + if ($apiKey && $domain) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'domain' => $domain, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/sendgrid') @@ -186,17 +186,17 @@ App::post('/v1/messaging/providers/sendgrid') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'sendgrid', - 'type' => 'email', - 'credentials' => [ - 'apiKey' => $apiKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'sendgrid', + 'type' => 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/sendgrid') @@ -217,32 +217,32 @@ App::patch('/v1/messaging/providers/:id/sendgrid') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'sendgrid') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'sendgrid') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($apiKey) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey - ]); - } + if ($apiKey) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + ]); + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); /** @@ -266,18 +266,18 @@ App::post('/v1/messaging/providers/msg91') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'msg91', - 'type' => 'sms', - 'credentials' => [ - 'senderId' => $senderId, - 'authKey' => $authKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'msg91', + 'type' => 'sms', + 'credentials' => [ + 'senderId' => $senderId, + 'authKey' => $authKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/msg91') @@ -299,39 +299,39 @@ App::patch('/v1/messaging/providers/:id/msg91') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'msg91') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'msg91') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($senderId || $authKey) { - // Check if all five variables are present - if ($senderId && $authKey) { - $provider->setAttribute('credentials', [ - 'senderId' => $senderId, - 'authKey' => $authKey - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($senderId || $authKey) { + // Check if all five variables are present + if ($senderId && $authKey) { + $provider->setAttribute('credentials', [ + 'senderId' => $senderId, + 'authKey' => $authKey, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/telesign') @@ -352,18 +352,18 @@ App::post('/v1/messaging/providers/telesign') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $username, string $password, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'telesign', - 'type' => 'sms', - 'credentials' => [ - 'username' => $username, - 'password' => $password, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'telesign', + 'type' => 'sms', + 'credentials' => [ + 'username' => $username, + 'password' => $password, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/telesign') @@ -385,39 +385,39 @@ App::patch('/v1/messaging/providers/:id/telesign') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $username, string $password, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'telesign') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'telesign') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($username || $password) { - // Check if all five variables are present - if ($username && $password) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'password' => $password - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($username || $password) { + // Check if all five variables are present + if ($username && $password) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'password' => $password, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/textmagic') @@ -438,18 +438,18 @@ App::post('/v1/messaging/providers/textmagic') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'text-magic', - 'type' => 'sms', - 'credentials' => [ - 'username' => $username, - 'apiKey' => $apiKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'text-magic', + 'type' => 'sms', + 'credentials' => [ + 'username' => $username, + 'apiKey' => $apiKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/textmagic') @@ -471,39 +471,39 @@ App::patch('/v1/messaging/providers/:id/textmagic') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'text-magic') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'text-magic') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($username || $apiKey) { - // Check if all five variables are present - if ($username && $apiKey) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'apiKey' => $apiKey - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($username || $apiKey) { + // Check if all five variables are present + if ($username && $apiKey) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'apiKey' => $apiKey, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/twilio') @@ -524,18 +524,18 @@ App::post('/v1/messaging/providers/twilio') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'twilio', - 'type' => 'sms', - 'credentials' => [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'twilio', + 'type' => 'sms', + 'credentials' => [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/twilio') @@ -557,39 +557,39 @@ App::patch('/v1/messaging/providers/:id/twilio') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'twilio') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'twilio') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($accountSid || $authToken) { - // Check if all five variables are present - if ($accountSid && $authToken) { - $provider->setAttribute('credentials', [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($accountSid || $authToken) { + // Check if all five variables are present + if ($accountSid && $authToken) { + $provider->setAttribute('credentials', [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/vonage') @@ -610,18 +610,18 @@ App::post('/v1/messaging/providers/vonage') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'vonage', - 'type' => 'sms', - 'credentials' => [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'vonage', + 'type' => 'sms', + 'credentials' => [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/vonage') @@ -643,39 +643,39 @@ App::patch('/v1/messaging/providers/:id/vonage') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'vonage') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'vonage') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($apiKey || $apiSecret) { - // Check if all five variables are present - if ($apiKey && $apiSecret) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($apiKey || $apiSecret) { + // Check if all five variables are present + if ($apiKey && $apiSecret) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); /** @@ -698,17 +698,17 @@ App::post('/v1/messaging/providers/fcm') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $serverKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'fcm', - 'type' => 'push', - 'credentials' => [ - 'serverKey' => $serverKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'fcm', + 'type' => 'push', + 'credentials' => [ + 'serverKey' => $serverKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/fcm') @@ -729,30 +729,30 @@ App::patch('/v1/messaging/providers/:id/fcm') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $serverKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'fcm') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'fcm') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($serverKey) { - $provider->setAttribute('credentials', ['serverKey' => $serverKey]); - } + if ($serverKey) { + $provider->setAttribute('credentials', ['serverKey' => $serverKey]); + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/apns') @@ -776,21 +776,21 @@ App::post('/v1/messaging/providers/apns') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'apns', - 'type' => 'push', - 'credentials' => [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'apns', + 'type' => 'push', + 'credentials' => [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/apns') @@ -815,42 +815,42 @@ App::patch('/v1/messaging/providers/:id/apns') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'apns') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'apns') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { - // Check if all five variables are present - if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { - $provider->setAttribute('credentials', [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { + // Check if all five variables are present + if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { + $provider->setAttribute('credentials', [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::delete('/v1/messaging/providers/:id') @@ -869,16 +869,16 @@ App::delete('/v1/messaging/providers/:id') ->inject('dbForProject') ->inject('response') ->action(function (string $id, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } - $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $dbForProject->deleteDocument('providers', $provider->getId()); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $dbForProject->deleteDocument('providers', $provider->getId()); - $response->noContent(); + $response->noContent(); }); App::post('/v1/messaging/messages/email') @@ -904,30 +904,30 @@ App::post('/v1/messaging/messages/email') ->inject('events') ->inject('response') ->action(function (string $providerId, string $to, string $subject, string $content, string $from, string $html, DateTime $deliveryTime, Database $dbForProject, Event $eventsInstance, Response $response) { - $provider = $dbForProject->getDocument('providers', $providerId); + $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } - $message = $dbForProject->createDocument('messages', new Document([ - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), - 'to' => $to, - 'data' => [ - 'subject' => $subject, - 'content' => $content, - ], - 'deliveryTime' => $deliveryTime, - 'deliveryError' => null, - 'deliveredTo' => null, - 'delivered' => false, - 'search' => null, - ])); + $message = $dbForProject->createDocument('messages', new Document([ + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'to' => $to, + 'data' => [ + 'subject' => $subject, + 'content' => $content, + ], + 'deliveryTime' => $deliveryTime, + 'deliveryError' => null, + 'deliveredTo' => null, + 'delivered' => false, + 'search' => null, + ])); - $eventsInstance->setParam('messageId', $message->getId()); + $eventsInstance->setParam('messageId', $message->getId()); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_MESSAGE); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_MESSAGE); }); diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index 8d961a0450..23ebc29362 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -28,7 +28,7 @@ use Utopia\Validator\Text; use Utopia\Validator\URL; use Utopia\Validator\WhiteList; -include_once __DIR__ . '/../shared/api.php'; +include_once __DIR__.'/../shared/api.php'; App::post('/v1/migrations/appwrite') ->groups(['api', 'migrations']) @@ -110,7 +110,7 @@ App::post('/v1/migrations/firebase/oauth') $firebase = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' ); $identity = $dbForConsole->findOne('identities', [ @@ -141,7 +141,7 @@ App::post('/v1/migrations/firebase/oauth') $identity = $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $firebase->getAccessTokenExpiry(''))); $dbForConsole->updateDocument('identities', $identity->getId(), $identity); } @@ -167,7 +167,7 @@ App::post('/v1/migrations/firebase/oauth') 'resources' => $resources, 'statusCounters' => '{}', 'resourceData' => '{}', - 'errors' => [] + 'errors' => [], ])); $events->setParam('migrationId', $migration->getId()); @@ -368,14 +368,14 @@ App::get('/v1/migrations') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MIGRATION_LIST) - ->param('queries', [], new Migrations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Migrations::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Migrations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Migrations::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -505,7 +505,7 @@ App::get('/v1/migrations/firebase/report/oauth') $firebase = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' ); $identity = $dbForConsole->findOne('identities', [ @@ -536,7 +536,7 @@ App::get('/v1/migrations/firebase/report/oauth') $identity = $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $firebase->getAccessTokenExpiry(''))); $dbForConsole->updateDocument('identities', $identity->getId(), $identity); } @@ -597,7 +597,7 @@ App::get('/v1/migrations/firebase/connect') $oauth2 = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' ); $url = $oauth2->getLoginURL(); @@ -611,7 +611,7 @@ App::get('/v1/migrations/firebase/redirect') ->desc('Capture and receive data on Firebase authorization') ->groups(['api', 'migrations']) ->label('scope', 'public') - ->label('error', __DIR__ . '/../../views/general/error.phtml') + ->label('error', __DIR__.'/../../views/general/error.phtml') ->param('code', '', new Text(2048), 'OAuth2 code.', true) ->inject('user') ->inject('project') @@ -635,7 +635,7 @@ App::get('/v1/migrations/firebase/redirect') $project = $dbForConsole->getDocument('projects', $projectId); if (empty($redirect)) { - $redirect = $request->getProtocol() . '://' . $request->getHostname() . '/console/project-$projectId/settings/migrations'; + $redirect = $request->getProtocol().'://'.$request->getHostname().'/console/project-$projectId/settings/migrations'; } if ($project->isEmpty()) { @@ -648,11 +648,11 @@ App::get('/v1/migrations/firebase/redirect') } // OAuth Authroization - if (!empty($code)) { + if (! empty($code)) { $oauth2 = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' ); $accessToken = $oauth2->getAccessToken($code); @@ -678,17 +678,17 @@ App::get('/v1/migrations/firebase/redirect') Query::equal('providerEmail', [$email]), ]); - if ($identity !== false && !$identity->isEmpty()) { + if ($identity !== false && ! $identity->isEmpty()) { if ($identity->getAttribute('userInternalId', '') !== $user->getInternalId()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } } - if ($identity !== false && !$identity->isEmpty()) { + if ($identity !== false && ! $identity->isEmpty()) { $identity = $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry)); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry)); $dbForConsole->updateDocument('identities', $identity->getId(), $identity); } else { @@ -706,7 +706,7 @@ App::get('/v1/migrations/firebase/redirect') 'providerEmail' => $email, 'providerAccessToken' => $accessToken, 'providerRefreshToken' => $refreshToken, - 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry), + 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry), ])); } } else { @@ -738,7 +738,7 @@ App::get('/v1/migrations/firebase/projects') $firebase = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' ); $identity = $dbForConsole->findOne('identities', [ @@ -781,7 +781,7 @@ App::get('/v1/migrations/firebase/projects') $identity = $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $firebase->getAccessTokenExpiry(''))); $dbForConsole->updateDocument('identities', $identity->getId(), $identity); } @@ -964,7 +964,7 @@ App::delete('/v1/migrations/:migrationId') throw new Exception(Exception::MIGRATION_NOT_FOUND); } - if (!$dbForProject->deleteDocument('migrations', $migration->getId())) { + if (! $dbForProject->deleteDocument('migrations', $migration->getId())) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove migration from DB', 500); } diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index 0f05c6f497..0146f1c19f 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -4,7 +4,6 @@ use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Config\Config; use Utopia\Database\Database; -use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; @@ -24,7 +23,6 @@ App::get('/v1/project/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { - $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -37,7 +35,7 @@ App::get('/v1/project/usage') METRIC_DATABASES, METRIC_USERS, METRIC_BUCKETS, - METRIC_FILES_STORAGE + METRIC_FILES_STORAGE, ]; Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { @@ -60,25 +58,23 @@ App::get('/v1/project/usage') } }); - $format = match ($days['period']) { '1h' => 'Y-m-d\TH:00:00.000P', '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } - $response->dynamic(new Document([ 'range' => $range, diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 6fff6b324b..f28f5197cb 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1,19 +1,22 @@ groups(['projects']) @@ -64,7 +63,7 @@ App::post('/v1/projects') ->param('projectId', '', new ProjectId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can\'t start with a special char. Max length is 36 chars.') ->param('name', null, new Text(128), 'Project name. Max length: 128 chars.') ->param('teamId', '', new UID(), 'Team unique ID.') - ->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn($config) => !$config['disabled']))), 'Project Region.', true) + ->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn ($config) => ! $config['disabled']))), 'Project Region.', true) ->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true) ->param('logo', '', new Text(1024), 'Project logo.', true) ->param('url', '', new URL(), 'Project URL.', true) @@ -79,8 +78,6 @@ App::post('/v1/projects') ->inject('cache') ->inject('pools') ->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools) { - - $team = $dbForConsole->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -164,7 +161,7 @@ App::post('/v1/projects') 'domains' => null, 'auths' => $auths, 'search' => implode(' ', [$projectId, $name]), - 'database' => $database + 'database' => $database, ])); } catch (Duplicate $th) { throw new Exception(Exception::PROJECT_ALREADY_EXISTS); @@ -201,7 +198,7 @@ App::post('/v1/projects') 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '' + 'format' => $attribute['format'] ?? '', ]); } @@ -232,15 +229,14 @@ App::get('/v1/projects') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT_LIST) - ->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Projects::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Projects::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForConsole') ->action(function (array $queries, string $search, Response $response, Database $dbForConsole) { - $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -281,7 +277,6 @@ App::get('/v1/projects/:projectId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -315,7 +310,6 @@ App::patch('/v1/projects/:projectId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $name, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -353,7 +347,6 @@ App::patch('/v1/projects/:projectId/team') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $teamId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); $team = $dbForConsole->getDocument('teams', $teamId); @@ -389,12 +382,11 @@ App::patch('/v1/projects/:projectId/service') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])), true), 'Service name.') + ->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])), true), 'Service name.') ->param('status', null, new Boolean(), 'Service status.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $service, bool $status, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -424,14 +416,13 @@ App::patch('/v1/projects/:projectId/service/all') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, bool $status, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { throw new Exception(Exception::PROJECT_NOT_FOUND); } - $allServices = array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])); + $allServices = array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])); $services = []; foreach ($allServices as $service) { @@ -461,7 +452,6 @@ App::patch('/v1/projects/:projectId/oauth2') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $provider, ?string $appId, ?string $secret, ?bool $enabled, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -471,15 +461,15 @@ App::patch('/v1/projects/:projectId/oauth2') $providers = $project->getAttribute('authProviders', []); if ($appId !== null) { - $providers[$provider . 'Appid'] = $appId; + $providers[$provider.'Appid'] = $appId; } if ($secret !== null) { - $providers[$provider . 'Secret'] = $secret; + $providers[$provider.'Secret'] = $secret; } if ($enabled !== null) { - $providers[$provider . 'Enabled'] = $enabled; + $providers[$provider.'Enabled'] = $enabled; } $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('authProviders', $providers)); @@ -502,7 +492,6 @@ App::patch('/v1/projects/:projectId/auth/limit') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -533,7 +522,6 @@ App::patch('/v1/projects/:projectId/auth/duration') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, int $duration, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -560,12 +548,11 @@ App::patch('/v1/projects/:projectId/auth/:method') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: ' . implode(',', \array_keys(Config::getParam('auth'))), false) + ->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: '.implode(',', \array_keys(Config::getParam('auth'))), false) ->param('status', false, new Boolean(true), 'Set the status of this auth method.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $method, bool $status, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); $auth = Config::getParam('auth')[$method] ?? []; $authKey = $auth['key'] ?? ''; @@ -594,11 +581,10 @@ App::patch('/v1/projects/:projectId/auth/password-history') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is' . APP_LIMIT_USER_PASSWORD_HISTORY . '. Default value is 0') + ->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is'.APP_LIMIT_USER_PASSWORD_HISTORY.'. Default value is 0') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -629,7 +615,6 @@ App::patch('/v1/projects/:projectId/auth/password-dictionary') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, bool $enabled, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -660,7 +645,6 @@ App::patch('/v1/projects/:projectId/auth/personal-data') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, bool $enabled, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -687,11 +671,10 @@ App::patch('/v1/projects/:projectId/auth/max-sessions') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-' . APP_LIMIT_USER_SESSIONS_MAX . '. Default is ' . APP_LIMIT_USER_SESSIONS_DEFAULT) + ->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-'.APP_LIMIT_USER_SESSIONS_MAX.'. Default is '.APP_LIMIT_USER_SESSIONS_DEFAULT) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -730,10 +713,9 @@ App::delete('/v1/projects/:projectId') $deletes ->setType(DELETE_TYPE_DOCUMENT) - ->setDocument($project) - ; + ->setDocument($project); - if (!$dbForConsole->deleteDocument('projects', $projectId)) { + if (! $dbForConsole->deleteDocument('projects', $projectId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove project from DB'); } @@ -754,7 +736,7 @@ App::post('/v1/projects/:projectId/webhooks') ->label('sdk.response.model', Response::MODEL_WEBHOOK) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.') - ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') + ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.') ->param('url', null, new URL(['http', 'https']), 'Webhook URL.') ->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.') ->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true) @@ -762,7 +744,6 @@ App::post('/v1/projects/:projectId/webhooks') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -812,7 +793,6 @@ App::get('/v1/projects/:projectId/webhooks') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -845,7 +825,6 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -877,7 +856,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->param('projectId', '', new UID(), 'Project unique ID.') ->param('webhookId', '', new UID(), 'Webhook unique ID.') ->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.') - ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') + ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.') ->param('url', null, new URL(['http', 'https']), 'Webhook URL.') ->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.') ->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true) @@ -885,7 +864,6 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -909,8 +887,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->setAttribute('url', $url) ->setAttribute('security', $security) ->setAttribute('httpUser', $httpUser) - ->setAttribute('httpPass', $httpPass) - ; + ->setAttribute('httpPass', $httpPass); $dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook); $dbForConsole->deleteCachedDocument('projects', $project->getId()); @@ -933,7 +910,6 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -971,7 +947,6 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1008,12 +983,11 @@ App::post('/v1/projects/:projectId/keys') ->label('sdk.response.model', Response::MODEL_KEY) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') - ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.') + ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' scopes are allowed.') ->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1060,7 +1034,6 @@ App::get('/v1/projects/:projectId/keys') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1093,7 +1066,6 @@ App::get('/v1/projects/:projectId/keys/:keyId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1125,12 +1097,11 @@ App::put('/v1/projects/:projectId/keys/:keyId') ->param('projectId', '', new UID(), 'Project unique ID.') ->param('keyId', '', new UID(), 'Key unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') - ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') + ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.') ->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $keyId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1149,8 +1120,7 @@ App::put('/v1/projects/:projectId/keys/:keyId') $key ->setAttribute('name', $name) ->setAttribute('scopes', $scopes) - ->setAttribute('expire', $expire) - ; + ->setAttribute('expire', $expire); $dbForConsole->updateDocument('keys', $key->getId(), $key); @@ -1173,7 +1143,6 @@ App::delete('/v1/projects/:projectId/keys/:keyId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1236,7 +1205,7 @@ App::post('/v1/projects/:projectId/platforms') 'name' => $name, 'key' => $key, 'store' => $store, - 'hostname' => $hostname + 'hostname' => $hostname, ]); $platform = $dbForConsole->createDocument('platforms', $platform); @@ -1262,7 +1231,6 @@ App::get('/v1/projects/:projectId/platforms') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1295,7 +1263,6 @@ App::get('/v1/projects/:projectId/platforms/:platformId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1352,8 +1319,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId') ->setAttribute('name', $name) ->setAttribute('key', $key) ->setAttribute('store', $store) - ->setAttribute('hostname', $hostname) - ; + ->setAttribute('hostname', $hostname); $dbForConsole->updateDocument('platforms', $platform->getId(), $platform); @@ -1376,7 +1342,6 @@ App::delete('/v1/projects/:projectId/platforms/:platformId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1416,7 +1381,6 @@ App::post('/v1/projects/:projectId/domains') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $domain, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1428,17 +1392,17 @@ App::post('/v1/projects/:projectId/domains') } $document = $dbForConsole->findOne('domains', [ - Query::equal('domain', [$domain]) + Query::equal('domain', [$domain]), ]); - if ($document && !$document->isEmpty()) { + if ($document && ! $document->isEmpty()) { throw new Exception(Exception::DOMAIN_ALREADY_EXISTS); } $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); - if (!$target->isKnown() || $target->isTest()) { - throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target (' . $target->get() . '). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.'); + if (! $target->isKnown() || $target->isTest()) { + throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target ('.$target->get().'). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.'); } $domain = new Domain($domain); @@ -1483,7 +1447,6 @@ App::get('/v1/projects/:projectId/domains') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1516,7 +1479,6 @@ App::get('/v1/projects/:projectId/domains/:domainId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1550,7 +1512,6 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1568,8 +1529,8 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); - if (!$target->isKnown() || $target->isTest()) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.'); + if (! $target->isKnown() || $target->isTest()) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.'); } if ($domain->getAttribute('verification') === true) { @@ -1578,11 +1539,10 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $validator = new CNAME($target->get()); // Verify Domain with DNS records - if (!$validator->isValid($domain->getAttribute('domain', ''))) { + if (! $validator->isValid($domain->getAttribute('domain', ''))) { throw new Exception(Exception::DOMAIN_VERIFICATION_FAILED); } - $dbForConsole->updateDocument('domains', $domain->getId(), $domain->setAttribute('verification', true)); $dbForConsole->deleteCachedDocument('projects', $project->getId()); @@ -1610,7 +1570,6 @@ App::delete('/v1/projects/:projectId/domains/:domainId') ->inject('dbForConsole') ->inject('deletes') ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole, Delete $deletes) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1663,7 +1622,6 @@ App::patch('/v1/projects/:projectId/smtp') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, bool $enabled, string $sender, string $host, int $port, string $username, string $password, string $secure, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1681,7 +1639,7 @@ App::patch('/v1/projects/:projectId/smtp') $mail->SMTPAutoTLS = false; $valid = $mail->SmtpConnect(); - if (!$valid) { + if (! $valid) { throw new Exception(Exception::GENERAL_SMTP_DISABLED); } @@ -1712,11 +1670,10 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale') ->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1724,11 +1681,11 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale') } $templates = $project->getAttribute('templates', []); - $template = $templates['sms.' . $type . '-' . $locale] ?? null; + $template = $templates['sms.'.$type.'-'.$locale] ?? null; if (is_null($template)) { $template = [ - 'message' => Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl')->render(), + 'message' => Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl')->render(), ]; } @@ -1750,11 +1707,10 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale') ->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1762,11 +1718,11 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale') } $templates = $project->getAttribute('templates', []); - $template = $templates['email.' . $type . '-' . $locale] ?? null; + $template = $templates['email.'.$type.'-'.$locale] ?? null; $localeObj = new Locale($locale); if (is_null($template)) { - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $message = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); $message = $message ->setParam('{{hello}}', $localeObj->getText("emails.{$type}.hello")) ->setParam('{{name}}', '') @@ -1781,12 +1737,12 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale') ->render(); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($localeObj->getText('emails.sender'), $project->getAttribute('name')); - $from = empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from; + $from = empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')) : $from; $template = [ 'message' => $message, - 'subject' => $localeObj->getText('emails.' . $type . '.subject'), + 'subject' => $localeObj->getText('emails.'.$type.'.subject'), 'senderEmail' => App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', ''), - 'senderName' => $from + 'senderName' => $from, ]; } @@ -1808,12 +1764,11 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale') ->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->param('message', '', new Text(0), 'Template message') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, string $message, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1821,8 +1776,8 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale') } $templates = $project->getAttribute('templates', []); - $templates['sms.' . $type . '-' . $locale] = [ - 'message' => $message + $templates['sms.'.$type.'-'.$locale] = [ + 'message' => $message, ]; $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates)); @@ -1846,7 +1801,7 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale') ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->param('senderName', '', new Text(255), 'Name of the email sender') ->param('senderEmail', '', new Email(), 'Email of the sender') ->param('subject', '', new Text(255), 'Email Subject') @@ -1855,7 +1810,6 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, string $senderName, string $senderEmail, string $subject, string $message, string $replyTo, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1863,12 +1817,12 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale') } $templates = $project->getAttribute('templates', []); - $templates['email.' . $type . '-' . $locale] = [ + $templates['email.'.$type.'-'.$locale] = [ 'senderName' => $senderName, 'senderEmail' => $senderEmail, 'subject' => $subject, 'replyTo' => $replyTo, - 'message' => $message + 'message' => $message, ]; $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates)); @@ -1880,7 +1834,7 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale') 'senderEmail' => $senderEmail, 'subject' => $subject, 'replyTo' => $replyTo, - 'message' => $message + 'message' => $message, ]), Response::MODEL_EMAIL_TEMPLATE); }); @@ -1896,11 +1850,10 @@ App::delete('/v1/projects/:projectId/templates/sms/:type/:locale') ->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1908,20 +1861,20 @@ App::delete('/v1/projects/:projectId/templates/sms/:type/:locale') } $templates = $project->getAttribute('templates', []); - $template = $templates['sms.' . $type . '-' . $locale] ?? null; + $template = $templates['sms.'.$type.'-'.$locale] ?? null; if (is_null($template)) { throw new Exception(Exception::PROJECT_TEMPLATE_DEFAULT_DELETION); } - unset($template['sms.' . $type . '-' . $locale]); + unset($template['sms.'.$type.'-'.$locale]); $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates)); $response->dynamic(new Document([ 'type' => $type, 'locale' => $locale, - 'message' => $template['message'] + 'message' => $template['message'], ]), Response::MODEL_SMS_TEMPLATE); }); @@ -1937,11 +1890,10 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale') ->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1949,13 +1901,13 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale') } $templates = $project->getAttribute('templates', []); - $template = $templates['email.' . $type . '-' . $locale] ?? null; + $template = $templates['email.'.$type.'-'.$locale] ?? null; if (is_null($template)) { throw new Exception(Exception::PROJECT_TEMPLATE_DEFAULT_DELETION); } - unset($templates['email.' . $type . '-' . $locale]); + unset($templates['email.'.$type.'-'.$locale]); $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates)); @@ -1966,6 +1918,6 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale') 'senderEmail' => $template['senderEmail'], 'subject' => $template['subject'], 'replyTo' => $template['replyTo'], - 'message' => $template['message'] + 'message' => $template['message'], ]), Response::MODEL_EMAIL_TEMPLATE); }); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index c34515b5e1..3206e2231f 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -4,28 +4,27 @@ use Appwrite\Auth\Auth; use Appwrite\ClamAV\Network; use Appwrite\Event\Delete; use Appwrite\Event\Event; -use Appwrite\Utopia\Database\Validator\CustomId; +use Appwrite\Extend\Exception; use Appwrite\OpenSSL\OpenSSL; +use Appwrite\Utopia\Database\Validator\CustomId; +use Appwrite\Utopia\Database\Validator\Queries\Buckets; +use Appwrite\Utopia\Database\Validator\Queries\Files; use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\DateTime; -use Utopia\Database\Exception\Duplicate; use Utopia\Database\Exception\Authorization as AuthorizationException; +use Utopia\Database\Exception\Duplicate; use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Query; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; -use Appwrite\Extend\Exception; -use Appwrite\Utopia\Database\Validator\Queries\Buckets; -use Appwrite\Utopia\Database\Validator\Queries\Files; use Utopia\Image\Image; use Utopia\Storage\Compression\Algorithms\GZIP; use Utopia\Storage\Compression\Algorithms\Zstd; @@ -35,14 +34,13 @@ use Utopia\Storage\Validator\File; use Utopia\Storage\Validator\FileExt; use Utopia\Storage\Validator\FileSize; use Utopia\Storage\Validator\Upload; +use Utopia\Swoole\Request; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\HexColor; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; -use Utopia\DSN\DSN; -use Utopia\Swoole\Request; App::post('/v1/storage/buckets') ->desc('Create bucket') @@ -63,16 +61,15 @@ App::post('/v1/storage/buckets') ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true) ->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true) ->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true) - ->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) - ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true) - ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) - ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) - ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) + ->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is '.Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0).'. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) + ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' extensions are allowed, each 64 characters long.', true) + ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd), For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' compression is skipped even if it\'s enabled', true) + ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' encryption is skipped even if it\'s enabled', true) + ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above '.Storage::human(APP_LIMIT_ANTIVIRUS, 0).' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') ->inject('events') ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $events) { - $bucketId = $bucketId === 'unique()' ? ID::unique() : $bucketId; // Map aggregate permissions into the multiple permissions they represent. @@ -97,7 +94,7 @@ App::post('/v1/storage/buckets') 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '' + 'format' => $attribute['format'] ?? '', ]); } @@ -128,14 +125,13 @@ App::post('/v1/storage/buckets') $bucket = $dbForProject->getDocument('buckets', $bucketId); - $dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity); + $dbForProject->createCollection('bucket_'.$bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity); } catch (Duplicate) { throw new Exception(Exception::STORAGE_BUCKET_ALREADY_EXISTS); } $events - ->setParam('bucketId', $bucket->getId()) - ; + ->setParam('bucketId', $bucket->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -153,15 +149,14 @@ App::get('/v1/storage/buckets') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_BUCKET_LIST) - ->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Buckets::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Buckets::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { - $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -203,7 +198,6 @@ App::get('/v1/storage/buckets/:bucketId') ->inject('response') ->inject('dbForProject') ->action(function (string $bucketId, Response $response, Database $dbForProject) { - $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -232,11 +226,11 @@ App::put('/v1/storage/buckets/:bucketId') ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true) ->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true) ->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true) - ->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) - ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true) - ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) - ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) - ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) + ->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is '.Storage::human((int) App::getEnv('_APP_STORAGE_LIMIT', 0), 0).'. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) + ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' extensions are allowed, each 64 characters long.', true) + ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd), For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' compression is skipped even if it\'s enabled', true) + ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' encryption is skipped even if it\'s enabled', true) + ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above '.Storage::human(APP_LIMIT_ANTIVIRUS, 0).' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') ->inject('events') @@ -271,11 +265,10 @@ App::put('/v1/storage/buckets/:bucketId') ->setAttribute('encryption', $encryption) ->setAttribute('compression', $compression) ->setAttribute('antivirus', $antivirus)); - $dbForProject->updateCollection('bucket_' . $bucket->getInternalId(), $permissions, $fileSecurity); + $dbForProject->updateCollection('bucket_'.$bucket->getInternalId(), $permissions, $fileSecurity); $events - ->setParam('bucketId', $bucket->getId()) - ; + ->setParam('bucketId', $bucket->getId()); $response->dynamic($bucket, Response::MODEL_BUCKET); }); @@ -305,7 +298,7 @@ App::delete('/v1/storage/buckets/:bucketId') throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - if (!$dbForProject->deleteDocument('buckets', $bucketId)) { + if (! $dbForProject->deleteDocument('buckets', $bucketId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove bucket from DB'); } @@ -315,8 +308,7 @@ App::delete('/v1/storage/buckets/:bucketId') $events ->setParam('bucketId', $bucket->getId()) - ->setPayload($response->output($bucket, Response::MODEL_BUCKET)) - ; + ->setPayload($response->output($bucket, Response::MODEL_BUCKET)); $response->noContent(); }); @@ -354,15 +346,14 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('deviceFiles') ->inject('deviceLocal') ->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $validator = new Authorization(Database::PERMISSION_CREATE); - if (!$validator->isValid($bucket->getCreate())) { + if (! $validator->isValid($bucket->getCreate())) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -378,7 +369,7 @@ App::post('/v1/storage/buckets/:bucketId/files') // Add permissions for current the user if none were provided. if (\is_null($permissions)) { $permissions = []; - if (!empty($user->getId())) { + if (! empty($user->getId())) { foreach ($allowedPermissions as $permission) { $permissions[] = (new Permission($permission, 'user', $user->getId()))->toString(); } @@ -387,7 +378,7 @@ App::post('/v1/storage/buckets/:bucketId/files') // Users can only manage their own roles, API keys and Admin users can manage any $roles = Authorization::getRoles(); - if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { + if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -399,8 +390,8 @@ App::post('/v1/storage/buckets/:bucketId/files') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); + if (! Authorization::isRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')'); } } } @@ -411,7 +402,6 @@ App::post('/v1/storage/buckets/:bucketId/files') throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Maximum bucket file size is larger than _APP_STORAGE_LIMIT'); } - $file = $request->getFiles('file'); // GraphQL multipart spec adds files with index keys @@ -433,7 +423,7 @@ App::post('/v1/storage/buckets/:bucketId/files') $chunk = 1; $chunks = 1; - if (!empty($contentRange)) { + if (! empty($contentRange)) { $start = $request->getContentRangeStart(); $end = $request->getContentRangeEnd(); $fileSize = $request->getContentRangeSize(); @@ -444,7 +434,7 @@ App::post('/v1/storage/buckets/:bucketId/files') } $idValidator = new UID(); - if (!$idValidator->isValid($request->getHeader('x-appwrite-id'))) { + if (! $idValidator->isValid($request->getHeader('x-appwrite-id'))) { throw new Exception(Exception::STORAGE_INVALID_APPWRITE_ID); } @@ -465,30 +455,30 @@ App::post('/v1/storage/buckets/:bucketId/files') // Check if file type is allowed $allowedFileExtensions = $bucket->getAttribute('allowedFileExtensions', []); $fileExt = new FileExt($allowedFileExtensions); - if (!empty($allowedFileExtensions) && !$fileExt->isValid($fileName)) { + if (! empty($allowedFileExtensions) && ! $fileExt->isValid($fileName)) { throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED, 'File extension not allowed'); } // Check if file size is exceeding allowed limit $fileSizeValidator = new FileSize($maximumFileSize); - if (!$fileSizeValidator->isValid($fileSize)) { + if (! $fileSizeValidator->isValid($fileSize)) { throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE, 'File size not allowed'); } $upload = new Upload(); - if (!$upload->isValid($fileTmpName)) { + if (! $upload->isValid($fileTmpName)) { throw new Exception(Exception::STORAGE_INVALID_FILE); } // Save to storage $fileSize ??= $deviceLocal->getFileSize($fileTmpName); - $path = $deviceFiles->getPath($fileId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION)); - $path = str_ireplace($deviceFiles->getRoot(), $deviceFiles->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $path); // Add bucket id to path after root + $path = $deviceFiles->getPath($fileId.'.'.\pathinfo($fileName, PATHINFO_EXTENSION)); + $path = str_ireplace($deviceFiles->getRoot(), $deviceFiles->getRoot().DIRECTORY_SEPARATOR.$bucket->getId(), $path); // Add bucket id to path after root - $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); + $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); $metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)]; - if (!$file->isEmpty()) { + if (! $file->isEmpty()) { $chunks = $file->getAttribute('chunksTotal', 1); $metadata = $file->getAttribute('metadata', []); if ($chunk === -1) { @@ -508,7 +498,7 @@ App::post('/v1/storage/buckets/:bucketId/files') (int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310) ); - if (!$antivirus->fileScan($path)) { + if (! $antivirus->fileScan($path)) { $deviceFiles->delete($path); throw new Exception(Exception::STORAGE_INVALID_FILE); } @@ -542,8 +532,8 @@ App::post('/v1/storage/buckets/:bucketId/files') $data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag); } - if (!empty($data)) { - if (!$deviceFiles->write($path, $data, $mimeType)) { + if (! empty($data)) { + if (! $deviceFiles->write($path, $data, $mimeType)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to save file'); } } @@ -587,7 +577,7 @@ App::post('/v1/storage/buckets/:bucketId/files') 'metadata' => $metadata, ]); - $file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc); + $file = $dbForProject->createDocument('bucket_'.$bucket->getInternalId(), $doc); } else { $file = $file ->setAttribute('$permissions', $permissions) @@ -602,7 +592,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->setAttribute('metadata', $metadata) ->setAttribute('chunksUploaded', $chunksUploaded); - $file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file); + $file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file); } } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); @@ -633,13 +623,13 @@ App::post('/v1/storage/buckets/:bucketId/files') 'metadata' => $metadata, ]); - $file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc); + $file = $dbForProject->createDocument('bucket_'.$bucket->getInternalId(), $doc); } else { $file = $file ->setAttribute('chunksUploaded', $chunksUploaded) ->setAttribute('metadata', $metadata); - $file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file); + $file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file); } } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); @@ -653,8 +643,7 @@ App::post('/v1/storage/buckets/:bucketId/files') $events ->setParam('bucketId', $bucket->getId()) ->setParam('fileId', $file->getId()) - ->setContext('bucket', $bucket) - ; + ->setContext('bucket', $bucket); $metadata = null; // was causing leaks as it was passed by reference @@ -676,29 +665,28 @@ App::get('/v1/storage/buckets/:bucketId/files') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_FILE_LIST) ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') - ->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Files::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') ->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (!$fileSecurity && !$valid) { + if (! $fileSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -709,10 +697,10 @@ App::get('/v1/storage/buckets/:bucketId/files') /** @var Query $cursor */ $fileId = $cursor->getValue(); - if ($fileSecurity && !$valid) { - $cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); + if ($fileSecurity && ! $valid) { + $cursorDocument = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); } else { - $cursorDocument = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); } if ($cursorDocument->isEmpty()) { @@ -724,12 +712,12 @@ App::get('/v1/storage/buckets/:bucketId/files') $filterQueries = Query::groupByType($queries)['filters']; - if ($fileSecurity && !$valid) { - $files = $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries); - $total = $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT); + if ($fileSecurity && ! $valid) { + $files = $dbForProject->find('bucket_'.$bucket->getInternalId(), $queries); + $total = $dbForProject->count('bucket_'.$bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT); } else { - $files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries)); - $total = Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT)); + $files = Authorization::skip(fn () => $dbForProject->find('bucket_'.$bucket->getInternalId(), $queries)); + $total = Authorization::skip(fn () => $dbForProject->count('bucket_'.$bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT)); } $response->dynamic(new Document([ @@ -756,24 +744,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('dbForProject') ->inject('mode') ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, string $mode) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (!$fileSecurity && !$valid) { + if (! $fileSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } - if ($fileSecurity && !$valid) { - $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); + if ($fileSecurity && ! $valid) { + $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -802,7 +789,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->param('fileId', '', new UID(), 'File ID') ->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true) ->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true) - ->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of ' . implode(",", Image::getGravityTypes()), true) + ->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of '.implode(',', Image::getGravityTypes()), true) ->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true) ->param('borderWidth', 0, new Range(0, 100), 'Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.', true) ->param('borderColor', '', new HexColor(), 'Preview image border color. Use a valid HEX color, no # is needed for prefix.', true) @@ -819,21 +806,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->inject('deviceFiles') ->inject('deviceLocal') ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Request $request, Response $response, Document $project, Database $dbForProject, string $mode, Device $deviceFiles, Device $deviceLocal) { - - if (!\extension_loaded('imagick')) { + if (! \extension_loaded('imagick')) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); } $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (!$fileSecurity && !$valid) { + if (! $fileSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -845,10 +831,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $outputs = Config::getParam('storage-outputs'); $fileLogos = Config::getParam('storage-logos'); - if ($fileSecurity && !$valid) { - $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); + if ($fileSecurity && ! $valid) { + $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -860,8 +846,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $algorithm = $file->getAttribute('algorithm', 'none'); $cipher = $file->getAttribute('openSSLCipher'); $mime = $file->getAttribute('mimeType'); - if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) { - if (!\in_array($mime, $inputs)) { + if (! \in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) { + if (! \in_array($mime, $inputs)) { $path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default']; } else { // it was an image but the file size exceeded the limit @@ -875,7 +861,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $deviceFiles = $deviceLocal; } - if (!$deviceFiles->exists($path)) { + if (! $deviceFiles->exists($path)) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } @@ -885,14 +871,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type; } - $source = $deviceFiles->read($path); - if (!empty($cipher)) { // Decrypt + if (! empty($cipher)) { // Decrypt $source = OpenSSL::decrypt( $source, $file->getAttribute('openSSLCipher'), - App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')), + App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')), 0, \hex2bin($file->getAttribute('openSSLIV')), \hex2bin($file->getAttribute('openSSLTag')) @@ -914,23 +899,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $image->crop((int) $width, (int) $height, $gravity); - if (!empty($opacity) || $opacity === 0) { + if (! empty($opacity) || $opacity === 0) { $image->setOpacity($opacity); } - if (!empty($background)) { - $image->setBackground('#' . $background); + if (! empty($background)) { + $image->setBackground('#'.$background); } - if (!empty($borderWidth)) { - $image->setBorder($borderWidth, '#' . $borderColor); + if (! empty($borderWidth)) { + $image->setBorder($borderWidth, '#'.$borderColor); } - if (!empty($borderRadius)) { + if (! empty($borderRadius)) { $image->setBorderRadius($borderRadius); } - if (!empty($rotation)) { + if (! empty($rotation)) { $image->setRotation(($rotation + 360) % 360); } @@ -939,10 +924,9 @@ 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('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT') ->setContentType($contentType) - ->file($data) - ; + ->file($data); unset($image); }); @@ -967,24 +951,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->inject('mode') ->inject('deviceFiles') ->action(function (string $bucketId, string $fileId, Request $request, Response $response, Database $dbForProject, string $mode, Device $deviceFiles) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (!$fileSecurity && !$valid) { + if (! $fileSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } - if ($fileSecurity && !$valid) { - $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); + if ($fileSecurity && ! $valid) { + $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -993,21 +976,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $path = $file->getAttribute('path', ''); - if (!$deviceFiles->exists($path)) { - throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path); + if (! $deviceFiles->exists($path)) { + throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in '.$path); } $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('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache ->addHeader('X-Peak', \memory_get_peak_usage()) - ->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"') - ; + ->addHeader('Content-Disposition', 'attachment; filename="'.$file->getAttribute('name', '').'"'); $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); - if (!empty($rangeHeader)) { + if (! empty($rangeHeader)) { $start = $request->getRangeStart(); $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); @@ -1022,18 +1004,18 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $response ->addHeader('Accept-Ranges', 'bytes') - ->addHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $size) + ->addHeader('Content-Range', 'bytes '.$start.'-'.$end.'/'.$size) ->addHeader('Content-Length', $end - $start + 1) ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } $source = ''; - if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt + if (! empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceFiles->read($path); $source = OpenSSL::decrypt( $source, $file->getAttribute('openSSLCipher'), - App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')), + App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')), 0, \hex2bin($file->getAttribute('openSSLIV')), \hex2bin($file->getAttribute('openSSLTag')) @@ -1057,14 +1039,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') break; } - if (!empty($source)) { - if (!empty($rangeHeader)) { + if (! empty($source)) { + if (! empty($rangeHeader)) { $response->send(substr($source, $start, ($end - $start + 1))); } $response->send($source); } - if (!empty($rangeHeader)) { + if (! empty($rangeHeader)) { $response->send($deviceFiles->read($path, $start, ($end - $start + 1))); } @@ -1105,24 +1087,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->inject('mode') ->inject('deviceFiles') ->action(function (string $bucketId, string $fileId, Response $response, Request $request, Database $dbForProject, string $mode, Device $deviceFiles) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (!$fileSecurity && !$valid) { + if (! $fileSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } - if ($fileSecurity && !$valid) { - $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); + if ($fileSecurity && ! $valid) { + $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -1133,8 +1114,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $path = $file->getAttribute('path', ''); - if (!$deviceFiles->exists($path)) { - throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path); + if (! $deviceFiles->exists($path)) { + throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in '.$path); } $contentType = 'text/plain'; @@ -1147,15 +1128,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->setContentType($contentType) ->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('X-Peak', \memory_get_peak_usage()) - ; + ->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('X-Peak', \memory_get_peak_usage()); $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); - if (!empty($rangeHeader)) { + if (! empty($rangeHeader)) { $start = $request->getRangeStart(); $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); @@ -1176,12 +1156,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') } $source = ''; - if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt + if (! empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceFiles->read($path); $source = OpenSSL::decrypt( $source, $file->getAttribute('openSSLCipher'), - App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')), + App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')), 0, \hex2bin($file->getAttribute('openSSLIV')), \hex2bin($file->getAttribute('openSSLTag')) @@ -1205,14 +1185,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') break; } - if (!empty($source)) { - if (!empty($rangeHeader)) { + if (! empty($source)) { + if (! empty($rangeHeader)) { $response->send(substr($source, $start, ($end - $start + 1))); } $response->send($source); } - if (!empty($rangeHeader)) { + if (! empty($rangeHeader)) { $response->send($deviceFiles->read($path, $start, ($end - $start + 1))); } @@ -1262,22 +1242,21 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('mode') ->inject('events') ->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $events) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttributes('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_UPDATE); $valid = $validator->isValid($bucket->getUpdate()); - if (!$fileSecurity && !$valid) { + if (! $fileSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } // Read permission should not be required for update - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); @@ -1292,7 +1271,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') // Users can only manage their own roles, API keys and Admin users can manage any $roles = Authorization::getRoles(); - if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) { + if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles) && ! \is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -1304,8 +1283,8 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (!Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); + if (! Authorization::isRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')'); } } } @@ -1317,25 +1296,24 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') $file->setAttribute('$permissions', $permissions); - if (!is_null($name)) { + if (! is_null($name)) { $file->setAttribute('name', $name); } - if ($fileSecurity && !$valid) { + if ($fileSecurity && ! $valid) { try { - $file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file); + $file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file); } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } } else { - $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); + $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file)); } $events ->setParam('bucketId', $bucket->getId()) ->setParam('fileId', $file->getId()) - ->setContext('bucket', $bucket) - ; + ->setContext('bucket', $bucket); $response->dynamic($file, Response::MODEL_FILE); }); @@ -1368,26 +1346,26 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, string $mode, Device $deviceFiles, Delete $deletes) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttributes('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_DELETE); $valid = $validator->isValid($bucket->getDelete()); - if (!$fileSecurity && !$valid) { + if (! $fileSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } // Read permission should not be required for delete - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } // Make sure we don't delete the file before the document permission check occurs - if ($fileSecurity && !$valid && !$validator->isValid($file->getDelete())) { + if ($fileSecurity && ! $valid && ! $validator->isValid($file->getDelete())) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -1404,20 +1382,19 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') if ($deviceDeleted) { $deletes ->setType(DELETE_TYPE_CACHE_BY_RESOURCE) - ->setResource('file/' . $fileId) - ; + ->setResource('file/'.$fileId); - if ($fileSecurity && !$valid) { + if ($fileSecurity && ! $valid) { try { - $deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId); + $deleted = $dbForProject->deleteDocument('bucket_'.$bucket->getInternalId(), $fileId); } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } } else { - $deleted = Authorization::skip(fn() => $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_'.$bucket->getInternalId(), $fileId)); } - if (!$deleted) { + if (! $deleted) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove file from DB'); } } else { @@ -1428,8 +1405,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->setParam('bucketId', $bucket->getId()) ->setParam('fileId', $file->getId()) ->setContext('bucket', $bucket) - ->setPayload($response->output($file, Response::MODEL_FILE)) - ; + ->setPayload($response->output($file, Response::MODEL_FILE)); $response->noContent(); }); @@ -1448,7 +1424,6 @@ App::get('/v1/storage/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { - $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -1518,7 +1493,6 @@ App::get('/v1/storage/:bucketId/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $bucketId, string $range, Response $response, Database $dbForProject) { - $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index e03e481d7c..e50378f4b6 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -9,14 +9,10 @@ use Appwrite\Event\Mail; use Appwrite\Event\Phone as EventPhone; use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; -use Utopia\Validator\Host; use Appwrite\Template\Template; use Appwrite\Utopia\Database\Validator\CustomId; -use Utopia\Database\Validator\Queries; use Appwrite\Utopia\Database\Validator\Queries\Memberships; use Appwrite\Utopia\Database\Validator\Queries\Teams; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use MaxMind\Db\Reader; @@ -24,20 +20,24 @@ use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; use Utopia\Database\Database; +use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Authorization as AuthorizationException; use Utopia\Database\Exception\Duplicate; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Query; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; +use Utopia\Validator\Host; use Utopia\Validator\Text; App::post('/v1/teams') @@ -56,20 +56,19 @@ App::post('/v1/teams') ->label('sdk.response.model', Response::MODEL_TEAM) ->param('teamId', '', new CustomId(), 'Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', null, new Text(128), 'Team name. Max length: 128 chars.') - ->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', true) + ->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.', true) ->inject('response') ->inject('user') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $events) { - $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); $teamId = $teamId == 'unique()' ? ID::unique() : $teamId; try { - $team = Authorization::skip(fn() => $dbForProject->createDocument('teams', new Document([ + $team = Authorization::skip(fn () => $dbForProject->createDocument('teams', new Document([ '$id' => $teamId, '$permissions' => [ Permission::read(Role::team($teamId)), @@ -85,8 +84,8 @@ App::post('/v1/teams') throw new Exception(Exception::TEAM_ALREADY_EXISTS); } - if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode - if (!\in_array('owner', $roles)) { + if (! $isPrivilegedUser && ! $isAppUser) { // Don't add user on server mode + if (! \in_array('owner', $roles)) { $roles[] = 'owner'; } @@ -110,7 +109,7 @@ App::post('/v1/teams') 'joined' => DateTime::now(), 'confirm' => true, 'secret' => '', - 'search' => implode(' ', [$membershipId, $user->getId()]) + 'search' => implode(' ', [$membershipId, $user->getId()]), ]); $membership = $dbForProject->createDocument('memberships', $membership); @@ -119,7 +118,7 @@ App::post('/v1/teams') $events->setParam('teamId', $team->getId()); - if (!empty($user->getId())) { + if (! empty($user->getId())) { $events->setParam('userId', $user->getId()); } @@ -140,15 +139,14 @@ App::get('/v1/teams') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TEAM_LIST) ->label('sdk.offline.model', '/teams') - ->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Teams::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { - $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -195,7 +193,6 @@ App::get('/v1/teams/:teamId') ->inject('response') ->inject('dbForProject') ->action(function (string $teamId, Response $response, Database $dbForProject) { - $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -221,7 +218,6 @@ App::get('/v1/teams/:teamId/prefs') ->inject('response') ->inject('dbForProject') ->action(function (string $teamId, Response $response, Database $dbForProject) { - $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -256,7 +252,6 @@ App::put('/v1/teams/:teamId') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, string $name, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events) { - $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -298,7 +293,6 @@ App::put('/v1/teams/:teamId/prefs') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, array $prefs, Response $response, Database $dbForProject, Event $events) { - $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -331,14 +325,13 @@ App::delete('/v1/teams/:teamId') ->inject('events') ->inject('deletes') ->action(function (string $teamId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { - $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); } - if (!$dbForProject->deleteDocument('teams', $teamId)) { + if (! $dbForProject->deleteDocument('teams', $teamId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove team from DB'); } @@ -348,8 +341,7 @@ App::delete('/v1/teams/:teamId') $events ->setParam('teamId', $team->getId()) - ->setPayload($response->output($team, Response::MODEL_TEAM)) - ; + ->setPayload($response->output($team, Response::MODEL_TEAM)); $response->noContent(); }); @@ -375,8 +367,8 @@ 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](/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') - ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page + ->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](/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.') + ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['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') ->inject('project') @@ -387,14 +379,13 @@ App::post('/v1/teams/:teamId/memberships') ->inject('messaging') ->inject('events') ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, EventPhone $messaging, Event $events) { - if (empty($userId) && empty($email) && empty($phone)) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'At least one of userId, email, or phone is required'); } $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); - if (!$isPrivilegedUser && !$isAppUser && empty(App::getEnv('_APP_SMTP_HOST'))) { + if (! $isPrivilegedUser && ! $isAppUser && empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED); } @@ -405,28 +396,28 @@ App::post('/v1/teams/:teamId/memberships') if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); } - if (!empty($userId)) { + if (! empty($userId)) { $invitee = $dbForProject->getDocument('users', $userId); if ($invitee->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND, 'User with given userId doesn\'t exist.', 404); } - if (!empty($email) && $invitee->getAttribute('email', '') !== $email) { + if (! empty($email) && $invitee->getAttribute('email', '') !== $email) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and email doesn\'t match', 409); } - if (!empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { + if (! empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and phone doesn\'t match', 409); } $email = $invitee->getAttribute('email', ''); $phone = $invitee->getAttribute('phone', ''); $name = empty($name) ? $invitee->getAttribute('name', '') : $name; - } elseif (!empty($email)) { + } elseif (! empty($email)) { $invitee = $dbForProject->findOne('users', [Query::equal('email', [$email])]); // Get user by email address - if (!empty($invitee) && !empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { + if (! empty($invitee) && ! empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given email and phone doesn\'t match', 409); } - } elseif (!empty($phone)) { + } elseif (! empty($phone)) { $invitee = $dbForProject->findOne('users', [Query::equal('phone', [$phone])]); - if (!empty($invitee) && !empty($email) && $invitee->getAttribute('email', '') !== $email) { + if (! empty($invitee) && ! empty($email) && $invitee->getAttribute('email', '') !== $email) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given phone and email doesn\'t match', 409); } } @@ -446,13 +437,13 @@ App::post('/v1/teams/:teamId/memberships') $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } try { $userId = ID::unique(); - $invitee = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([ + $invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([ '$id' => $userId, '$permissions' => [ Permission::read(Role::any()), @@ -480,16 +471,16 @@ App::post('/v1/teams/:teamId/memberships') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]) + 'search' => implode(' ', [$userId, $email, $name]), ]))); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); } } - $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); + $isOwner = Authorization::isRole('team:'.$team->getId().'/owner'); - if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) + if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to send invitations for this team'); } @@ -514,17 +505,17 @@ App::post('/v1/teams/:teamId/memberships') 'joined' => ($isPrivilegedUser || $isAppUser) ? DateTime::now() : null, 'confirm' => ($isPrivilegedUser || $isAppUser), 'secret' => Auth::hash($secret), - 'search' => implode(' ', [$membershipId, $invitee->getId()]) + 'search' => implode(' ', [$membershipId, $invitee->getId()]), ]); if ($isPrivilegedUser || $isAppUser) { // Allow admin to create membership try { - $membership = Authorization::skip(fn() => $dbForProject->createDocument('memberships', $membership)); + $membership = Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership)); } catch (Duplicate $th) { throw new Exception(Exception::TEAM_INVITE_ALREADY_EXISTS); } $team->setAttribute('total', $team->getAttribute('total', 0) + 1); - $team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team)); + $team = Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team)); $dbForProject->deleteCachedDocument('users', $invitee->getId()); } else { @@ -537,16 +528,16 @@ App::post('/v1/teams/:teamId/memberships') $url = Template::parseURL($url); $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]); $url = Template::unParseURL($url); - if (!empty($email)) { + if (! empty($email)) { $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); - $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); - $subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName); + $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); + $subject = \sprintf($locale->getText('emails.invitation.subject'), $team->getAttribute('name'), $projectName); $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; - $customTemplate = $project->getAttribute('templates', [])['email.invitation-' . $locale->default] ?? []; - if ($smtpEnabled && !empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['email.invitation-'.$locale->default] ?? []; + if ($smtpEnabled && ! empty($customTemplate)) { $body = $customTemplate['message']; $subject = $customTemplate['subject']; $from = $customTemplate['senderName']; @@ -557,13 +548,13 @@ App::post('/v1/teams/:teamId/memberships') $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.invitation.hello")) + ->setParam('{{hello}}', $locale->getText('emails.invitation.hello')) ->setParam('{{name}}', $user->getAttribute('name')) - ->setParam('{{body}}', $locale->getText("emails.invitation.body")) + ->setParam('{{body}}', $locale->getText('emails.invitation.body')) ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText("emails.invitation.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.invitation.signature")) + ->setParam('{{footer}}', $locale->getText('emails.invitation.footer')) + ->setParam('{{thanks}}', $locale->getText('emails.invitation.thanks')) + ->setParam('{{signature}}', $locale->getText('emails.invitation.signature')) ->setParam('{{project}}', $projectName) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -578,13 +569,12 @@ App::post('/v1/teams/:teamId/memberships') ->setFrom($from) ->setRecipient($invitee->getAttribute('email')) ->setName($invitee->getAttribute('name')) - ->trigger() - ; - } elseif (!empty($phone)) { - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl'); + ->trigger(); + } elseif (! empty($phone)) { + $message = Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl'); - $customTemplate = $project->getAttribute('templates', [])['sms.invitation-' . $locale->default] ?? []; - if (!empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['sms.invitation-'.$locale->default] ?? []; + if (! empty($customTemplate)) { $message = $customTemplate['message']; } @@ -600,8 +590,7 @@ App::post('/v1/teams/:teamId/memberships') $events ->setParam('teamId', $team->getId()) - ->setParam('membershipId', $membership->getId()) - ; + ->setParam('membershipId', $membership->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -627,12 +616,11 @@ App::get('/v1/teams/:teamId/memberships') ->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST) ->label('sdk.offline.model', '/teams/{teamId}/memberships') ->param('teamId', '', new UID(), 'Team ID.') - ->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Memberships::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (string $teamId, array $queries, string $search, Response $response, Database $dbForProject) { - $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -641,7 +629,7 @@ App::get('/v1/teams/:teamId/memberships') $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -676,7 +664,7 @@ App::get('/v1/teams/:teamId/memberships') max: APP_LIMIT_COUNT ); - $memberships = array_filter($memberships, fn(Document $membership) => !empty($membership->getAttribute('userId'))); + $memberships = array_filter($memberships, fn (Document $membership) => ! empty($membership->getAttribute('userId'))); $memberships = array_map(function ($membership) use ($dbForProject, $team) { $user = $dbForProject->getDocument('users', $membership->getAttribute('userId')); @@ -684,8 +672,7 @@ App::get('/v1/teams/:teamId/memberships') $membership ->setAttribute('teamName', $team->getAttribute('name')) ->setAttribute('userName', $user->getAttribute('name')) - ->setAttribute('userEmail', $user->getAttribute('email')) - ; + ->setAttribute('userEmail', $user->getAttribute('email')); return $membership; }, $memberships); @@ -714,7 +701,6 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') ->inject('response') ->inject('dbForProject') ->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject) { - $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -732,8 +718,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') $membership ->setAttribute('teamName', $team->getAttribute('name')) ->setAttribute('userName', $user->getAttribute('name')) - ->setAttribute('userEmail', $user->getAttribute('email')) - ; + ->setAttribute('userEmail', $user->getAttribute('email')); $response->dynamic($membership, Response::MODEL_MEMBERSHIP); }); @@ -754,14 +739,13 @@ 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', [], 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.') ->inject('request') ->inject('response') ->inject('user') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) { - $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); @@ -779,9 +763,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); - $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); + $isOwner = Authorization::isRole('team:'.$team->getId().'/owner'); - if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) + if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to modify roles'); } @@ -848,7 +832,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') throw new Exception(Exception::TEAM_MEMBERSHIP_MISMATCH); } - $team = Authorization::skip(fn() => $dbForProject->getDocument('teams', $teamId)); + $team = Authorization::skip(fn () => $dbForProject->getDocument('teams', $teamId)); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); @@ -859,7 +843,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if ($userId !== $membership->getAttribute('userId')) { - throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')'); + throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')'); } if ($user->isEmpty()) { @@ -867,7 +851,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if ($membership->getAttribute('userId') !== $user->getId()) { - throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')'); + throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')'); } if ($membership->getAttribute('confirm') === true) { @@ -876,10 +860,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $membership // Attach user to team ->setAttribute('joined', DateTime::now()) - ->setAttribute('confirm', true) - ; + ->setAttribute('confirm', true); - Authorization::skip(fn() => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); + Authorization::skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); // Log user in @@ -917,23 +900,20 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $dbForProject->deleteCachedDocument('users', $user->getId()); - $team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1))); + $team = Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1))); $events ->setParam('teamId', $team->getId()) - ->setParam('membershipId', $membership->getId()) - ; + ->setParam('membershipId', $membership->getId()); - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response - ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])) - ; + ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } $response - ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) - ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ; + ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); $response->dynamic( $membership @@ -963,7 +943,6 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $events) { - $membership = $dbForProject->getDocument('memberships', $membershipId); if ($membership->isEmpty()) { @@ -998,14 +977,13 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') if ($membership->getAttribute('confirm')) { // Count only confirmed members $team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0)); - Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team)); + Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team)); } $events ->setParam('teamId', $team->getId()) ->setParam('membershipId', $membership->getId()) - ->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP)) - ; + ->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP)); $response->noContent(); }); @@ -1028,7 +1006,6 @@ App::get('/v1/teams/:teamId/logs') ->inject('locale') ->inject('geodb') ->action(function (string $teamId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { - $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -1041,13 +1018,13 @@ App::get('/v1/teams/:teamId/logs') $offset = $grouped['offset'] ?? 0; $audit = new Audit($dbForProject); - $resource = 'team/' . $team->getId(); + $resource = 'team/'.$team->getId(); $logs = $audit->getLogsByResource($resource, $limit, $offset); $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -1075,14 +1052,14 @@ App::get('/v1/teams/:teamId/logs') 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'] + 'deviceModel' => $device['deviceModel'], ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index cf94135351..f868bdd69e 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -2,43 +2,43 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\Validator\Password; +use Appwrite\Auth\Validator\PasswordDictionary; +use Appwrite\Auth\Validator\PasswordHistory; +use Appwrite\Auth\Validator\PersonalData; use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; use Appwrite\Event\Delete; use Appwrite\Event\Event; +use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; use Appwrite\Utopia\Database\Validator\CustomId; -use Utopia\Database\Validator\Queries; use Appwrite\Utopia\Database\Validator\Queries\Identities; use Appwrite\Utopia\Database\Validator\Queries\Users; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; use Appwrite\Utopia\Response; +use MaxMind\Db\Reader; use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; +use Utopia\Database\Database; +use Utopia\Database\DateTime; +use Utopia\Database\Document; +use Utopia\Database\Exception\Duplicate; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Locale\Locale; -use Appwrite\Extend\Exception; -use Utopia\Database\Document; -use Utopia\Database\DateTime; -use Utopia\Database\Exception\Duplicate; -use Utopia\Database\Validator\UID; -use Utopia\Database\Database; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; +use Utopia\Database\Validator\UID; +use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; -use Utopia\Validator\WhiteList; -use Utopia\Validator\Text; use Utopia\Validator\Boolean; -use MaxMind\Db\Reader; use Utopia\Validator\Integer; -use Appwrite\Auth\Validator\PasswordHistory; -use Appwrite\Auth\Validator\PasswordDictionary; -use Appwrite\Auth\Validator\PersonalData; +use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; /** TODO: Remove function when we move to using utopia/platform */ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Document $project, Database $dbForProject, Event $events): Document @@ -46,14 +46,14 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e $hashOptionsObject = (\is_string($hashOptions)) ? \json_decode($hashOptions, true) : $hashOptions; // Cast to JSON array $passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0; - if (!empty($email)) { + if (! empty($email)) { $email = \strtolower($email); // Makes sure this email is not already used in another identity $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } } @@ -65,12 +65,12 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) { $personalDataValidator = new PersonalData($userId, $email, $name, $phone); - if (!$personalDataValidator->isValid($password)) { + if (! $personalDataValidator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA); } } - $password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null; + $password = (! empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null; $user = $dbForProject->createDocument('users', new Document([ '$id' => $userId, '$permissions' => [ @@ -86,7 +86,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'labels' => [], 'password' => $password, 'passwordHistory' => is_null($password) && $passwordHistory === 0 ? [] : [$password], - 'passwordUpdate' => (!empty($password)) ? DateTime::now() : null, + 'passwordUpdate' => (! empty($password)) ? DateTime::now() : null, 'hash' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO : $hash, 'hashOptions' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO_OPTIONS : $hashOptionsObject + ['type' => $hash], 'registration' => DateTime::now(), @@ -96,7 +96,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $phone, $name]) + 'search' => implode(' ', [$userId, $email, $phone, $name]), ])); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); @@ -131,7 +131,6 @@ App::post('/v1/users') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) { - $user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $project, $dbForProject, $events); $response @@ -255,8 +254,8 @@ App::post('/v1/users/sha') ->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Document $project, Database $dbForProject, Event $events) { $options = '{}'; - if (!empty($passwordVersion)) { - $options = '{"version":"' . $passwordVersion . '"}'; + if (! empty($passwordVersion)) { + $options = '{"version":"'.$passwordVersion.'"}'; } $user = createUser('sha', $options, $userId, $email, $password, null, $name, $project, $dbForProject, $events); @@ -329,7 +328,7 @@ App::post('/v1/users/scrypt') 'costCpu' => $passwordCpu, 'costMemory' => $passwordMemory, 'costParallel' => $passwordParallel, - 'length' => $passwordLength + 'length' => $passwordLength, ]; $user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $project, $dbForProject, $events); @@ -365,7 +364,7 @@ App::post('/v1/users/scrypt-modified') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Document $project, Database $dbForProject, Event $events) { - $user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $project, $dbForProject, $events); + $user = createUser('scryptMod', '{"signerKey":"'.$passwordSignerKey.'","saltSeparator":"'.$passwordSaltSeparator.'","salt":"'.$passwordSalt.'"}', $userId, $email, $password, null, $name, $project, $dbForProject, $events); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -406,7 +405,7 @@ App::post('/v1/users/:userId/targets') $target = $dbForProject->getDocument('targets', $targetId); - if (!$target->isEmpty()) { + if (! $target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } @@ -414,7 +413,7 @@ App::post('/v1/users/:userId/targets') '$id' => $targetId, // TO DO: what permissions should be given when created a target. '$permissions' => [ - Permission::read(Role::any()) + Permission::read(Role::any()), ], 'providerId' => $providerId, 'providerInternalId' => $provider->getInternalId(), @@ -442,15 +441,14 @@ App::get('/v1/users') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_USER_LIST) - ->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Users::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { - $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -492,7 +490,6 @@ App::get('/v1/users/:userId') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, Response $response, Database $dbForProject) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -517,7 +514,6 @@ App::get('/v1/users/:userId/prefs') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, Response $response, Database $dbForProject) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -545,7 +541,6 @@ App::get('/v1/users/:userId/targets/:targetId') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, string $targetId, Response $response, Database $dbForProject) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -577,7 +572,6 @@ App::get('/v1/users/:userId/sessions') ->inject('dbForProject') ->inject('locale') ->action(function (string $userId, Response $response, Database $dbForProject, Locale $locale) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -588,8 +582,7 @@ App::get('/v1/users/:userId/sessions') foreach ($sessions as $key => $session) { /** @var Document $session */ - - $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session->setAttribute('countryName', $countryName); $session->setAttribute('current', false); @@ -617,7 +610,6 @@ App::get('/v1/users/:userId/memberships') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, Response $response, Database $dbForProject) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -659,7 +651,6 @@ App::get('/v1/users/:userId/logs') ->inject('locale') ->inject('geodb') ->action(function (string $userId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -678,7 +669,7 @@ App::get('/v1/users/:userId/logs') $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -702,14 +693,14 @@ App::get('/v1/users/:userId/logs') 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'] + 'deviceModel' => $device['deviceModel'], ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -737,7 +728,6 @@ App::get('/v1/users/:userId/targets') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, Response $response, Database $dbForProject) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -763,15 +753,14 @@ App::get('/v1/users/identities') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_IDENTITY_LIST) - ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Identities::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Identities::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { - $queries = Query::parseQueries($queries); - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -819,7 +808,6 @@ App::patch('/v1/users/:userId/status') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, bool $status, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -856,7 +844,6 @@ App::put('/v1/users/:userId/labels') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, array $labels, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -893,7 +880,6 @@ App::patch('/v1/users/:userId/verification') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -928,7 +914,6 @@ App::patch('/v1/users/:userId/verification/phone') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, bool $phoneVerification, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -964,7 +949,6 @@ App::patch('/v1/users/:userId/name') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $name, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1002,7 +986,6 @@ App::patch('/v1/users/:userId/password') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $password, Response $response, Document $project, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1011,7 +994,7 @@ App::patch('/v1/users/:userId/password') if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) { $personalDataValidator = new PersonalData($userId, $user->getAttribute('email'), $user->getAttribute('name'), $user->getAttribute('phone')); - if (!$personalDataValidator->isValid($password)) { + if (! $personalDataValidator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA); } } @@ -1022,7 +1005,7 @@ App::patch('/v1/users/:userId/password') $history = $user->getAttribute('passwordHistory', []); if ($historyLimit > 0) { $validator = new PasswordHistory($history, $user->getAttribute('hash'), $user->getAttribute('hashOptions')); - if (!$validator->isValid($password)) { + if (! $validator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED); } @@ -1065,7 +1048,6 @@ App::patch('/v1/users/:userId/email') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $email, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1079,15 +1061,13 @@ App::patch('/v1/users/:userId/email') Query::equal('providerEmail', [$email]), Query::notEqual('userId', $user->getId()), ]); - if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } $user ->setAttribute('email', $email) - ->setAttribute('emailVerification', false) - ; - + ->setAttribute('emailVerification', false); try { $user = $dbForProject->updateDocument('users', $user->getId(), $user); @@ -1120,7 +1100,6 @@ App::patch('/v1/users/:userId/phone') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $number, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1129,8 +1108,7 @@ App::patch('/v1/users/:userId/phone') $user ->setAttribute('phone', $number) - ->setAttribute('phoneVerification', false) - ; + ->setAttribute('phoneVerification', false); try { $user = $dbForProject->updateDocument('users', $user->getId(), $user); @@ -1164,7 +1142,6 @@ App::patch('/v1/users/:userId/verification') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1196,7 +1173,6 @@ App::patch('/v1/users/:userId/prefs') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, array $prefs, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1230,7 +1206,6 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->inject('dbForProject') ->inject('events') ->action(function (string $targetId, string $userId, string $identifier, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1276,7 +1251,6 @@ App::delete('/v1/users/:userId/sessions/:sessionId') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $sessionId, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1318,7 +1292,6 @@ App::delete('/v1/users/:userId/sessions') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1361,7 +1334,6 @@ App::delete('/v1/users/:userId') ->inject('events') ->inject('deletes') ->action(function (string $userId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1402,7 +1374,6 @@ App::delete('/v1/users/:userId/targets/:targetId') ->inject('dbForProject') ->inject('events') ->action(function (string $targetId, string $userId, Response $response, Database $dbForProject, Event $events) { - $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1449,7 +1420,6 @@ App::delete('/v1/users/identities/:identityId') ->inject('events') ->inject('deletes') ->action(function (string $identityId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { - $identity = $dbForProject->getDocument('identities', $identityId); if ($identity->isEmpty()) { @@ -1476,7 +1446,6 @@ App::get('/v1/users/usage') ->inject('dbForProject') ->inject('register') ->action(function (string $range, Response $response, Database $dbForProject) { - $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -1509,22 +1478,22 @@ App::get('/v1/users/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, - 'usersTotal' => $usage[$metrics[0]], + 'usersTotal' => $usage[$metrics[0]], 'sessionsTotal' => $usage[$metrics[1]], ]), Response::MODEL_USAGE_USERS); }); diff --git a/app/controllers/general.php b/app/controllers/general.php index e8d6bb225a..bbd3d45f31 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -1,38 +1,38 @@ getHostname(); $domains = Config::getParam('domains', []); - if (!array_key_exists($domain, $domains)) { - $domain = new Domain(!empty($domain) ? $domain : ''); + if (! array_key_exists($domain, $domains)) { + $domain = new Domain(! empty($domain) ? $domain : ''); - if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) { + if (empty($domain->get()) || ! $domain->isKnown() || $domain->isTest()) { $domains[$domain->get()] = false; - Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.'); + Console::warning($domain->get().' is not a publicly accessible domain. Skipping SSL certificate generation.'); } elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) { Console::warning('Skipping SSL certificates generation on ACME challenge.'); } else { @@ -97,7 +97,7 @@ App::init() $envDomain = App::getEnv('_APP_DOMAIN', ''); $mainDomain = null; - if (!empty($envDomain) && $envDomain !== 'localhost') { + if (! empty($envDomain) && $envDomain !== 'localhost') { $mainDomain = $envDomain; } else { $domainDocument = $dbForConsole->findOne('domains', [Query::orderAsc('_id')]); @@ -105,13 +105,13 @@ App::init() } if ($mainDomain !== $domain->get()) { - Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.'); + Console::warning($domain->get().' is not a main domain. Skipping SSL certificate generation.'); } else { $domainDocument = $dbForConsole->findOne('domains', [ - Query::equal('domain', [$domain->get()]) + Query::equal('domain', [$domain->get()]), ]); - if (!$domainDocument) { + if (! $domainDocument) { $domainDocument = new Document([ 'domain' => $domain->get(), 'tld' => $domain->getSuffix(), @@ -122,7 +122,7 @@ App::init() $domainDocument = $dbForConsole->createDocument('domains', $domainDocument); - Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...'); + Console::info('Issuing a TLS certificate for the main domain ('.$domain->get().') in a few seconds...'); (new Certificate()) ->setDomain($domainDocument) @@ -145,7 +145,7 @@ App::init() throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND); } - if (!empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) { + if (! empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) { throw new AppwriteException(AppwriteException::PROJECT_UNKNOWN); } @@ -160,14 +160,14 @@ App::init() $refDomainOrigin = $origin; } - $refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $refDomainOrigin . (!empty($port) ? ':' . $port : ''); + $refDomain = (! empty($protocol) ? $protocol : $request->getProtocol()).'://'.$refDomainOrigin.(! empty($port) ? ':'.$port : ''); - $refDomain = (!$route->getLabel('origin', false)) // This route is publicly accessible + $refDomain = (! $route->getLabel('origin', false)) // This route is publicly accessible ? $refDomain - : (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : ''); + : (! empty($protocol) ? $protocol : $request->getProtocol()).'://'.$origin.(! empty($port) ? ':'.$port : ''); $selfDomain = new Domain($request->getHostname()); - $endDomain = new Domain((string)$origin); + $endDomain = new Domain((string) $origin); Config::setParam( 'domainVerification', @@ -175,7 +175,7 @@ App::init() $endDomain->getRegisterable() !== '' ); - $isLocalHost = $request->getHostname() === 'localhost' || $request->getHostname() === 'localhost:' . $request->getPort(); + $isLocalHost = $request->getHostname() === 'localhost' || $request->getHostname() === 'localhost:'.$request->getPort(); $isIpAddress = filter_var($request->getHostname(), FILTER_VALIDATE_IP) !== false; $isConsoleProject = $project->getAttribute('$id', '') === 'console'; @@ -186,8 +186,8 @@ App::init() $isLocalHost || $isIpAddress ? null : ($isConsoleProject && $isConsoleRootSession - ? '.' . $selfDomain->getRegisterable() - : '.' . $request->getHostname() + ? '.'.$selfDomain->getRegisterable() + : '.'.$request->getHostname() ) ); @@ -231,12 +231,12 @@ App::init() throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP.'); } - return $response->redirect('https://' . $request->getHostname() . $request->getURI()); + return $response->redirect('https://'.$request->getHostname().$request->getURI()); } } if ($request->getProtocol() === 'https') { - $response->addHeader('Strict-Transport-Security', 'max-age=' . (60 * 60 * 24 * 126)); // 126 days + $response->addHeader('Strict-Transport-Security', 'max-age='.(60 * 60 * 24 * 126)); // 126 days } $response @@ -246,8 +246,7 @@ App::init() ->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma') ->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies') ->addHeader('Access-Control-Allow-Origin', $refDomain) - ->addHeader('Access-Control-Allow-Credentials', 'true') - ; + ->addHeader('Access-Control-Allow-Credentials', 'true'); /* * Validate Client Domain - Check to avoid CSRF attack @@ -258,7 +257,7 @@ App::init() $originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', []))); if ( - !$originValidator->isValid($origin) + ! $originValidator->isValid($origin) && \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE]) && $route->getLabel('origin', false) !== '*' && empty($request->getHeader('x-appwrite-key', '')) @@ -298,7 +297,7 @@ App::init() $authKey = $request->getHeader('x-appwrite-key', ''); - if (!empty($authKey)) { // API Key authentication + if (! empty($authKey)) { // API Key authentication // Check if given key match project API keys $key = $project->find('secret', $authKey, 'keys'); @@ -310,7 +309,7 @@ App::init() $user = new Document([ '$id' => '', 'status' => true, - 'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(), + 'email' => 'app.'.$project->getId().'@service.'.$request->getHostname(), 'password' => '', 'name' => $project->getAttribute('name', 'Untitled'), ]); @@ -319,8 +318,8 @@ App::init() $scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', [])); $expire = $key->getAttribute('expire'); - if (!empty($expire) && $expire < DateTime::formatTz(DateTime::now())) { - throw new AppwriteException(AppwriteException:: PROJECT_KEY_EXPIRED); + if (! empty($expire) && $expire < DateTime::formatTz(DateTime::now())) { + throw new AppwriteException(AppwriteException::PROJECT_KEY_EXPIRED); } Authorization::setRole(Auth::USER_ROLE_APPS); @@ -337,7 +336,7 @@ App::init() $sdk = $request->getHeader('x-sdk-name', 'UNKNOWN'); if ($sdkValidator->isValid($sdk)) { $sdks = $key->getAttribute('sdks', []); - if (!in_array($sdk, $sdks)) { + if (! in_array($sdk, $sdks)) { array_push($sdks, $sdk); $key->setAttribute('sdks', $sdks); @@ -357,22 +356,22 @@ App::init() } $service = $route->getLabel('sdk.namespace', ''); - if (!empty($service)) { + if (! empty($service)) { if ( array_key_exists($service, $project->getAttribute('services', [])) - && !$project->getAttribute('services', [])[$service] - && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) + && ! $project->getAttribute('services', [])[$service] + && ! (Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) ) { throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED); } } - if (!\in_array($scope, $scopes)) { + if (! \in_array($scope, $scopes)) { if ($project->isEmpty()) { // Check if permission is denied because project is missing throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND); } - throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')'); + throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')'); } if (false === $user->getAttribute('status')) { // Account is blocked @@ -388,7 +387,6 @@ App::options() ->inject('request') ->inject('response') ->action(function (Request $request, Response $response) { - $origin = $request->getOrigin(); $response @@ -410,7 +408,6 @@ App::error() ->inject('logger') ->inject('loggerBreadcrumbs') ->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, array $loggerBreadcrumbs) { - $version = App::getEnv('_APP_VERSION', 'UNKNOWN'); $route = $utopia->match($request); @@ -425,11 +422,11 @@ App::error() $log = new Utopia\Logger\Log(); - if (isset($user) && !$user->isEmpty()) { + if (isset($user) && ! $user->isEmpty()) { $log->setUser(new User($user->getId())); } - $log->setNamespace("http"); + $log->setNamespace('http'); $log->setServer(\gethostname()); $log->setVersion($version); $log->setType(Log::TYPE_ERROR); @@ -442,7 +439,7 @@ App::error() $log->addTag('code', $error->getCode()); $log->addTag('projectId', $project->getId()); $log->addTag('hostname', $request->getHostname()); - $log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', ''))); + $log->addTag('locale', (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', ''))); $log->addExtra('file', $error->getFile()); $log->addExtra('line', $error->getLine()); @@ -450,7 +447,7 @@ App::error() $log->addExtra('detailedTrace', $error->getTrace()); $log->addExtra('roles', Authorization::getRoles()); - $action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD"); + $action = $route->getLabel('sdk.namespace', 'UNKNOWN_NAMESPACE').'.'.$route->getLabel('sdk.method', 'UNKNOWN_METHOD'); $log->setAction($action); $isProduction = App::getEnv('_APP_ENV', 'development') === 'production'; @@ -461,7 +458,7 @@ App::error() } $responseCode = $logger->addLog($log); - Console::info('Log pushed with status code: ' . $responseCode); + Console::info('Log pushed with status code: '.$responseCode); } } @@ -472,17 +469,17 @@ App::error() $trace = $error->getTrace(); if (php_sapi_name() === 'cli') { - Console::error('[Error] Timestamp: ' . date('c', time())); + Console::error('[Error] Timestamp: '.date('c', time())); if ($route) { - Console::error('[Error] Method: ' . $route->getMethod()); - Console::error('[Error] URL: ' . $route->getPath()); + Console::error('[Error] Method: '.$route->getMethod()); + Console::error('[Error] URL: '.$route->getPath()); } - Console::error('[Error] Type: ' . get_class($error)); - Console::error('[Error] Message: ' . $message); - Console::error('[Error] File: ' . $file); - Console::error('[Error] Line: ' . $line); + Console::error('[Error] Type: '.get_class($error)); + Console::error('[Error] Message: '.$message); + Console::error('[Error] File: '.$file); + Console::error('[Error] Line: '.$line); } /** Handle Utopia Errors */ @@ -503,7 +500,7 @@ App::error() } /** Wrap all exceptions inside Appwrite\Extend\Exception */ - if (!($error instanceof AppwriteException)) { + if (! ($error instanceof AppwriteException)) { $error = new AppwriteException(AppwriteException::GENERAL_UNKNOWN, $message, $code, $error); } @@ -548,8 +545,7 @@ App::error() ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate') ->addHeader('Expires', '0') ->addHeader('Pragma', 'no-cache') - ->setStatusCode($code) - ; + ->setStatusCode($code); $template = ($route) ? $route->getLabel('error', null) : null; @@ -557,15 +553,14 @@ App::error() $layout = new View($template); $layout - ->setParam('title', $project->getAttribute('name') . ' - Error') + ->setParam('title', $project->getAttribute('name').' - Error') ->setParam('development', App::isDevelopment()) ->setParam('projectName', $project->getAttribute('name')) ->setParam('projectURL', $project->getAttribute('url')) ->setParam('message', $error->getMessage()) ->setParam('type', $type) ->setParam('code', $code) - ->setParam('trace', $trace) - ; + ->setParam('trace', $trace); $response->html($layout->render()); } @@ -582,7 +577,7 @@ App::get('/robots.txt') ->label('docs', false) ->inject('response') ->action(function (Response $response) { - $template = new View(__DIR__ . '/../views/general/robots.phtml'); + $template = new View(__DIR__.'/../views/general/robots.phtml'); $response->text($template->render(false)); }); @@ -592,7 +587,7 @@ App::get('/humans.txt') ->label('docs', false) ->inject('response') ->action(function (Response $response) { - $template = new View(__DIR__ . '/../views/general/humans.phtml'); + $template = new View(__DIR__.'/../views/general/humans.phtml'); $response->text($template->render(false)); }); @@ -611,43 +606,43 @@ App::get('/.well-known/acme-challenge/*') ...Text::ALPHABET_LOWER, ...Text::ALPHABET_UPPER, '-', - '_' + '_', ]); - if (!$validator->isValid($token) || \count($uriChunks) !== 4) { + if (! $validator->isValid($token) || \count($uriChunks) !== 4) { throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, 'Invalid challenge token.'); } $base = \realpath(APP_STORAGE_CERTIFICATES); - $absolute = \realpath($base . '/.well-known/acme-challenge/' . $token); + $absolute = \realpath($base.'/.well-known/acme-challenge/'.$token); - if (!$base) { + if (! $base) { throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Storage error'); } - if (!$absolute) { + if (! $absolute) { throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path'); } - if (!\substr($absolute, 0, \strlen($base)) === $base) { + if (! \substr($absolute, 0, \strlen($base)) === $base) { throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, 'Invalid path'); } - if (!\file_exists($absolute)) { + if (! \file_exists($absolute)) { throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path'); } $content = @\file_get_contents($absolute); - if (!$content) { + if (! $content) { throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Failed to get contents'); } $response->text($content); }); -include_once __DIR__ . '/shared/api.php'; -include_once __DIR__ . '/shared/api/auth.php'; +include_once __DIR__.'/shared/api.php'; +include_once __DIR__.'/shared/api/auth.php'; foreach (Config::getParam('services', []) as $service) { include_once $service['controller']; diff --git a/app/controllers/mock.php b/app/controllers/mock.php index 892c41d872..779c361b61 100644 --- a/app/controllers/mock.php +++ b/app/controllers/mock.php @@ -3,18 +3,18 @@ global $utopia, $request, $response; use Appwrite\Extend\Exception; -use Utopia\Database\Document; -use Utopia\Validator\Host; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Utopia\App; -use Utopia\Validator\ArrayList; -use Utopia\Validator\Integer; -use Utopia\Validator\Text; -use Utopia\Storage\Validator\File; -use Utopia\Validator\WhiteList; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; +use Utopia\Storage\Validator\File; +use Utopia\Validator\ArrayList; +use Utopia\Validator\Host; +use Utopia\Validator\Integer; use Utopia\Validator\Nullable; +use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; App::get('/v1/mock/tests/foo') ->desc('Get Foo') @@ -220,9 +220,9 @@ App::get('/v1/mock/tests/general/headers') 'x-sdk-version' => $request->getHeader('x-sdk-version'), ]; $res = array_map(function ($key, $value) { - return $key . ': ' . $value; + return $key.': '.$value; }, array_keys($res), $res); - $res = implode("; ", $res); + $res = implode('; ', $res); $response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK); }); @@ -241,14 +241,12 @@ App::get('/v1/mock/tests/general/download') ->label('sdk.mock', true) ->inject('response') ->action(function (Response $response) { - $response ->setContentType('text/plain') ->addHeader('Content-Disposition', 'attachment; filename="test.txt"') - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache ->addHeader('X-Peak', \memory_get_peak_usage()) - ->send("GET:/v1/mock/tests/general/download:passed") - ; + ->send('GET:/v1/mock/tests/general/download:passed'); }); App::post('/v1/mock/tests/general/upload') @@ -271,14 +269,13 @@ App::post('/v1/mock/tests/general/upload') ->inject('request') ->inject('response') ->action(function (string $x, int $y, array $z, mixed $file, Request $request, Response $response) { - $file = $request->getFiles('file'); $contentRange = $request->getHeader('content-range'); $chunkSize = 5 * 1024 * 1024; // 5MB - if (!empty($contentRange)) { + if (! empty($contentRange)) { $start = $request->getContentRangeStart(); $end = $request->getContentRangeEnd(); $size = $request->getContentRangeSize(); @@ -293,7 +290,7 @@ App::post('/v1/mock/tests/general/upload') throw new Exception(Exception::GENERAL_MOCK, 'Invalid content-range header'); } - if ($start === 0 && !empty($id)) { + if ($start === 0 && ! empty($id)) { throw new Exception(Exception::GENERAL_MOCK, 'First chunked request cannot have id header'); } @@ -317,7 +314,7 @@ App::post('/v1/mock/tests/general/upload') $response->json([ '$id' => ID::custom('newfileid'), 'chunksTotal' => (int) ceil($size / ($end + 1 - $start)), - 'chunksUploaded' => ceil($start / $chunkSize) + 1 + 'chunksUploaded' => ceil($start / $chunkSize) + 1, ]); } } else { @@ -330,7 +327,7 @@ App::post('/v1/mock/tests/general/upload') } if ($file['size'] !== 38756) { - throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size'); + throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size'); } if (\md5(\file_get_contents($file['tmp_name'])) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') { @@ -353,7 +350,6 @@ App::get('/v1/mock/tests/general/redirect') ->label('sdk.mock', true) ->inject('response') ->action(function (Response $response) { - $response->redirect('/v1/mock/tests/general/redirect/done'); }); @@ -387,7 +383,6 @@ App::get('/v1/mock/tests/general/set-cookie') ->inject('response') ->inject('request') ->action(function (Response $response, Request $request) { - $response->addCookie('cookieName', 'cookieValue', \time() + 31536000, '/', $request->getHostname(), true, true); }); @@ -405,7 +400,6 @@ App::get('/v1/mock/tests/general/get-cookie') ->label('sdk.mock', true) ->inject('request') ->action(function (Request $request) { - if ($request->getCookie('cookieName', '') !== 'cookieValue') { throw new Exception(Exception::GENERAL_MOCK, 'Missing cookie value'); } @@ -424,7 +418,6 @@ App::get('/v1/mock/tests/general/empty') ->label('sdk.mock', true) ->inject('response') ->action(function (Response $response) { - $response->noContent(); }); @@ -465,9 +458,9 @@ App::get('/v1/mock/tests/general/headers') 'x-sdk-version' => $request->getHeader('x-sdk-version'), ]; $res = array_map(function ($key, $value) { - return $key . ': ' . $value; + return $key.': '.$value; }, array_keys($res), $res); - $res = implode("; ", $res); + $res = implode('; ', $res); $response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK); }); @@ -518,11 +511,9 @@ App::get('/v1/mock/tests/general/502-error') ->label('sdk.mock', true) ->inject('response') ->action(function (Response $response) { - $response ->setStatusCode(502) - ->text('This is a text error') - ; + ->text('This is a text error'); }); App::get('/v1/mock/tests/general/oauth2') @@ -537,8 +528,7 @@ App::get('/v1/mock/tests/general/oauth2') ->param('state', '', new Text(1024), 'OAuth2 state.') ->inject('response') ->action(function (string $client_id, string $redirectURI, string $scope, string $state, Response $response) { - - $response->redirect($redirectURI . '?' . \http_build_query(['code' => 'abcdef', 'state' => $state])); + $response->redirect($redirectURI.'?'.\http_build_query(['code' => 'abcdef', 'state' => $state])); }); App::get('/v1/mock/tests/general/oauth2/token') @@ -555,7 +545,6 @@ App::get('/v1/mock/tests/general/oauth2/token') ->param('refresh_token', '', new Text(100), 'OAuth2 refresh token.', true) ->inject('response') ->action(function (string $client_id, string $client_secret, string $grantType, string $redirectURI, string $code, string $refreshToken, Response $response) { - if ($client_id != '1') { throw new Exception(Exception::GENERAL_MOCK, 'Invalid client ID'); } @@ -567,7 +556,7 @@ App::get('/v1/mock/tests/general/oauth2/token') $responseJson = [ 'access_token' => '123456', 'refresh_token' => 'tuvwxyz', - 'expires_in' => 14400 + 'expires_in' => 14400, ]; if ($grantType === 'authorization_code') { @@ -595,7 +584,6 @@ App::get('/v1/mock/tests/general/oauth2/user') ->param('token', '', new Text(100), 'OAuth2 Access Token.') ->inject('response') ->action(function (string $token, Response $response) { - if ($token != '123456') { throw new Exception(Exception::GENERAL_MOCK, 'Invalid token'); } @@ -614,7 +602,6 @@ App::get('/v1/mock/tests/general/oauth2/success') ->label('docs', false) ->inject('response') ->action(function (Response $response) { - $response->json([ 'result' => 'success', ]); @@ -627,7 +614,6 @@ App::get('/v1/mock/tests/general/oauth2/failure') ->label('docs', false) ->inject('response') ->action(function (Response $response) { - $response ->setStatusCode(Response::STATUS_CODE_BAD_REQUEST) ->json([ @@ -641,23 +627,22 @@ App::shutdown() ->inject('response') ->inject('request') ->action(function (App $utopia, Response $response, Request $request) { - $result = []; - $route = $utopia->match($request); - $path = APP_STORAGE_CACHE . '/tests.json'; - $tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : []; + $route = $utopia->match($request); + $path = APP_STORAGE_CACHE.'/tests.json'; + $tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : []; - if (!\is_array($tests)) { + if (! \is_array($tests)) { throw new Exception(Exception::GENERAL_MOCK, 'Failed to read results', 500); } - $result[$route->getMethod() . ':' . $route->getPath()] = true; + $result[$route->getMethod().':'.$route->getPath()] = true; $tests = \array_merge($tests, $result); - if (!\file_put_contents($path, \json_encode($tests), LOCK_EX)) { + if (! \file_put_contents($path, \json_encode($tests), LOCK_EX)) { throw new Exception(Exception::GENERAL_MOCK, 'Failed to save results', 500); } - $response->dynamic(new Document(['result' => $route->getMethod() . ':' . $route->getPath() . ':passed']), Response::MODEL_MOCK); + $response->dynamic(new Document(['result' => $route->getMethod().':'.$route->getPath().':passed']), Response::MODEL_MOCK); }); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 2bbac41811..ad7b3d135d 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -7,14 +7,14 @@ use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Event\Func; use Appwrite\Event\Mail; -use Appwrite\Extend\Exception; use Appwrite\Event\Usage; +use Appwrite\Extend\Exception; use Appwrite\Messaging\Adapter\Realtime; -use Appwrite\Utopia\Response; use Appwrite\Utopia\Request; -use Utopia\App; +use Appwrite\Utopia\Response; use Utopia\Abuse\Abuse; use Utopia\Abuse\Adapters\TimeLimit; +use Utopia\App; use Utopia\Cache\Adapter\Filesystem; use Utopia\Cache\Cache; use Utopia\Database\Database; @@ -36,7 +36,7 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar $replace = $parts[1] ?? ''; $params = match ($namespace) { - 'user' => (array)$user, + 'user' => (array) $user, 'request' => $requestParams, default => $responsePayload, }; @@ -45,11 +45,11 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar $label = \str_replace($find, $params[$replace], $label); } } + return $label; }; $databaseListener = function (string $event, Document $document, Document $project, Usage $queueForUsage, Database $dbForProject) { - $value = 1; if ($event === Database::EVENT_DOCUMENT_DELETE) { $value = -1; @@ -81,13 +81,13 @@ $databaseListener = function (string $event, Document $document, Document $proje ->addReduce($document); } break; - case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections + case str_starts_with($document->getCollection(), 'database_') && ! str_contains($document->getCollection(), 'collection'): //collections $parts = explode('_', $document->getCollection()); $databaseInternalId = $parts[1] ?? 0; $queueForUsage ->addMetric(METRIC_COLLECTIONS, $value) // per project ->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value) // per database - ; +; if ($event === Database::EVENT_DOCUMENT_DELETE) { $queueForUsage @@ -96,7 +96,7 @@ $databaseListener = function (string $event, Document $document, Document $proje break; case str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_'): //documents $parts = explode('_', $document->getCollection()); - $databaseInternalId = $parts[1] ?? 0; + $databaseInternalId = $parts[1] ?? 0; $collectionInternalId = $parts[3] ?? 0; $queueForUsage ->addMetric(METRIC_DOCUMENTS, $value) // per project @@ -132,13 +132,13 @@ $databaseListener = function (string $event, Document $document, Document $proje ->addMetric(METRIC_DEPLOYMENTS, $value) // per project ->addMetric(METRIC_DEPLOYMENTS_STORAGE, $document->getAttribute('size') * $value) // per project ->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS), $value)// per function - ->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value);// per function + ->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value); // per function break; case $document->getCollection() === 'executions': $queueForUsage ->addMetric(METRIC_EXECUTIONS, $value) // per project - ->addMetric(str_replace('{functionInternalId}', $document->getAttribute('functionInternalId'), METRIC_FUNCTION_ID_EXECUTIONS), $value);// per function + ->addMetric(str_replace('{functionInternalId}', $document->getAttribute('functionInternalId'), METRIC_FUNCTION_ID_EXECUTIONS), $value); // per function break; default: break; @@ -161,7 +161,6 @@ App::init() ->inject('mode') ->inject('mails') ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, Usage $queueForUsage, string $mode, Mail $mails) use ($databaseListener) { - $route = $utopia->match($request); if ($project->isEmpty() && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope @@ -174,7 +173,7 @@ App::init() $abuseKeyLabel = $route->getLabel('abuse-key', 'url:{url},ip:{ip}'); $timeLimitArray = []; - $abuseKeyLabel = (!is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel; + $abuseKeyLabel = (! is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel; foreach ($abuseKeyLabel as $abuseKey) { $timeLimit = new TimeLimit($abuseKey, $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForProject); @@ -182,7 +181,7 @@ App::init() ->setParam('{userId}', $user->getId()) ->setParam('{userAgent}', $request->getUserAgent('')) ->setParam('{ip}', $request->getIP()) - ->setParam('{url}', $request->getHostname() . $route->getPath()) + ->setParam('{url}', $request->getHostname().$route->getPath()) ->setParam('{method}', $request->getMethod()); $timeLimitArray[] = $timeLimit; } @@ -195,8 +194,8 @@ App::init() foreach ($timeLimitArray as $timeLimit) { foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys - if (!empty($value)) { - $timeLimit->setParam('{param-' . $key . '}', (\is_array($value)) ? \json_encode($value) : $value); + if (! empty($value)) { + $timeLimit->setParam('{param-'.$key.'}', (\is_array($value)) ? \json_encode($value) : $value); } } @@ -210,16 +209,15 @@ App::init() $response ->addHeader('X-RateLimit-Limit', $limit) ->addHeader('X-RateLimit-Remaining', $remaining) - ->addHeader('X-RateLimit-Reset', $time) - ; + ->addHeader('X-RateLimit-Reset', $time); } $enabled = App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled'; if ( $enabled // Abuse is enabled - && !$isAppUser // User is not API key - && !$isPrivilegedUser // User is not an admin + && ! $isAppUser // User is not API key + && ! $isPrivilegedUser // User is not an admin && $abuse->check() // Route is rate-limited ) { throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED); @@ -243,7 +241,7 @@ App::init() ->setUser($user); $smtp = $project->getAttribute('smtp', []); - if (!empty($smtp) && ($smtp['enabled'] ?? false)) { + if (! empty($smtp) && ($smtp['enabled'] ?? false)) { $mails ->setSmtpHost($smtp['host'] ?? '') ->setSmtpPort($smtp['port'] ?? 25) @@ -265,14 +263,14 @@ App::init() $useCache = $route->getLabel('cache', false); if ($useCache) { - $key = md5($request->getURI() . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER; + $key = md5($request->getURI().implode('*', $request->getParams())).'*'.APP_CACHE_BUSTER; $cache = new Cache( - new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId()) + new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$project->getId()) ); $timestamp = 60 * 60 * 24 * 30; $data = $cache->load($key, $timestamp); - if (!empty($data)) { + if (! empty($data)) { $data = json_decode($data, true); $parts = explode('/', $data['resourceType']); $type = $parts[0] ?? null; @@ -282,24 +280,24 @@ App::init() $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (!$fileSecurity && !$valid) { + if (! $fileSecurity && ! $valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } $parts = explode('/', $data['resource']); $fileId = $parts[1] ?? null; - if ($fileSecurity && !$valid) { - $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); + if ($fileSecurity && ! $valid) { + $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -308,11 +306,10 @@ App::init() } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT') + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp).' GMT') ->addHeader('X-Appwrite-Cache', 'hit') ->setContentType($data['contentType']) - ->send(base64_decode($data['payload'])) - ; + ->send(base64_decode($data['payload'])); $route->setIsActive(false); } else { @@ -327,7 +324,6 @@ App::init() ->inject('request') ->inject('project') ->action(function (App $utopia, Request $request, Document $project) { - $route = $utopia->match($request); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -431,10 +427,9 @@ App::shutdown() ->inject('mode') ->inject('dbForConsole') ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, Func $queueForFunctions, Usage $queueForUsage, string $mode, Database $dbForConsole) use ($parseLabel) { - $responsePayload = $response->getPayload(); - if (!empty($events->getEvent())) { + if (! empty($events->getEvent())) { if (empty($events->getPayload())) { $events->setPayload($responsePayload); } @@ -483,7 +478,7 @@ App::shutdown() roles: $target['roles'], options: [ 'permissionsChanged' => $target['permissionsChanged'], - 'userId' => $events->getParam('userId') + 'userId' => $events->getParam('userId'), ] ); } @@ -496,24 +491,24 @@ App::shutdown() * Audit labels */ $pattern = $route->getLabel('audits.resource', null); - if (!empty($pattern)) { + if (! empty($pattern)) { $resource = $parseLabel($pattern, $responsePayload, $requestParams, $user); - if (!empty($resource) && $resource !== $pattern) { + if (! empty($resource) && $resource !== $pattern) { $audits->setResource($resource); } } - if (!$user->isEmpty()) { + if (! $user->isEmpty()) { $audits->setUser($user); } - if (!empty($audits->getResource()) && !empty($audits->getUser()->getId())) { + if (! empty($audits->getResource()) && ! empty($audits->getUser()->getId())) { /** * audits.payload is switched to default true * in order to auto audit payload for all endpoints */ $pattern = $route->getLabel('audits.payload', true); - if (!empty($pattern)) { + if (! empty($pattern)) { $audits->setPayload($responsePayload); } @@ -523,11 +518,11 @@ App::shutdown() $audits->trigger(); } - if (!empty($deletes->getType())) { + if (! empty($deletes->getType())) { $deletes->trigger(); } - if (!empty($database->getType())) { + if (! empty($database->getType())) { $database->trigger(); } @@ -539,35 +534,35 @@ App::shutdown() $resource = $resourceType = null; $data = $response->getPayload(); - if (!empty($data['payload'])) { + if (! empty($data['payload'])) { $pattern = $route->getLabel('cache.resource', null); - if (!empty($pattern)) { + if (! empty($pattern)) { $resource = $parseLabel($pattern, $responsePayload, $requestParams, $user); } $pattern = $route->getLabel('cache.resourceType', null); - if (!empty($pattern)) { + if (! empty($pattern)) { $resourceType = $parseLabel($pattern, $responsePayload, $requestParams, $user); } - $key = md5($request->getURI() . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER; + $key = md5($request->getURI().implode('*', $request->getParams())).'*'.APP_CACHE_BUSTER; $data = json_encode([ 'resourceType' => $resourceType, 'resource' => $resource, 'contentType' => $response->getContentType(), 'payload' => base64_encode($data['payload']), - ]) ; + ]); $signature = md5($data); - $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); + $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); $accessedAt = $cacheLog->getAttribute('accessedAt', ''); $now = DateTime::now(); if ($cacheLog->isEmpty()) { Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([ - '$id' => $key, - 'resource' => $resource, - 'accessedAt' => $now, - 'signature' => $signature, + '$id' => $key, + 'resource' => $resource, + 'accessedAt' => $now, + 'signature' => $signature, ]))); } elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) { $cacheLog->setAttribute('accessedAt', $now); @@ -576,20 +571,18 @@ App::shutdown() if ($signature !== $cacheLog->getAttribute('signature')) { $cache = new Cache( - new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId()) + new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$project->getId()) ); $cache->save($key, $data); } } } - - if ($project->getId() !== 'console') { if ($mode !== APP_MODE_ADMIN) { $fileSize = 0; $file = $request->getFiles('file'); - if (!empty($file)) { + if (! empty($file)) { $fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size']; } @@ -607,7 +600,7 @@ App::shutdown() /** * Update user last activity */ - if (!$user->isEmpty()) { + if (! $user->isEmpty()) { $accessedAt = $user->getAttribute('accessedAt', ''); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_USER_ACCCESS)) > $accessedAt) { $user->setAttribute('accessedAt', DateTime::now()); diff --git a/app/controllers/shared/api/auth.php b/app/controllers/shared/api/auth.php index 5b1af0d36c..acb8410804 100644 --- a/app/controllers/shared/api/auth.php +++ b/app/controllers/shared/api/auth.php @@ -1,9 +1,9 @@ inject('request') ->inject('project') ->action(function (App $utopia, Request $request, Document $project) { - $route = $utopia->match($request); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index dcf9c80a51..37914dda37 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -11,9 +11,9 @@ App::init() ->action(function (Request $request, Response $response) { $response ->addHeader('X-Frame-Options', 'SAMEORIGIN') // Avoid console and homepage from showing in iframes - ->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url=' . \urlencode($request->getURI())) + ->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url='.\urlencode($request->getURI())) ->addHeader('X-UA-Compatible', 'IE=Edge') // Deny IE browsers from going into quirks mode - ; +; }); App::get('/console/*') @@ -30,41 +30,41 @@ App::get('/console/*') ->inject('request') ->inject('response') ->action(function (Request $request, Response $response) { - $fallback = file_get_contents(__DIR__ . '/../../../console/index.html'); + $fallback = file_get_contents(__DIR__.'/../../../console/index.html'); // Card SSR if (\str_starts_with($request->getURI(), '/card')) { $urlCunks = \explode('/', $request->getURI()); $userId = $urlCunks[\count($urlCunks) - 1] ?? ''; - $domain = $request->getProtocol() . '://' . $request->getHostname(); + $domain = $request->getProtocol().'://'.$request->getHostname(); - if (!empty($userId)) { - $ogImageUrl = $domain . '/v1/cards/cloud-og?userId=' . $userId; + if (! empty($userId)) { + $ogImageUrl = $domain.'/v1/cards/cloud-og?userId='.$userId; } else { - $ogImageUrl = $domain . '/v1/cards/cloud-og?mock=normal'; + $ogImageUrl = $domain.'/v1/cards/cloud-og?mock=normal'; } $ogTags = [ 'Appwrite Cloud Card', '', - '', + '', '', '', '', '', '', '', - '', + '', '', - '', - '', + '', + '', '', '', '', '', '', - '', + '', ]; $fallback = \str_replace('', \implode('', $ogTags), $fallback); diff --git a/app/controllers/web/home.php b/app/controllers/web/home.php index e90f3ec25b..fb33350792 100644 --- a/app/controllers/web/home.php +++ b/app/controllers/web/home.php @@ -24,14 +24,14 @@ App::get('/versions') continue; } - if (isset($language['enabled']) && !$language['enabled']) { + if (isset($language['enabled']) && ! $language['enabled']) { continue; } $platformKey = $platform['key'] ?? ''; $languageKey = $language['key'] ?? ''; $version = $language['version'] ?? ''; - $versions[$platformKey . '-' . $languageKey] = $version; + $versions[$platformKey.'-'.$languageKey] = $version; } } diff --git a/app/http.php b/app/http.php index 8ce7b6f017..88ee35ff1f 100644 --- a/app/http.php +++ b/app/http.php @@ -1,30 +1,30 @@ on('WorkerStart', function ($server, $workerId) { - Console::success('Worker ' . ++$workerId . ' started successfully'); + Console::success('Worker '.++$workerId.' started successfully'); }); $http->on('BeforeReload', function ($server, $workerId) { @@ -53,16 +53,16 @@ $http->on('AfterReload', function ($server, $workerId) { Console::success('Reload completed...'); }); -Files::load(__DIR__ . '/../console'); +Files::load(__DIR__.'/../console'); -include __DIR__ . '/controllers/general.php'; +include __DIR__.'/controllers/general.php'; $http->on('start', function (Server $http) use ($payloadSize, $register) { $app = new App('UTC'); go(function () use ($register, $app) { $pools = $register->get('pools'); /** @var Group $pools */ - App::setResource('pools', fn() => $pools); + App::setResource('pools', fn () => $pools); // wait for database to be ready $attempts = 0; @@ -77,7 +77,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { } catch (\Exception $e) { Console::warning("Database not ready. Retrying connection ({$attempts})..."); if ($attempts >= $max) { - throw new \Exception('Failed to connect to database: ' . $e->getMessage()); + throw new \Exception('Failed to connect to database: '.$e->getMessage()); } sleep($sleep); } @@ -98,7 +98,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { } if ($dbForConsole->getCollection(TimeLimit::COLLECTION)->isEmpty()) { - $adapter = new TimeLimit("", 0, 1, $dbForConsole); + $adapter = new TimeLimit('', 0, 1, $dbForConsole); $adapter->setup(); } @@ -109,11 +109,11 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { if (($collection['$collection'] ?? '') !== Database::METADATA) { continue; } - if (!$dbForConsole->getCollection($key)->isEmpty()) { + if (! $dbForConsole->getCollection($key)->isEmpty()) { continue; } - Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...'); + Console::success('[Setup] - Creating collection: '.$collection['$id'].'...'); $attributes = []; $indexes = []; @@ -128,7 +128,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '' + 'format' => $attribute['format'] ?? '', ]); } @@ -145,7 +145,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { $dbForConsole->createCollection($key, $attributes, $indexes); } - if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && !$dbForConsole->exists($dbForConsole->getDefaultDatabase(), 'bucket_1')) { + if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && ! $dbForConsole->exists($dbForConsole->getDefaultDatabase(), 'bucket_1')) { Console::success('[Setup] - Creating default bucket...'); $dbForConsole->createDocument('buckets', new Document([ '$id' => ID::custom('default'), @@ -188,7 +188,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '' + 'format' => $attribute['format'] ?? '', ]); } @@ -202,7 +202,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { ]); } - $dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes); + $dbForConsole->createCollection('bucket_'.$bucket->getInternalId(), $attributes, $indexes); } $pools->reclaim(); @@ -210,7 +210,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { Console::success('[Setup] - Server database init completed...'); }); - Console::success('Server started successfully (max payload is ' . number_format($payloadSize) . ' bytes)'); + Console::success('Server started successfully (max payload is '.number_format($payloadSize).' bytes)'); Console::info("Master pid {$http->master_pid}, manager pid {$http->manager_pid}"); // listen ctrl + c @@ -229,8 +229,8 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $response ->setContentType(Files::getFileMimeType($request->getURI())) - ->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', 'public, max-age='.$time) + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time).' GMT') // 45 days cache ->send(Files::getFileContents($request->getURI())); return; @@ -239,7 +239,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $app = new App('UTC'); $pools = $register->get('pools'); - App::setResource('pools', fn() => $pools); + App::setResource('pools', fn () => $pools); try { Authorization::cleanRoles(); @@ -249,7 +249,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo } catch (\Throwable $th) { $version = App::getEnv('_APP_VERSION', 'UNKNOWN'); - $logger = $app->getResource("logger"); + $logger = $app->getResource('logger'); if ($logger) { try { /** @var Utopia\Database\Document $user */ @@ -258,16 +258,16 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo // All good, user is optional information for logger } - $loggerBreadcrumbs = $app->getResource("loggerBreadcrumbs"); + $loggerBreadcrumbs = $app->getResource('loggerBreadcrumbs'); $route = $app->match($request); $log = new Utopia\Logger\Log(); - if (isset($user) && !$user->isEmpty()) { + if (isset($user) && ! $user->isEmpty()) { $log->setUser(new User($user->getId())); } - $log->setNamespace("http"); + $log->setNamespace('http'); $log->setServer(\gethostname()); $log->setVersion($version); $log->setType(Log::TYPE_ERROR); @@ -279,7 +279,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $log->addTag('code', $th->getCode()); // $log->addTag('projectId', $project->getId()); // TODO: Figure out how to get ProjectID, if it becomes relevant $log->addTag('hostname', $request->getHostname()); - $log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', ''))); + $log->addTag('locale', (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', ''))); $log->addExtra('file', $th->getFile()); $log->addExtra('line', $th->getLine()); @@ -287,7 +287,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $log->addExtra('detailedTrace', $th->getTrace()); $log->addExtra('roles', Authorization::getRoles()); - $action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD"); + $action = $route->getLabel('sdk.namespace', 'UNKNOWN_NAMESPACE').'.'.$route->getLabel('sdk.method', 'UNKNOWN_METHOD'); $log->setAction($action); $isProduction = App::getEnv('_APP_ENV', 'development') === 'production'; @@ -298,18 +298,18 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo } $responseCode = $logger->addLog($log); - Console::info('Log pushed with status code: ' . $responseCode); + Console::info('Log pushed with status code: '.$responseCode); } - Console::error('[Error] Type: ' . get_class($th)); - Console::error('[Error] Message: ' . $th->getMessage()); - Console::error('[Error] File: ' . $th->getFile()); - Console::error('[Error] Line: ' . $th->getLine()); + Console::error('[Error] Type: '.get_class($th)); + Console::error('[Error] Message: '.$th->getMessage()); + Console::error('[Error] File: '.$th->getFile()); + Console::error('[Error] Line: '.$th->getLine()); $swooleResponse->setStatusCode(500); $output = ((App::isDevelopment())) ? [ - 'message' => 'Error: ' . $th->getMessage(), + 'message' => 'Error: '.$th->getMessage(), 'code' => 500, 'file' => $th->getFile(), 'line' => $th->getLine(), diff --git a/app/init.php b/app/init.php index ea3a039ec9..2eb066e737 100644 --- a/app/init.php +++ b/app/init.php @@ -5,11 +5,9 @@ * * Initializes both Appwrite API entry point, queue workers, and CLI tasks. * Set configuration, framework resources & app constants - * */ - -if (\file_exists(__DIR__ . '/../vendor/autoload.php')) { - require_once __DIR__ . '/../vendor/autoload.php'; +if (\file_exists(__DIR__.'/../vendor/autoload.php')) { + require_once __DIR__.'/../vendor/autoload.php'; } ini_set('memory_limit', '512M'); @@ -18,41 +16,54 @@ ini_set('display_startup_errors', 1); ini_set('default_socket_timeout', -1); error_reporting(E_ALL); -use Appwrite\Event\Usage; -use Appwrite\Extend\Exception; +use Ahc\Jwt\JWT; +use Ahc\Jwt\JWTException; use Appwrite\Auth\Auth; use Appwrite\Event\Audit; use Appwrite\Event\Database as EventDatabase; +use Appwrite\Event\Delete; use Appwrite\Event\Event; +use Appwrite\Event\Func; use Appwrite\Event\Mail; use Appwrite\Event\Phone; -use Appwrite\Event\Delete; +use Appwrite\Event\Usage; +use Appwrite\Extend\Exception; +use Appwrite\GraphQL\Promises\Adapter\Swoole; use Appwrite\GraphQL\Schema; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\Origin; use Appwrite\OpenSSL\OpenSSL; use Appwrite\URL\URL as AppwriteURL; +use MaxMind\Db\Reader; +use PHPMailer\PHPMailer\PHPMailer; +use Swoole\Database\PDOProxy; use Utopia\App; -use Utopia\Logger\Logger; use Utopia\Cache\Adapter\Redis as RedisCache; +use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; use Utopia\Config\Config; -use Utopia\Database\Helpers\ID; +use Utopia\Database\Adapter\MariaDB; +use Utopia\Database\Adapter\MySQL; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Helpers\ID; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Structure; -use Utopia\Locale\Locale; use Utopia\DSN\DSN; +use Utopia\Locale\Locale; +use Utopia\Logger\Logger; use Utopia\Messaging\Adapters\SMS\Mock; -use Appwrite\GraphQL\Promises\Adapter\Swoole; use Utopia\Messaging\Adapters\SMS\Msg91; use Utopia\Messaging\Adapters\SMS\Telesign; use Utopia\Messaging\Adapters\SMS\TextMagic; use Utopia\Messaging\Adapters\SMS\Twilio; use Utopia\Messaging\Adapters\SMS\Vonage; +use Utopia\Pools\Group; +use Utopia\Pools\Pool; +use Utopia\Queue; +use Utopia\Queue\Connection; use Utopia\Registry\Registry; use Utopia\Storage\Device; use Utopia\Storage\Device\Backblaze; @@ -61,22 +72,9 @@ use Utopia\Storage\Device\Linode; use Utopia\Storage\Device\Local; use Utopia\Storage\Device\S3; use Utopia\Storage\Device\Wasabi; -use Utopia\Cache\Adapter\Sharding; -use Utopia\Database\Adapter\MariaDB; -use Utopia\Database\Adapter\MySQL; -use Utopia\Pools\Group; -use Utopia\Pools\Pool; -use Ahc\Jwt\JWT; -use Ahc\Jwt\JWTException; -use Appwrite\Event\Func; -use MaxMind\Db\Reader; -use PHPMailer\PHPMailer\PHPMailer; -use Swoole\Database\PDOProxy; -use Utopia\Queue; -use Utopia\Queue\Connection; use Utopia\Storage\Storage; -use Utopia\Validator\Range; use Utopia\Validator\IP; +use Utopia\Validator\Range; use Utopia\Validator\URL; use Utopia\Validator\WhiteList; @@ -84,7 +82,7 @@ const APP_NAME = 'Appwrite'; const APP_DOMAIN = 'appwrite.io'; const APP_EMAIL_TEAM = 'team@localhost.test'; // Default email address const APP_EMAIL_SECURITY = ''; // Default security email address -const APP_USERAGENT = APP_NAME . '-Server v%s. Please report abuse at %s'; +const APP_USERAGENT = APP_NAME.'-Server v%s. Please report abuse at %s'; const APP_MODE_DEFAULT = 'default'; const APP_MODE_ADMIN = 'admin'; const APP_PAGING_LIMIT = 12; @@ -162,7 +160,7 @@ const DELETE_TYPE_REALTIME = 'realtime'; const DELETE_TYPE_BUCKETS = 'buckets'; const DELETE_TYPE_SESSIONS = 'sessions'; const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp'; -const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; +const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; const DELETE_TYPE_SCHEDULES = 'schedules'; // Compression type const COMPRESSION_TYPE_NONE = 'none'; @@ -184,7 +182,7 @@ const MAX_OUTPUT_CHUNK_SIZE = 2 * 1024 * 1024; // 2MB // Usage metrics const METRIC_TEAMS = 'teams'; const METRIC_USERS = 'users'; -const METRIC_SESSIONS = 'sessions'; +const METRIC_SESSIONS = 'sessions'; const METRIC_DATABASES = 'databases'; const METRIC_COLLECTIONS = 'collections'; const METRIC_DATABASE_ID_COLLECTIONS = '{databaseInternalId}.collections'; @@ -192,28 +190,28 @@ const METRIC_DOCUMENTS = 'documents'; const METRIC_DATABASE_ID_DOCUMENTS = '{databaseInternalId}.documents'; const METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS = '{databaseInternalId}.{collectionInternalId}.documents'; const METRIC_BUCKETS = 'buckets'; -const METRIC_FILES = 'files'; -const METRIC_FILES_STORAGE = 'files.storage'; +const METRIC_FILES = 'files'; +const METRIC_FILES_STORAGE = 'files.storage'; const METRIC_BUCKET_ID_FILES = '{bucketInternalId}.files'; -const METRIC_BUCKET_ID_FILES_STORAGE = '{bucketInternalId}.files.storage'; -const METRIC_FUNCTIONS = 'functions'; -const METRIC_DEPLOYMENTS = 'deployments'; -const METRIC_DEPLOYMENTS_STORAGE = 'deployments.storage'; -const METRIC_BUILDS = 'builds'; -const METRIC_BUILDS_STORAGE = 'builds.storage'; -const METRIC_BUILDS_COMPUTE = 'builds.compute'; -const METRIC_FUNCTION_ID_BUILDS = '{functionInternalId}.builds'; +const METRIC_BUCKET_ID_FILES_STORAGE = '{bucketInternalId}.files.storage'; +const METRIC_FUNCTIONS = 'functions'; +const METRIC_DEPLOYMENTS = 'deployments'; +const METRIC_DEPLOYMENTS_STORAGE = 'deployments.storage'; +const METRIC_BUILDS = 'builds'; +const METRIC_BUILDS_STORAGE = 'builds.storage'; +const METRIC_BUILDS_COMPUTE = 'builds.compute'; +const METRIC_FUNCTION_ID_BUILDS = '{functionInternalId}.builds'; const METRIC_FUNCTION_ID_BUILDS_STORAGE = '{functionInternalId}.builds.storage'; -const METRIC_FUNCTION_ID_BUILDS_COMPUTE = '{functionInternalId}.builds.compute'; -const METRIC_FUNCTION_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments'; -const METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage'; -const METRIC_EXECUTIONS = 'executions'; -const METRIC_EXECUTIONS_COMPUTE = 'executions.compute'; -const METRIC_FUNCTION_ID_EXECUTIONS = '{functionInternalId}.executions'; -const METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE = '{functionInternalId}.executions.compute'; -const METRIC_NETWORK_REQUESTS = 'network.requests'; -const METRIC_NETWORK_INBOUND = 'network.inbound'; -const METRIC_NETWORK_OUTBOUND = 'network.outbound'; +const METRIC_FUNCTION_ID_BUILDS_COMPUTE = '{functionInternalId}.builds.compute'; +const METRIC_FUNCTION_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments'; +const METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage'; +const METRIC_EXECUTIONS = 'executions'; +const METRIC_EXECUTIONS_COMPUTE = 'executions.compute'; +const METRIC_FUNCTION_ID_EXECUTIONS = '{functionInternalId}.executions'; +const METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE = '{functionInternalId}.executions.compute'; +const METRIC_NETWORK_REQUESTS = 'network.requests'; +const METRIC_NETWORK_INBOUND = 'network.inbound'; +const METRIC_NETWORK_OUTBOUND = 'network.outbound'; $register = new Registry(); @@ -222,42 +220,42 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION)); /* * ENV vars */ -Config::load('events', __DIR__ . '/config/events.php'); -Config::load('auth', __DIR__ . '/config/auth.php'); -Config::load('errors', __DIR__ . '/config/errors.php'); -Config::load('authProviders', __DIR__ . '/config/authProviders.php'); -Config::load('platforms', __DIR__ . '/config/platforms.php'); -Config::load('collections', __DIR__ . '/config/collections.php'); -Config::load('runtimes', __DIR__ . '/config/runtimes.php'); -Config::load('usage', __DIR__ . '/config/usage.php'); -Config::load('roles', __DIR__ . '/config/roles.php'); // User roles and scopes -Config::load('scopes', __DIR__ . '/config/scopes.php'); // User roles and scopes -Config::load('services', __DIR__ . '/config/services.php'); // List of services -Config::load('variables', __DIR__ . '/config/variables.php'); // List of env variables -Config::load('regions', __DIR__ . '/config/regions.php'); // List of available regions -Config::load('avatar-browsers', __DIR__ . '/config/avatars/browsers.php'); -Config::load('avatar-credit-cards', __DIR__ . '/config/avatars/credit-cards.php'); -Config::load('avatar-flags', __DIR__ . '/config/avatars/flags.php'); -Config::load('locale-codes', __DIR__ . '/config/locale/codes.php'); -Config::load('locale-currencies', __DIR__ . '/config/locale/currencies.php'); -Config::load('locale-eu', __DIR__ . '/config/locale/eu.php'); -Config::load('locale-languages', __DIR__ . '/config/locale/languages.php'); -Config::load('locale-phones', __DIR__ . '/config/locale/phones.php'); -Config::load('locale-countries', __DIR__ . '/config/locale/countries.php'); -Config::load('locale-continents', __DIR__ . '/config/locale/continents.php'); -Config::load('locale-templates', __DIR__ . '/config/locale/templates.php'); -Config::load('storage-logos', __DIR__ . '/config/storage/logos.php'); -Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php'); -Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php'); -Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php'); -Config::load('messagingProviders', __DIR__ . '/config/messagingProviders.php'); +Config::load('events', __DIR__.'/config/events.php'); +Config::load('auth', __DIR__.'/config/auth.php'); +Config::load('errors', __DIR__.'/config/errors.php'); +Config::load('authProviders', __DIR__.'/config/authProviders.php'); +Config::load('platforms', __DIR__.'/config/platforms.php'); +Config::load('collections', __DIR__.'/config/collections.php'); +Config::load('runtimes', __DIR__.'/config/runtimes.php'); +Config::load('usage', __DIR__.'/config/usage.php'); +Config::load('roles', __DIR__.'/config/roles.php'); // User roles and scopes +Config::load('scopes', __DIR__.'/config/scopes.php'); // User roles and scopes +Config::load('services', __DIR__.'/config/services.php'); // List of services +Config::load('variables', __DIR__.'/config/variables.php'); // List of env variables +Config::load('regions', __DIR__.'/config/regions.php'); // List of available regions +Config::load('avatar-browsers', __DIR__.'/config/avatars/browsers.php'); +Config::load('avatar-credit-cards', __DIR__.'/config/avatars/credit-cards.php'); +Config::load('avatar-flags', __DIR__.'/config/avatars/flags.php'); +Config::load('locale-codes', __DIR__.'/config/locale/codes.php'); +Config::load('locale-currencies', __DIR__.'/config/locale/currencies.php'); +Config::load('locale-eu', __DIR__.'/config/locale/eu.php'); +Config::load('locale-languages', __DIR__.'/config/locale/languages.php'); +Config::load('locale-phones', __DIR__.'/config/locale/phones.php'); +Config::load('locale-countries', __DIR__.'/config/locale/countries.php'); +Config::load('locale-continents', __DIR__.'/config/locale/continents.php'); +Config::load('locale-templates', __DIR__.'/config/locale/templates.php'); +Config::load('storage-logos', __DIR__.'/config/storage/logos.php'); +Config::load('storage-mimes', __DIR__.'/config/storage/mimes.php'); +Config::load('storage-inputs', __DIR__.'/config/storage/inputs.php'); +Config::load('storage-outputs', __DIR__.'/config/storage/outputs.php'); +Config::load('messagingProviders', __DIR__.'/config/messagingProviders.php'); $user = App::getEnv('_APP_REDIS_USER', ''); $pass = App::getEnv('_APP_REDIS_PASS', ''); -if (!empty($user) || !empty($pass)) { - Resque::setBackend('redis://' . $user . ':' . $pass . '@' . App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', '')); +if (! empty($user) || ! empty($pass)) { + Resque::setBackend('redis://'.$user.':'.$pass.'@'.App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', '')); } else { - Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', '')); + Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', '')); } /** @@ -313,8 +311,7 @@ Database::addFilter( if (isset($formatOptions['min']) || isset($formatOptions['max'])) { $attribute ->setAttribute('min', $formatOptions['min']) - ->setAttribute('max', $formatOptions['max']) - ; + ->setAttribute('max', $formatOptions['max']); } return $value; @@ -437,7 +434,7 @@ Database::addFilter( return null; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn() => $database + return Authorization::skip(fn () => $database ->find('tokens', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -451,7 +448,7 @@ Database::addFilter( return null; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn() => $database + return Authorization::skip(fn () => $database ->find('memberships', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -493,7 +490,7 @@ Database::addFilter( return null; } $value = json_decode($value, true); - $key = App::getEnv('_APP_OPENSSL_KEY_V' . $value['version']); + $key = App::getEnv('_APP_OPENSSL_KEY_V'.$value['version']); return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag'])); } @@ -506,11 +503,11 @@ Database::addFilter( $user->getId(), $user->getAttribute('email', ''), $user->getAttribute('name', ''), - $user->getAttribute('phone', '') + $user->getAttribute('phone', ''), ]; foreach ($user->getAttribute('labels', []) as $label) { - $searchValues[] = 'label:' . $label; + $searchValues[] = 'label:'.$label; } $search = implode(' ', \array_filter($searchValues)); @@ -528,7 +525,7 @@ Database::addFilter( return null; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn() => $database + return Authorization::skip(fn () => $database ->find('targets', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -542,7 +539,7 @@ Database::addFilter( return null; }, function (mixed $value, Document $document, Database $database) { - $provider = Authorization::skip(fn() => $database + $provider = Authorization::skip(fn () => $database ->findOne('providers', [ Query::equal('$id', [$document->getAttribute('providerId')]), Query::select(['type']), @@ -551,6 +548,7 @@ Database::addFilter( if ($provider) { return $provider->getAttribute('type'); } + return null; } ); @@ -568,6 +566,7 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_DATETIME, function () { Structure::addFormat(APP_DATABASE_ATTRIBUTE_ENUM, function ($attribute) { $elements = $attribute['formatOptions']['elements']; + return new WhiteList($elements, true); }, Database::VAR_STRING); @@ -582,12 +581,14 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_URL, function () { Structure::addFormat(APP_DATABASE_ATTRIBUTE_INT_RANGE, function ($attribute) { $min = $attribute['formatOptions']['min'] ?? -INF; $max = $attribute['formatOptions']['max'] ?? INF; + return new Range($min, $max, Range::TYPE_INTEGER); }, Database::VAR_INTEGER); Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function ($attribute) { $min = $attribute['formatOptions']['min'] ?? -INF; $max = $attribute['formatOptions']['max'] ?? INF; + return new Range($min, $max, Range::TYPE_FLOAT); }, Database::VAR_FLOAT); @@ -603,12 +604,13 @@ $register->set('logger', function () { return null; } - if (!Logger::hasProvider($providerName)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled"); + if (! Logger::hasProvider($providerName)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Logging provider not supported. Logging is disabled'); } - $classname = '\\Utopia\\Logger\\Adapter\\' . \ucfirst($providerName); + $classname = '\\Utopia\\Logger\\Adapter\\'.\ucfirst($providerName); $adapter = new $classname($providerConfig); + return new Logger($adapter); }); $register->set('pools', function () { @@ -677,7 +679,7 @@ $register->set('pools', function () { throw new \Exception('Pool size is too small. Increase the number of allowed database connections or decrease the number of workers.', 500); } - $poolSize = (int)($instanceConnections / $workerCount); + $poolSize = (int) ($instanceConnections / $workerCount); foreach ($connections as $key => $connection) { $type = $connection['type'] ?? ''; @@ -688,7 +690,7 @@ $register->set('pools', function () { $dsns = explode(',', $connection['dsns'] ?? ''); foreach ($dsns as &$dsn) { $dsn = explode('=', $dsn); - $name = ($multipe) ? $key . '_' . $dsn[0] : $key; + $name = ($multipe) ? $key.'_'.$dsn[0] : $key; $dsn = $dsn[1] ?? ''; $config[] = $name; if (empty($dsn)) { @@ -704,8 +706,8 @@ $register->set('pools', function () { $dsnScheme = $dsn->getScheme(); $dsnDatabase = $dsn->getPath(); - if (!in_array($dsnScheme, $schemes)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme"); + if (! in_array($dsnScheme, $schemes)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Invalid console database scheme'); } /** @@ -720,21 +722,21 @@ $register->set('pools', function () { case 'mariadb': $resource = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { - return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array( + return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, [ PDO::ATTR_TIMEOUT => 3, // Seconds PDO::ATTR_PERSISTENT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed PDO::ATTR_EMULATE_PREPARES => true, - PDO::ATTR_STRINGIFY_FETCHES => true - )); + PDO::ATTR_STRINGIFY_FETCHES => true, + ]); }); }; break; case 'redis': $resource = function () use ($dsnHost, $dsnPort, $dsnPass) { $redis = new Redis(); - @$redis->pconnect($dsnHost, (int)$dsnPort); + @$redis->pconnect($dsnHost, (int) $dsnPort); if ($dsnPass) { $redis->auth($dsnPass); } @@ -745,7 +747,7 @@ $register->set('pools', function () { break; default: - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid scheme"); + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Invalid scheme'); break; } @@ -779,7 +781,7 @@ $register->set('pools', function () { break; default: - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Server error: Missing adapter implementation.'); break; } @@ -789,7 +791,7 @@ $register->set('pools', function () { $group->add($pool); } - Config::setParam('pools-' . $key, $config); + Config::setParam('pools-'.$key, $config); } return $group; @@ -806,14 +808,14 @@ $register->set('smtp', function () { $mail->XMailer = 'Appwrite Mailer'; $mail->Host = App::getEnv('_APP_SMTP_HOST', 'smtp'); $mail->Port = App::getEnv('_APP_SMTP_PORT', 25); - $mail->SMTPAuth = (!empty($username) && !empty($password)); + $mail->SMTPAuth = (! empty($username) && ! empty($password)); $mail->Username = $username; $mail->Password = $password; $mail->SMTPSecure = App::getEnv('_APP_SMTP_SECURE', false); $mail->SMTPAutoTLS = false; $mail->CharSet = 'UTF-8'; - $from = \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')); + $from = \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')); $email = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); $mail->setFrom($email, $from); @@ -824,12 +826,13 @@ $register->set('smtp', function () { return $mail; }); $register->set('geodb', function () { - return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2023-01.mmdb'); + return new Reader(__DIR__.'/assets/dbip/dbip-country-lite-2023-01.mmdb'); }); $register->set('passwordsDictionary', function () { - $content = \file_get_contents(__DIR__ . '/assets/security/10k-common-passwords'); + $content = \file_get_contents(__DIR__.'/assets/security/10k-common-passwords'); $content = explode("\n", $content); $content = array_flip($content); + return $content; }); $register->set('promiseAdapter', function () { @@ -845,12 +848,12 @@ $locales = Config::getParam('locale-codes', []); foreach ($locales as $locale) { $code = $locale['code']; - $path = __DIR__ . '/config/locale/translations/' . $code . '.json'; + $path = __DIR__.'/config/locale/translations/'.$code.'.json'; - if (!\file_exists($path)) { - $path = __DIR__ . '/config/locale/translations/' . \substr($code, 0, 2) . '.json'; // if `ar-ae` doesn't exist, look for `ar` - if (!\file_exists($path)) { - $path = __DIR__ . '/config/locale/translations/en.json'; // if none translation exists, use default from `en.json` + if (! \file_exists($path)) { + $path = __DIR__.'/config/locale/translations/'.\substr($code, 0, 2).'.json'; // if `ar-ae` doesn't exist, look for `ar` + if (! \file_exists($path)) { + $path = __DIR__.'/config/locale/translations/en.json'; // if none translation exists, use default from `en.json` } } @@ -878,20 +881,20 @@ App::setResource('loggerBreadcrumbs', function () { return []; }); -App::setResource('register', fn() => $register); -App::setResource('locale', fn() => new Locale(App::getEnv('_APP_LOCALE', 'en'))); +App::setResource('register', fn () => $register); +App::setResource('locale', fn () => new Locale(App::getEnv('_APP_LOCALE', 'en'))); App::setResource('localeCodes', function () { - return array_map(fn($locale) => $locale['code'], Config::getParam('locale-codes', [])); + return array_map(fn ($locale) => $locale['code'], Config::getParam('locale-codes', [])); }); // Queues -App::setResource('events', fn() => new Event('', '')); -App::setResource('audits', fn() => new Audit()); -App::setResource('mails', fn() => new Mail()); -App::setResource('deletes', fn() => new Delete()); -App::setResource('database', fn() => new EventDatabase()); -App::setResource('messaging', fn() => new Phone()); +App::setResource('events', fn () => new Event('', '')); +App::setResource('audits', fn () => new Audit()); +App::setResource('mails', fn () => new Mail()); +App::setResource('deletes', fn () => new Delete()); +App::setResource('database', fn () => new EventDatabase()); +App::setResource('messaging', fn () => new Phone()); App::setResource('queue', function (Group $pools) { return $pools->get('queue')->pop()->getResource(); }, ['pools']); @@ -917,7 +920,7 @@ App::setResource('clients', function ($request, $console, $project) { fn ($node) => $node['hostname'], \array_filter( $console->getAttribute('platforms', []), - fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && isset($node['hostname']) && !empty($node['hostname'])) + fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && isset($node['hostname']) && ! empty($node['hostname'])) ) ); @@ -928,7 +931,7 @@ App::setResource('clients', function ($request, $console, $project) { fn ($node) => $node['hostname'], \array_filter( $project->getAttribute('platforms', []), - fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB || $node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) && isset($node['hostname']) && !empty($node['hostname'])) + fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB || $node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) && isset($node['hostname']) && ! empty($node['hostname'])) ) ) ) @@ -944,23 +947,22 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons /** @var Utopia\Database\Database $dbForProject */ /** @var Utopia\Database\Database $dbForConsole */ /** @var string $mode */ - Authorization::setDefaultStatus(true); - Auth::setCookieName('a_session_' . $project->getId()); + Auth::setCookieName('a_session_'.$project->getId()); $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; if (APP_MODE_ADMIN === $mode) { - Auth::setCookieName('a_session_' . $console->getId()); + Auth::setCookieName('a_session_'.$console->getId()); $authDuration = Auth::TOKEN_EXPIRATION_LOGIN_LONG; } $session = Auth::decodeSession( $request->getCookie( Auth::$cookieName, // Get sessions - $request->getCookie(Auth::$cookieName . '_legacy', '') + $request->getCookie(Auth::$cookieName.'_legacy', '') ) - );// Get fallback session from old clients (no SameSite support) + ); // Get fallback session from old clients (no SameSite support) // Get fallback session from clients who block 3rd-party cookies if ($response) { @@ -991,7 +993,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons if ( $user->isEmpty() // Check a document has been found in the DB - || !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) + || ! Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) ) { // Validate user has valid login token $user = new Document([]); } @@ -1006,13 +1008,13 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons $authJWT = $request->getHeader('x-appwrite-jwt', ''); - if (!empty($authJWT) && !$project->isEmpty()) { // JWT authentication + if (! empty($authJWT) && ! $project->isEmpty()) { // JWT authentication $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. try { $payload = $jwt->decode($authJWT); } catch (JWTException $error) { - throw new Exception(Exception::USER_JWT_INVALID, 'Failed to verify JWT. ' . $error->getMessage()); + throw new Exception(Exception::USER_JWT_INVALID, 'Failed to verify JWT. '.$error->getMessage()); } $jwtUserId = $payload['userId'] ?? ''; @@ -1034,14 +1036,13 @@ App::setResource('project', function ($dbForConsole, $request, $console) { /** @var Appwrite\Utopia\Request $request */ /** @var Utopia\Database\Database $dbForConsole */ /** @var Utopia\Database\Document $console */ - $projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', '')); if (empty($projectId) || $projectId === 'console') { return $console; } - $project = Authorization::skip(fn() => $dbForConsole->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId)); return $project; }, ['dbForConsole', 'request', 'console']); @@ -1076,12 +1077,12 @@ App::setResource('console', function () { 'limit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, // 1 Year in seconds ], - 'authWhitelistEmails' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [], - 'authWhitelistIPs' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [], + 'authWhitelistEmails' => (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [], + 'authWhitelistIPs' => (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [], 'authProviders' => [ 'githubEnabled' => true, 'githubSecret' => App::getEnv('_APP_CONSOLE_GITHUB_SECRET', ''), - 'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', '') + 'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', ''), ], ]); }, []); @@ -1094,11 +1095,10 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole, $dbAdapter = $pools ->get($project->getAttribute('database')) ->pop() - ->getResource() - ; + ->getResource(); $database = new Database($dbAdapter, $cache); - $database->setNamespace('_' . $project->getInternalId()); + $database->setNamespace('_'.$project->getInternalId()); return $database; }, ['pools', 'dbForConsole', 'cache', 'project']); @@ -1107,8 +1107,7 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) { $dbAdapter = $pools ->get('console') ->pop() - ->getResource() - ; + ->getResource(); $database = new Database($dbAdapter, $cache); @@ -1125,8 +1124,7 @@ App::setResource('cache', function (Group $pools) { $adapters[] = $pools ->get($value) ->pop() - ->getResource() - ; + ->getResource(); } return new Cache(new Sharding($adapters)); @@ -1137,15 +1135,15 @@ App::setResource('deviceLocal', function () { }); App::setResource('deviceFiles', function ($project) { - return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId()); + return getDevice(APP_STORAGE_UPLOADS.'/app-'.$project->getId()); }, ['project']); App::setResource('deviceFunctions', function ($project) { - return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId()); + return getDevice(APP_STORAGE_FUNCTIONS.'/app-'.$project->getId()); }, ['project']); App::setResource('deviceBuilds', function ($project) { - return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId()); + return getDevice(APP_STORAGE_BUILDS.'/app-'.$project->getId()); }, ['project']); function getDevice($root): Device @@ -1167,7 +1165,7 @@ function getDevice($root): Device $bucket = $dsn->getPath(); $region = $dsn->getParam('region'); } catch (\Exception $e) { - Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); + Console::error($e->getMessage().'Invalid DSN. Defaulting to Local device.'); } switch ($device) { @@ -1240,7 +1238,6 @@ App::setResource('promiseAdapter', function ($register) { }, ['register']); App::setResource('schema', function ($utopia, $dbForProject) { - $complexity = function (int $complexity, array $args) { $queries = Query::parseQueries($args['queries'] ?? []); $query = Query::getByType($queries, [Query::TYPE_LIMIT])[0] ?? null; @@ -1250,7 +1247,7 @@ App::setResource('schema', function ($utopia, $dbForProject) { }; $attributes = function (int $limit, int $offset) use ($dbForProject) { - $attrs = Authorization::skip(fn() => $dbForProject->find('attributes', [ + $attrs = Authorization::skip(fn () => $dbForProject->find('attributes', [ Query::limit($limit), Query::offset($offset), ])); @@ -1280,7 +1277,7 @@ App::setResource('schema', function ($utopia, $dbForProject) { $params = [ 'list' => function (string $databaseId, string $collectionId, array $args) { - return [ 'queries' => $args['queries']]; + return ['queries' => $args['queries']]; }, 'create' => function (string $databaseId, string $collectionId, array $args) { $id = $args['id'] ?? 'unique()'; @@ -1328,18 +1325,21 @@ App::setResource('schema', function ($utopia, $dbForProject) { App::setResource('contributors', function () { $path = 'app/config/cloud/contributors.json'; $list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : []; + return $list; }, []); App::setResource('employees', function () { $path = 'app/config/cloud/employees.json'; $list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : []; + return $list; }, []); App::setResource('heroes', function () { $path = 'app/config/cloud/heroes.json'; $list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : []; + return $list; }, []); @@ -1347,12 +1347,13 @@ App::setResource('requestTimestamp', function ($request) { //TODO: Move this to the Request class itself $timestampHeader = $request->getHeader('x-appwrite-timestamp'); $requestTimestamp = null; - if (!empty($timestampHeader)) { + if (! empty($timestampHeader)) { try { $requestTimestamp = new \DateTime($timestampHeader); } catch (\Throwable $e) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid X-Appwrite-Timestamp header value'); } } + return $requestTimestamp; }, ['request']); diff --git a/app/preload.php b/app/preload.php index e587bfaed5..cec44d4a7d 100644 --- a/app/preload.php +++ b/app/preload.php @@ -5,38 +5,36 @@ * * Inializes both Appwrite API entry point, queue workers, and CLI tasks. * Set configuration, framework resources, app constants - * */ - ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); -if (file_exists(__DIR__ . '/../vendor/autoload.php')) { - require __DIR__ . '/../vendor/autoload.php'; +if (file_exists(__DIR__.'/../vendor/autoload.php')) { + require __DIR__.'/../vendor/autoload.php'; } use Utopia\Preloader\Preloader; -include __DIR__ . '/controllers/general.php'; +include __DIR__.'/controllers/general.php'; $preloader = new Preloader(); foreach ( [ - realpath(__DIR__ . '/../vendor/composer'), - realpath(__DIR__ . '/../vendor/amphp'), - realpath(__DIR__ . '/../vendor/felixfbecker'), - realpath(__DIR__ . '/../vendor/twig/twig'), - realpath(__DIR__ . '/../vendor/guzzlehttp/guzzle'), - realpath(__DIR__ . '/../vendor/slickdeals'), - realpath(__DIR__ . '/../vendor/psr/log'), - realpath(__DIR__ . '/../vendor/matomo'), - realpath(__DIR__ . '/../vendor/symfony'), - realpath(__DIR__ . '/../vendor/mongodb'), - realpath(__DIR__ . '/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload - realpath(__DIR__ . '/../vendor/utopia-php/cache'), // TODO: remove memcached autoload - realpath(__DIR__ . '/../vendor/utopia-php/queue/src/Queue/Adapter/Workerman.php'), // TODO: remove workerman autoload + realpath(__DIR__.'/../vendor/composer'), + realpath(__DIR__.'/../vendor/amphp'), + realpath(__DIR__.'/../vendor/felixfbecker'), + realpath(__DIR__.'/../vendor/twig/twig'), + realpath(__DIR__.'/../vendor/guzzlehttp/guzzle'), + realpath(__DIR__.'/../vendor/slickdeals'), + realpath(__DIR__.'/../vendor/psr/log'), + realpath(__DIR__.'/../vendor/matomo'), + realpath(__DIR__.'/../vendor/symfony'), + realpath(__DIR__.'/../vendor/mongodb'), + realpath(__DIR__.'/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload + realpath(__DIR__.'/../vendor/utopia-php/cache'), // TODO: remove memcached autoload + realpath(__DIR__.'/../vendor/utopia-php/queue/src/Queue/Adapter/Workerman.php'), // TODO: remove workerman autoload ] as $key => $value ) { if ($value !== false) { @@ -45,7 +43,7 @@ foreach ( } $preloader - ->paths(realpath(__DIR__ . '/../app/config')) - ->paths(realpath(__DIR__ . '/../app/controllers')) - ->paths(realpath(__DIR__ . '/../src')) + ->paths(realpath(__DIR__.'/../app/config')) + ->paths(realpath(__DIR__.'/../app/controllers')) + ->paths(realpath(__DIR__.'/../src')) ->load(); diff --git a/app/realtime.php b/app/realtime.php index 772eee49d6..24def0ec61 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -3,6 +3,7 @@ use Appwrite\Auth\Auth; use Appwrite\Messaging\Adapter\Realtime; use Appwrite\Network\Validator\Origin; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; @@ -12,23 +13,22 @@ use Swoole\Timer; use Utopia\Abuse\Abuse; use Utopia\Abuse\Adapters\TimeLimit; use Utopia\App; -use Utopia\CLI\Console; -use Utopia\Database\Helpers\ID; -use Utopia\Database\Helpers\Role; -use Utopia\Logger\Log; -use Utopia\Database\DateTime; -use Utopia\Database\Document; -use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; -use Appwrite\Utopia\Request; use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; +use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; -use Utopia\WebSocket\Server; +use Utopia\Database\DateTime; +use Utopia\Database\Document; +use Utopia\Database\Helpers\ID; +use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; +use Utopia\Logger\Log; use Utopia\WebSocket\Adapter; +use Utopia\WebSocket\Server; -require_once __DIR__ . '/init.php'; +require_once __DIR__.'/init.php'; Runtime::enableCoroutine(SWOOLE_HOOK_ALL); @@ -42,8 +42,7 @@ function getConsoleDB(): Database $dbAdapter = $pools ->get('console') ->pop() - ->getResource() - ; + ->getResource(); $database = new Database($dbAdapter, getCache()); @@ -66,11 +65,10 @@ function getProjectDB(Document $project): Database $dbAdapter = $pools ->get($project->getAttribute('database')) ->pop() - ->getResource() - ; + ->getResource(); $database = new Database($dbAdapter, getCache()); - $database->setNamespace('_' . $project->getInternalId()); + $database->setNamespace('_'.$project->getInternalId()); return $database; } @@ -80,7 +78,6 @@ function getCache(): Cache global $register; $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - $list = Config::getParam('pools-cache', []); $adapters = []; @@ -88,8 +85,7 @@ function getCache(): Cache $adapters[] = $pools ->get($value) ->pop() - ->getResource() - ; + ->getResource(); } return new Cache(new Sharding($adapters)); @@ -126,7 +122,7 @@ $logError = function (Throwable $error, string $action) use ($register) { $version = App::getEnv('_APP_VERSION', 'UNKNOWN'); $log = new Log(); - $log->setNamespace("realtime"); + $log->setNamespace('realtime'); $log->setServer(\gethostname()); $log->setVersion($version); $log->setType(Log::TYPE_ERROR); @@ -146,13 +142,13 @@ $logError = function (Throwable $error, string $action) use ($register) { $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); $responseCode = $logger->addLog($log); - Console::info('Realtime log pushed with status code: ' . $responseCode); + Console::info('Realtime log pushed with status code: '.$responseCode); } - Console::error('[Error] Type: ' . get_class($error)); - Console::error('[Error] Message: ' . $error->getMessage()); - Console::error('[Error] File: ' . $error->getFile()); - Console::error('[Error] Line: ' . $error->getLine()); + Console::error('[Error] Type: '.get_class($error)); + Console::error('[Error] Message: '.$error->getMessage()); + Console::error('[Error] File: '.$error->getFile()); + Console::error('[Error] Line: '.$error->getLine()); }; $server->error($logError); @@ -177,7 +173,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume '$permissions' => [], 'container' => $containerId, 'timestamp' => DateTime::now(), - 'value' => '{}' + 'value' => '{}', ]); $statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document)); @@ -211,7 +207,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument)); } catch (\Throwable $th) { - call_user_func($logError, $th, "updateWorkerDocument"); + call_user_func($logError, $th, 'updateWorkerDocument'); } finally { $register->get('pools')->reclaim(); } @@ -219,12 +215,12 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume }); $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime, $logError) { - Console::success('Worker ' . $workerId . ' started successfully'); + Console::success('Worker '.$workerId.' started successfully'); $attempts = 0; $start = time(); - Timer::tick(5000, function () use ($server, $register, $realtime, $stats, $logError) { + Timer::tick(5000, function () use ($server, $register, $realtime, $stats) { /** * Sending current connections to project channels on the console project every 5 seconds. */ @@ -243,34 +239,34 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, foreach ($list as $document) { foreach (json_decode($document->getAttribute('value')) as $projectId => $value) { if (array_key_exists($projectId, $payload)) { - $payload[$projectId] += $value; + $payload[$projectId] += $value; } else { - $payload[$projectId] = $value; + $payload[$projectId] = $value; } } } foreach ($stats as $projectId => $value) { - if (!array_key_exists($projectId, $payload)) { + if (! array_key_exists($projectId, $payload)) { continue; } $event = [ 'project' => 'console', - 'roles' => ['team:' . $stats->get($projectId, 'teamId')], + 'roles' => ['team:'.$stats->get($projectId, 'teamId')], 'data' => [ 'events' => ['stats.connections'], 'channels' => ['project'], 'timestamp' => DateTime::formatTz(DateTime::now()), 'payload' => [ - $projectId => $payload[$projectId] - ] - ] + $projectId => $payload[$projectId], + ], + ], ]; $server->send($realtime->getSubscribers($event), json_encode([ 'type' => 'event', - 'data' => $event['data'] + 'data' => $event['data'], ])); } @@ -289,13 +285,13 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, 'events' => ['test.event'], 'channels' => ['tests'], 'timestamp' => DateTime::formatTz(DateTime::now()), - 'payload' => $payload - ] + 'payload' => $payload, + ], ]; $server->send($realtime->getSubscribers($event), json_encode([ 'type' => 'event', - 'data' => $event['data'] + 'data' => $event['data'], ])); } }); @@ -303,8 +299,8 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, while ($attempts < 300) { try { if ($attempts > 0) { - Console::error('Pub/sub connection lost (lasted ' . (time() - $start) . ' seconds, worker: ' . $workerId . '). - Attempting restart in 5 seconds (attempt #' . $attempts . ')'); + Console::error('Pub/sub connection lost (lasted '.(time() - $start).' seconds, worker: '.$workerId.'). + Attempting restart in 5 seconds (attempt #'.$attempts.')'); sleep(5); // 5 sec delay between connection attempts } $start = time(); @@ -314,9 +310,9 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, if ($redis->ping(true)) { $attempts = 0; - Console::success('Pub/sub connection established (worker: ' . $workerId . ')'); + Console::success('Pub/sub connection established (worker: '.$workerId.')'); } else { - Console::error('Pub/sub failed (worker: ' . $workerId . ')'); + Console::error('Pub/sub failed (worker: '.$workerId.')'); } $redis->subscribe(['realtime'], function (Redis $redis, string $channel, string $payload) use ($server, $workerId, $stats, $register, $realtime) { @@ -326,10 +322,10 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $projectId = $event['project']; $userId = $event['userId']; - if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) { - $connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId])); + if ($realtime->hasSubscriber($projectId, 'user:'.$userId)) { + $connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:'.$userId])); $consoleDatabase = getConsoleDB(); - $project = Authorization::skip(fn() => $consoleDatabase->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $consoleDatabase->getDocument('projects', $projectId)); $database = getProjectDB($project); $user = $database->getDocument('users', $userId); @@ -344,17 +340,17 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $receivers = $realtime->getSubscribers($event); - if (App::isDevelopment() && !empty($receivers)) { - Console::log("[Debug][Worker {$workerId}] Receivers: " . count($receivers)); - Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: " . json_encode($receivers)); - Console::log("[Debug][Worker {$workerId}] Event: " . $payload); + if (App::isDevelopment() && ! empty($receivers)) { + Console::log("[Debug][Worker {$workerId}] Receivers: ".count($receivers)); + Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: ".json_encode($receivers)); + Console::log("[Debug][Worker {$workerId}] Event: ".$payload); } $server->send( $receivers, json_encode([ 'type' => 'event', - 'data' => $event['data'] + 'data' => $event['data'], ]) ); @@ -363,11 +359,12 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, } }); } catch (\Throwable $th) { - call_user_func($logError, $th, "pubSubConnection"); + call_user_func($logError, $th, 'pubSubConnection'); - Console::error('Pub/sub error: ' . $th->getMessage()); + Console::error('Pub/sub error: '.$th->getMessage()); $attempts++; sleep(DATABASE_RECONNECT_SLEEP); + continue; } finally { $register->get('pools')->reclaim(); @@ -384,9 +381,9 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, Console::info("Connection open (user: {$connection})"); - App::setResource('pools', fn() => $register->get('pools')); - App::setResource('request', fn() => $request); - App::setResource('response', fn() => $response); + App::setResource('pools', fn () => $register->get('pools')); + App::setResource('request', fn () => $request); + App::setResource('response', fn () => $response); try { /** @var \Utopia\Database\Document $project */ @@ -427,7 +424,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, $origin = $request->getOrigin(); $originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', []))); - if (!$originValidator->isValid($origin) && $project->getId() !== 'console') { + if (! $originValidator->isValid($origin) && $project->getId() !== 'console') { throw new Exception($originValidator->getDescription(), 1008); } @@ -450,25 +447,25 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, 'type' => 'connected', 'data' => [ 'channels' => array_keys($channels), - 'user' => $user - ] + 'user' => $user, + ], ])); $stats->set($project->getId(), [ 'projectId' => $project->getId(), - 'teamId' => $project->getAttribute('teamId') + 'teamId' => $project->getAttribute('teamId'), ]); $stats->incr($project->getId(), 'connections'); $stats->incr($project->getId(), 'connectionsTotal'); } catch (\Throwable $th) { - call_user_func($logError, $th, "initServer"); + call_user_func($logError, $th, 'initServer'); $response = [ 'type' => 'error', 'data' => [ 'code' => $th->getCode(), - 'message' => $th->getMessage() - ] + 'message' => $th->getMessage(), + ], ]; $server->send([$connection], json_encode($response)); @@ -476,8 +473,8 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, if (App::isDevelopment()) { Console::error('[Error] Connection Error'); - Console::error('[Error] Code: ' . $response['data']['code']); - Console::error('[Error] Message: ' . $response['data']['message']); + Console::error('[Error] Code: '.$response['data']['code']); + Console::error('[Error] Message: '.$response['data']['message']); } } finally { $register->get('pools')->reclaim(); @@ -492,7 +489,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re $database = getConsoleDB(); if ($projectId !== 'console') { - $project = Authorization::skip(fn() => $database->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $database->getDocument('projects', $projectId)); $database = getProjectDB($project); } @@ -515,16 +512,16 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re $message = json_decode($message, true); - if (is_null($message) || (!array_key_exists('type', $message) && !array_key_exists('data', $message))) { + if (is_null($message) || (! array_key_exists('type', $message) && ! array_key_exists('data', $message))) { throw new Exception('Message format is not valid.', 1003); } switch ($message['type']) { - /** + /** * This type is used to authenticate. */ case 'authentication': - if (!array_key_exists('session', $message['data'])) { + if (! array_key_exists('session', $message['data'])) { throw new Exception('Payload is not valid.', 1003); } @@ -537,7 +534,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re if ( empty($user->getId()) // Check a document has been found in the DB - || !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) // Validate user has valid login token + || ! Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) // Validate user has valid login token ) { // cookie not valid throw new Exception('Session is not valid.', 1003); @@ -553,8 +550,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re 'data' => [ 'to' => 'authentication', 'success' => true, - 'user' => $user - ] + 'user' => $user, + ], ])); break; @@ -567,8 +564,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re 'type' => 'error', 'data' => [ 'code' => $th->getCode(), - 'message' => $th->getMessage() - ] + 'message' => $th->getMessage(), + ], ]; $server->send([$connection], json_encode($response)); @@ -587,7 +584,7 @@ $server->onClose(function (int $connection) use ($realtime, $stats) { } $realtime->unsubscribe($connection); - Console::info('Connection close: ' . $connection); + Console::info('Connection close: '.$connection); }); $server->start(); diff --git a/app/worker.php b/app/worker.php index ea086fa43d..bd7cf7970d 100644 --- a/app/worker.php +++ b/app/worker.php @@ -1,6 +1,6 @@ $register); +Server::setResource('register', fn () => $register); Server::setResource('dbForConsole', function (Cache $cache, Registry $register) { $pools = $register->get('pools'); $database = $pools ->get('console') ->pop() - ->getResource() - ; + ->getResource(); $adapter = new Database($database, $cache); $adapter->setNamespace('console'); @@ -52,11 +51,11 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register, $database = $pools ->get($project->getAttribute('database')) ->pop() - ->getResource() - ; + ->getResource(); $adapter = new Database($database, $cache); - $adapter->setNamespace('_' . $project->getInternalId()); + $adapter->setNamespace('_'.$project->getInternalId()); + return $adapter; }, ['cache', 'register', 'message', 'dbForConsole']); @@ -69,8 +68,7 @@ Server::setResource('cache', function (Registry $register) { $adapters[] = $pools ->get($value) ->pop() - ->getResource() - ; + ->getResource(); } return new Cache(new Sharding($adapters)); @@ -78,6 +76,7 @@ Server::setResource('cache', function (Registry $register) { Server::setResource('queueForFunctions', function (Registry $register) { $pools = $register->get('pools'); + return new Func( $pools ->get('queue') @@ -88,6 +87,7 @@ Server::setResource('queueForFunctions', function (Registry $register) { Server::setResource('queueForUsage', function (Registry $register) { $pools = $register->get('pools'); + return new Usage( $pools ->get('queue') @@ -96,7 +96,7 @@ Server::setResource('queueForUsage', function (Registry $register) { ); }, ['register']); -Server::setResource('log', fn() => new Log()); +Server::setResource('log', fn () => new Log()); Server::setResource('logger', function ($register) { return $register->get('logger'); @@ -137,12 +137,12 @@ $server } if ($logger && ($error->getCode() >= 500 || $error->getCode() === 0)) { - $log->setNamespace("appwrite-worker"); + $log->setNamespace('appwrite-worker'); $log->setServer(\gethostname()); $log->setVersion($version); $log->setType(Log::TYPE_ERROR); $log->setMessage($error->getMessage()); - $log->setAction('appwrite-queue-' . App::getEnv('QUEUE')); + $log->setAction('appwrite-queue-'.App::getEnv('QUEUE')); $log->addTag('verboseType', get_class($error)); $log->addTag('code', $error->getCode()); $log->addExtra('file', $error->getFile()); @@ -155,11 +155,11 @@ $server $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); $responseCode = $logger->addLog($log); - Console::info('Usage stats log pushed with status code: ' . $responseCode); + Console::info('Usage stats log pushed with status code: '.$responseCode); } - Console::error('[Error] Type: ' . get_class($error)); - Console::error('[Error] Message: ' . $error->getMessage()); - Console::error('[Error] File: ' . $error->getFile()); - Console::error('[Error] Line: ' . $error->getLine()); + Console::error('[Error] Type: '.get_class($error)); + Console::error('[Error] Message: '.$error->getMessage()); + Console::error('[Error] File: '.$error->getFile()); + Console::error('[Error] Line: '.$error->getLine()); }); diff --git a/app/workers/audits.php b/app/workers/audits.php index 8369ec74ec..a304fd70bb 100644 --- a/app/workers/audits.php +++ b/app/workers/audits.php @@ -5,16 +5,16 @@ use Utopia\Audit\Audit; use Utopia\CLI\Console; use Utopia\Database\Document; -require_once __DIR__ . '/../init.php'; +require_once __DIR__.'/../init.php'; Console::title('Audits V1 Worker'); -Console::success(APP_NAME . ' audits worker v1 has started'); +Console::success(APP_NAME.' audits worker v1 has started'); class AuditsV1 extends Worker { public function getName(): string { - return "audits"; + return 'audits'; } public function init(): void diff --git a/app/workers/builds.php b/app/workers/builds.php index 972eb5dd18..41c3cbdcc7 100644 --- a/app/workers/builds.php +++ b/app/workers/builds.php @@ -6,20 +6,20 @@ use Appwrite\Messaging\Adapter\Realtime; use Appwrite\Resque\Worker; use Appwrite\Utopia\Response\Model\Deployment; use Executor\Executor; -use Utopia\Database\DateTime; use Utopia\App; use Utopia\CLI\Console; -use Utopia\Database\Helpers\ID; -use Utopia\DSN\DSN; -use Utopia\Database\Document; use Utopia\Config\Config; +use Utopia\Database\DateTime; +use Utopia\Database\Document; +use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Authorization; +use Utopia\DSN\DSN; use Utopia\Storage\Storage; -require_once __DIR__ . '/../init.php'; +require_once __DIR__.'/../init.php'; Console::title('Builds V1 Worker'); -Console::success(APP_NAME . ' build worker v1 has started'); +Console::success(APP_NAME.' build worker v1 has started'); // TODO: Executor should return appropriate response codes. class BuildsV1 extends Worker @@ -28,7 +28,7 @@ class BuildsV1 extends Worker public function getName(): string { - return "builds"; + return 'builds'; } public function init(): void @@ -46,7 +46,7 @@ class BuildsV1 extends Worker switch ($type) { case BUILD_TYPE_DEPLOYMENT: case BUILD_TYPE_RETRY: - Console::info('Creating build for deployment: ' . $deployment->getId()); + Console::info('Creating build for deployment: '.$deployment->getId()); $this->buildDeployment($project, $resource, $deployment); break; @@ -81,7 +81,7 @@ class BuildsV1 extends Worker $key = $function->getAttribute('runtime'); $runtime = isset($runtimes[$key]) ? $runtimes[$key] : null; if (\is_null($runtime)) { - throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); + throw new Exception('Runtime "'.$function->getAttribute('runtime', '').'" is not supported'); } $connection = App::getEnv('_APP_CONNECTIONS_STORAGE', ''); /** @TODO : move this to the registry or someplace else */ @@ -90,7 +90,7 @@ class BuildsV1 extends Worker $dsn = new DSN($connection); $device = $dsn->getScheme(); } catch (\Exception $e) { - Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); + Console::error($e->getMessage().'Invalid DSN. Defaulting to Local device.'); } $buildId = $deployment->getAttribute('buildId', ''); @@ -111,7 +111,7 @@ class BuildsV1 extends Worker 'stdout' => '', 'stderr' => '', 'endTime' => null, - 'duration' => 0 + 'duration' => 0, ])); $deployment->setAttribute('buildId', $build->getId()); $deployment->setAttribute('buildInternalId', $build->getInternalId()); @@ -150,7 +150,7 @@ class BuildsV1 extends Worker /** Trigger Realtime */ $allEvents = Event::generateEvents('functions.[functionId].deployments.[deploymentId].update', [ 'functionId' => $function->getId(), - 'deploymentId' => $deployment->getId() + 'deploymentId' => $deployment->getId(), ]); $target = Realtime::fromPayload( // Pass first, most verbose event pattern @@ -171,6 +171,7 @@ class BuildsV1 extends Worker $vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { $carry[$var->getAttribute('key')] = $var->getAttribute('value'); + return $carry; }, []); @@ -183,12 +184,12 @@ class BuildsV1 extends Worker remove: true, entrypoint: $deployment->getAttribute('entrypoint'), workdir: '/usr/code', - destination: APP_STORAGE_BUILDS . "/app-{$project->getId()}", + destination: APP_STORAGE_BUILDS."/app-{$project->getId()}", variables: $vars, commands: [ 'sh', '-c', 'tar -zxf /tmp/code.tar.gz -C /usr/code && \ - cd /usr/local/src/ && ./build.sh' + cd /usr/local/src/ && ./build.sh', ] ); @@ -222,8 +223,7 @@ class BuildsV1 extends Worker $schedule ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); - + ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); } catch (\Throwable $th) { @@ -261,12 +261,11 @@ class BuildsV1 extends Worker ->setProject($project) ->addMetric(METRIC_BUILDS, 1) // per project ->addMetric(METRIC_BUILDS_STORAGE, $build->getAttribute('size', 0)) - ->addMetric(METRIC_BUILDS_COMPUTE, (int)$build->getAttribute('duration', 0) * 1000) + ->addMetric(METRIC_BUILDS_COMPUTE, (int) $build->getAttribute('duration', 0) * 1000) ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS), 1) // per function ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE), $build->getAttribute('size', 0)) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int)$build->getAttribute('duration', 0) * 1000) - ->trigger() - ; + ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int) $build->getAttribute('duration', 0) * 1000) + ->trigger(); } public function shutdown(): void diff --git a/app/workers/certificates.php b/app/workers/certificates.php index 824a296b75..fc72f6d4e6 100644 --- a/app/workers/certificates.php +++ b/app/workers/certificates.php @@ -7,17 +7,17 @@ use Appwrite\Template\Template; use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Database; -use Utopia\Database\Document; use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; use Utopia\Domains\Domain; use Utopia\Locale\Locale; -require_once __DIR__ . '/../init.php'; +require_once __DIR__.'/../init.php'; Console::title('Certificates V1 Worker'); -Console::success(APP_NAME . ' certificates worker v1 has started'); +Console::success(APP_NAME.' certificates worker v1 has started'); class CertificatesV1 extends Worker { @@ -30,7 +30,7 @@ class CertificatesV1 extends Worker public function getName(): string { - return "certificates"; + return 'certificates'; } public function init(): void @@ -68,7 +68,6 @@ class CertificatesV1 extends Worker * * Note: Renewals are checked and scheduled from maintenence worker */ - $this->dbForConsole = $this->getConsoleDB(); $skipCheck = $this->args['skipRenewCheck'] ?? false; // If true, we won't double-check expiry from cert file @@ -79,7 +78,7 @@ class CertificatesV1 extends Worker $certificate = $this->dbForConsole->findOne('certificates', [Query::equal('domain', [$domain->get()])]); // If we don't have certificate for domain yet, let's create new document. At the end we save it - if (!$certificate) { + if (! $certificate) { $certificate = new Document(); $certificate->setAttribute('domain', $domain->get()); } @@ -92,14 +91,14 @@ class CertificatesV1 extends Worker } // Validate domain and DNS records. Skip if job is forced - if (!$skipCheck) { + if (! $skipCheck) { $mainDomain = $this->getMainDomain(); - $isMainDomain = !isset($mainDomain) || $domain->get() === $mainDomain; + $isMainDomain = ! isset($mainDomain) || $domain->get() === $mainDomain; $this->validateDomain($domain, $isMainDomain); } // If certificate exists already, double-check expiry date. Skip if job is forced - if (!$skipCheck && !$this->isRenewRequired($domain->get())) { + if (! $skipCheck && ! $this->isRenewRequired($domain->get())) { throw new Exception('Renew isn\'t required.'); } @@ -152,16 +151,15 @@ class CertificatesV1 extends Worker /** * Save certificate data into database. * - * @param string $domain Domain name that certificate is for - * @param Document $certificate Certificate document that we need to save - * + * @param string $domain Domain name that certificate is for + * @param Document $certificate Certificate document that we need to save * @return void */ private function saveCertificateDocument(string $domain, Document $certificate): void { // Check if update or insert required $certificateDocument = $this->dbForConsole->findOne('certificates', [Query::equal('domain', [$domain])]); - if (!empty($certificateDocument) && !$certificateDocument->isEmpty()) { + if (! empty($certificateDocument) && ! $certificateDocument->isEmpty()) { // Merge new data with current data $certificate = new Document(\array_merge($certificateDocument->getArrayCopy(), $certificate->getArrayCopy())); @@ -182,7 +180,7 @@ class CertificatesV1 extends Worker private function getMainDomain(): ?string { $envDomain = App::getEnv('_APP_DOMAIN', ''); - if (!empty($envDomain) && $envDomain !== 'localhost') { + if (! empty($envDomain) && $envDomain !== 'localhost') { return $envDomain; } else { $domainDocument = $this->dbForConsole->findOne('domains', [Query::orderAsc('_id')]); @@ -199,9 +197,8 @@ class CertificatesV1 extends Worker * - Domain needs to be public and valid (prevents NFT domains that are not supported by Let's Encrypt) * - Domain must have proper DNS record * - * @param Domain $domain Domain which we validate - * @param bool $isMainDomain In case of master domain, we look for different DNS configurations - * + * @param Domain $domain Domain which we validate + * @param bool $isMainDomain In case of master domain, we look for different DNS configurations * @return void */ private function validateDomain(Domain $domain, bool $isMainDomain): void @@ -210,23 +207,23 @@ class CertificatesV1 extends Worker throw new Exception('Missing certificate domain.'); } - if (!$domain->isKnown() || $domain->isTest()) { + if (! $domain->isKnown() || $domain->isTest()) { throw new Exception('Unknown public suffix for domain.'); } - if (!$isMainDomain) { + if (! $isMainDomain) { // TODO: Would be awesome to also support A/AAAA records here. Maybe dry run? // Validate if domain target is properly configured $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); - if (!$target->isKnown() || $target->isTest()) { - throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.'); + if (! $target->isKnown() || $target->isTest()) { + throw new Exception('Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.'); } // Verify domain with DNS records $validator = new CNAME($target->get()); - if (!$validator->isValid($domain->get())) { + if (! $validator->isValid($domain->get())) { throw new Exception('Failed to verify domain DNS records.'); } } else { @@ -238,13 +235,12 @@ class CertificatesV1 extends Worker /** * Reads expiry date of certificate from file and decides if renewal is required or not. * - * @param string $domain Domain for which we check certificate file - * + * @param string $domain Domain for which we check certificate file * @return bool True, if certificate needs to be renewed */ private function isRenewRequired(string $domain): bool { - $certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem'; + $certPath = APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem'; if (\file_exists($certPath)) { $validTo = null; @@ -268,9 +264,8 @@ class CertificatesV1 extends Worker /** * LetsEncrypt communication to issue certificate (using certbot CLI) * - * @param string $folder Folder into which certificates should be generated - * @param string $domain Domain to generate certificate for - * + * @param string $folder Folder into which certificates should be generated + * @param string $domain Domain to generate certificate for * @return array Named array with keys 'stdout' and 'stderr', both string */ private function issueCertificate(string $folder, string $domain, string $email): array @@ -280,83 +275,82 @@ class CertificatesV1 extends Worker $staging = (App::isProduction()) ? '' : ' --dry-run'; $exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}" - . " --email " . $email - . " --cert-name " . $folder - . " -w " . APP_STORAGE_CERTIFICATES - . " -d {$domain}", '', $stdout, $stderr); + .' --email '.$email + .' --cert-name '.$folder + .' -w '.APP_STORAGE_CERTIFICATES + ." -d {$domain}", '', $stdout, $stderr); // Unexpected error, usually 5XX, API limits, ... if ($exit !== 0) { - throw new Exception('Failed to issue a certificate with message: ' . $stderr); + throw new Exception('Failed to issue a certificate with message: '.$stderr); } return [ 'stdout' => $stdout, - 'stderr' => $stderr + 'stderr' => $stderr, ]; } /** * Read new renew date from certificate file generated by Let's Encrypt * - * @param string $domain Domain which certificate was generated for - * + * @param string $domain Domain which certificate was generated for * @return string */ private function getRenewDate(string $domain): string { - $certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem'; + $certPath = APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem'; $certData = openssl_x509_parse(file_get_contents($certPath)); $validTo = $certData['validTo_time_t'] ?? null; $dt = (new \DateTime())->setTimestamp($validTo); + return DateTime::addSeconds($dt, -60 * 60 * 24 * 30); // -30 days } /** * Method to take files from Let's Encrypt, and put it into Traefik. * - * @param string $domain Domain which certificate was generated for - * @param string $folder Folder in which certificates were generated - * @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error - * + * @param string $domain Domain which certificate was generated for + * @param string $folder Folder in which certificates were generated + * @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error * @return void */ private function applyCertificateFiles(string $folder, string $domain, array $letsEncryptData): void { // Prepare folder in storage for domain - $path = APP_STORAGE_CERTIFICATES . '/' . $domain; - if (!\is_readable($path)) { - if (!\mkdir($path, 0755, true)) { + $path = APP_STORAGE_CERTIFICATES.'/'.$domain; + if (! \is_readable($path)) { + if (! \mkdir($path, 0755, true)) { throw new Exception('Failed to create path for certificate.'); } } // Move generated files - if (!@\rename('/etc/letsencrypt/live/' . $folder . '/cert.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem')) { - throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']); + if (! @\rename('/etc/letsencrypt/live/'.$folder.'/cert.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem')) { + throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']); } - if (!@\rename('/etc/letsencrypt/live/' . $folder . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/chain.pem')) { - throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']); + if (! @\rename('/etc/letsencrypt/live/'.$folder.'/chain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/chain.pem')) { + throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']); } - if (!@\rename('/etc/letsencrypt/live/' . $folder . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/fullchain.pem')) { - throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']); + if (! @\rename('/etc/letsencrypt/live/'.$folder.'/fullchain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/fullchain.pem')) { + throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']); } - if (!@\rename('/etc/letsencrypt/live/' . $folder . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/privkey.pem')) { - throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']); + if (! @\rename('/etc/letsencrypt/live/'.$folder.'/privkey.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/privkey.pem')) { + throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']); } $config = \implode(PHP_EOL, [ - "tls:", - " certificates:", + 'tls:', + ' certificates:', " - certFile: /storage/certificates/{$domain}/fullchain.pem", - " keyFile: /storage/certificates/{$domain}/privkey.pem" + " keyFile: /storage/certificates/{$domain}/privkey.pem", ]); // Save configuration into Traefik using our new cert files - if (!\file_put_contents(APP_STORAGE_CONFIG . '/' . $domain . '.yml', $config)) { + if (! \file_put_contents(APP_STORAGE_CONFIG.'/'.$domain.'.yml', $config)) { throw new Exception('Failed to save Traefik configuration.'); } } @@ -364,39 +358,38 @@ class CertificatesV1 extends Worker /** * Method to make sure information about error is delivered to admnistrator. * - * @param string $domain Domain that caused the error - * @param string $errorMessage Verbose error message - * @param int $attempt How many times it failed already - * + * @param string $domain Domain that caused the error + * @param string $errorMessage Verbose error message + * @param int $attempt How many times it failed already * @return void */ private function notifyError(string $domain, string $errorMessage, int $attempt): void { // Log error into console - Console::warning('Cannot renew domain (' . $domain . ') on attempt no. ' . $attempt . ' certificate: ' . $errorMessage); + Console::warning('Cannot renew domain ('.$domain.') on attempt no. '.$attempt.' certificate: '.$errorMessage); // Send mail to administratore mail $locale = new Locale(App::getEnv('_APP_LOCALE', 'en')); - if (!$locale->getText('emails.sender') || !$locale->getText("emails.certificate.hello") || !$locale->getText("emails.certificate.subject") || !$locale->getText("emails.certificate.body") || !$locale->getText("emails.certificate.footer") || !$locale->getText("emails.certificate.thanks") || !$locale->getText("emails.certificate.signature")) { + if (! $locale->getText('emails.sender') || ! $locale->getText('emails.certificate.hello') || ! $locale->getText('emails.certificate.subject') || ! $locale->getText('emails.certificate.body') || ! $locale->getText('emails.certificate.footer') || ! $locale->getText('emails.certificate.thanks') || ! $locale->getText('emails.certificate.signature')) { $locale->setDefault('en'); } - $body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl'); + $body = Template::fromFile(__DIR__.'/../config/locale/templates/email-base.tpl'); - $subject = \sprintf($locale->getText("emails.certificate.subject"), $domain); - $body->setParam('{{domain}}', $domain); - $body->setParam('{{error}}', $errorMessage); - $body->setParam('{{attempt}}', $attempt); + $subject = \sprintf($locale->getText('emails.certificate.subject'), $domain); + $body->setParam('{{domain}}', $domain); + $body->setParam('{{error}}', $errorMessage); + $body->setParam('{{attempt}}', $attempt); $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.certificate.hello")) - ->setParam('{{body}}', $locale->getText("emails.certificate.body")) - ->setParam('{{redirect}}', 'https://' . $domain) - ->setParam('{{footer}}', $locale->getText("emails.certificate.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.certificate.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.certificate.signature")) + ->setParam('{{hello}}', $locale->getText('emails.certificate.hello')) + ->setParam('{{body}}', $locale->getText('emails.certificate.body')) + ->setParam('{{redirect}}', 'https://'.$domain) + ->setParam('{{footer}}', $locale->getText('emails.certificate.footer')) + ->setParam('{{thanks}}', $locale->getText('emails.certificate.thanks')) + ->setParam('{{signature}}', $locale->getText('emails.certificate.signature')) ->setParam('{{project}}', 'Console') ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -418,9 +411,8 @@ class CertificatesV1 extends Worker * - when renew creates new document? It might? * - overall makes it more reliable * - * @param string $certificateId ID of a new or updated certificate document - * @param string $domain Domain that is affected by new certificate - * + * @param string $certificateId ID of a new or updated certificate document + * @param string $domain Domain that is affected by new certificate * @return void */ private function updateDomainDocuments(string $certificateId, string $domain): void diff --git a/app/workers/databases.php b/app/workers/databases.php index 764f668f33..6490c7a8d9 100644 --- a/app/workers/databases.php +++ b/app/workers/databases.php @@ -9,10 +9,10 @@ use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Exception as DatabaseException; -require_once __DIR__ . '/../init.php'; +require_once __DIR__.'/../init.php'; Console::title('Database V1 Worker'); -Console::success(APP_NAME . ' database worker v1 has started' . "\n"); +Console::success(APP_NAME.' database worker v1 has started'."\n"); class DatabaseV1 extends Worker { @@ -51,7 +51,7 @@ class DatabaseV1 extends Worker break; default: - Console::error('No database operation for type: ' . $type); + Console::error('No database operation for type: '.$type); break; } } @@ -61,10 +61,10 @@ class DatabaseV1 extends Worker } /** - * @param Document $database - * @param Document $collection - * @param Document $attribute - * @param Document $project + * @param Document $database + * @param Document $collection + * @param Document $attribute + * @param Document $project */ protected function createAttribute(Document $database, Document $collection, Document $attribute, Document $project): void { @@ -75,7 +75,7 @@ class DatabaseV1 extends Worker $events = Event::generateEvents('databases.[databaseId].collections.[collectionId].attributes.[attributeId].update', [ 'databaseId' => $database->getId(), 'collectionId' => $collection->getId(), - 'attributeId' => $attribute->getId() + 'attributeId' => $attribute->getId(), ]); /** * Fetch attribute from the database, since with Resque float values are loosing informations. @@ -99,15 +99,15 @@ class DatabaseV1 extends Worker try { switch ($type) { case Database::VAR_RELATIONSHIP: - $relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']); + $relatedCollection = $dbForProject->getDocument('database_'.$database->getInternalId(), $options['relatedCollection']); if ($relatedCollection->isEmpty()) { throw new DatabaseException('Collection not found'); } if ( - !$dbForProject->createRelationship( - collection: 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), - relatedCollection: 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), + ! $dbForProject->createRelationship( + collection: 'database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), + relatedCollection: 'database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId(), type: $options['relationType'], twoWay: $options['twoWay'], id: $key, @@ -119,12 +119,12 @@ class DatabaseV1 extends Worker } if ($options['twoWay']) { - $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']); + $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$options['twoWayKey']); $dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'available')); } break; default: - if (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) { + if (! $dbForProject->createAttribute('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) { throw new Exception('Failed to create Attribute'); } } @@ -170,23 +170,24 @@ class DatabaseV1 extends Worker options: [ 'projectId' => $projectId, 'databaseId' => $database->getId(), - 'collectionId' => $collection->getId() + 'collectionId' => $collection->getId(), ] ); } if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) { - $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); + $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $relatedCollection->getId()); } - $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId); + $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId); } /** - * @param Document $database - * @param Document $collection - * @param Document $attribute - * @param Document $project + * @param Document $database + * @param Document $collection + * @param Document $attribute + * @param Document $project + * * @throws Throwable */ protected function deleteAttribute(Document $database, Document $collection, Document $attribute, Document $project): void @@ -198,7 +199,7 @@ class DatabaseV1 extends Worker $events = Event::generateEvents('databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete', [ 'databaseId' => $database->getId(), 'collectionId' => $collection->getId(), - 'attributeId' => $attribute->getId() + 'attributeId' => $attribute->getId(), ]); $collectionId = $collection->getId(); $key = $attribute->getAttribute('key', ''); @@ -219,25 +220,25 @@ class DatabaseV1 extends Worker if ($status !== 'failed') { if ($type === Database::VAR_RELATIONSHIP) { if ($options['twoWay']) { - $relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']); + $relatedCollection = $dbForProject->getDocument('database_'.$database->getInternalId(), $options['relatedCollection']); if ($relatedCollection->isEmpty()) { throw new DatabaseException('Collection not found'); } - $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']); + $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$options['twoWayKey']); } - if (!$dbForProject->deleteRelationship('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { + if (! $dbForProject->deleteRelationship('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) { $dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'stuck')); throw new DatabaseException('Failed to delete Relationship'); } - } elseif (!$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { + } elseif (! $dbForProject->deleteAttribute('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) { throw new DatabaseException('Failed to delete Attribute'); } } $dbForProject->deleteDocument('attributes', $attribute->getId()); - if (!$relatedAttribute->isEmpty()) { + if (! $relatedAttribute->isEmpty()) { $dbForProject->deleteDocument('attributes', $relatedAttribute->getId()); } } catch (\Exception $e) { @@ -245,7 +246,7 @@ class DatabaseV1 extends Worker if ($e instanceof DatabaseException) { $attribute->setAttribute('error', $e->getMessage()); - if (!$relatedAttribute->isEmpty()) { + if (! $relatedAttribute->isEmpty()) { $relatedAttribute->setAttribute('error', $e->getMessage()); } } @@ -254,7 +255,7 @@ class DatabaseV1 extends Worker $attribute->getId(), $attribute->setAttribute('status', 'stuck') ); - if (!$relatedAttribute->isEmpty()) { + if (! $relatedAttribute->isEmpty()) { $dbForProject->updateDocument( 'attributes', $relatedAttribute->getId(), @@ -278,7 +279,7 @@ class DatabaseV1 extends Worker options: [ 'projectId' => $projectId, 'databaseId' => $database->getId(), - 'collectionId' => $collection->getId() + 'collectionId' => $collection->getId(), ] ); } @@ -334,20 +335,21 @@ class DatabaseV1 extends Worker } } - $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId); - $dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId()); + $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId); + $dbForProject->deleteCachedCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId()); - if (!$relatedCollection->isEmpty() && !$relatedAttribute->isEmpty()) { - $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); - $dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); + if (! $relatedCollection->isEmpty() && ! $relatedAttribute->isEmpty()) { + $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $relatedCollection->getId()); + $dbForProject->deleteCachedCollection('database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId()); } } /** - * @param Document $database - * @param Document $collection - * @param Document $index - * @param Document $project + * @param Document $database + * @param Document $collection + * @param Document $index + * @param Document $project + * * @throws \Exception */ protected function createIndex(Document $database, Document $collection, Document $index, Document $project): void @@ -359,7 +361,7 @@ class DatabaseV1 extends Worker $events = Event::generateEvents('databases.[databaseId].collections.[collectionId].indexes.[indexId].update', [ 'databaseId' => $database->getId(), 'collectionId' => $collection->getId(), - 'indexId' => $index->getId() + 'indexId' => $index->getId(), ]); $collectionId = $collection->getId(); $key = $index->getAttribute('key', ''); @@ -370,7 +372,7 @@ class DatabaseV1 extends Worker $project = $dbForConsole->getDocument('projects', $projectId); try { - if (!$dbForProject->createIndex('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) { + if (! $dbForProject->createIndex('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) { throw new DatabaseException('Failed to create Index'); } $dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available')); @@ -402,19 +404,19 @@ class DatabaseV1 extends Worker options: [ 'projectId' => $projectId, 'databaseId' => $database->getId(), - 'collectionId' => $collection->getId() + 'collectionId' => $collection->getId(), ] ); } - $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId); + $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId); } /** - * @param Document $database - * @param Document $collection - * @param Document $index - * @param Document $project + * @param Document $database + * @param Document $collection + * @param Document $index + * @param Document $project */ protected function deleteIndex(Document $database, Document $collection, Document $index, Document $project): void { @@ -425,14 +427,14 @@ class DatabaseV1 extends Worker $events = Event::generateEvents('databases.[databaseId].collections.[collectionId].indexes.[indexId].delete', [ 'databaseId' => $database->getId(), 'collectionId' => $collection->getId(), - 'indexId' => $index->getId() + 'indexId' => $index->getId(), ]); $key = $index->getAttribute('key'); $status = $index->getAttribute('status', ''); $project = $dbForConsole->getDocument('projects', $projectId); try { - if ($status !== 'failed' && !$dbForProject->deleteIndex('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { + if ($status !== 'failed' && ! $dbForProject->deleteIndex('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) { throw new DatabaseException('Failed to delete index'); } $dbForProject->deleteDocument('indexes', $index->getId()); @@ -464,11 +466,11 @@ class DatabaseV1 extends Worker options: [ 'projectId' => $projectId, 'databaseId' => $database->getId(), - 'collectionId' => $collection->getId() + 'collectionId' => $collection->getId(), ] ); } - $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collection->getId()); + $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collection->getId()); } } diff --git a/app/workers/deletes.php b/app/workers/deletes.php index 7f426bf4f4..7d276f22cf 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -1,29 +1,29 @@ deleteCollection($document, $project); break; } - Console::error('No lazy delete operation available for document of type: ' . $document->getCollection()); + Console::error('No lazy delete operation available for document of type: '.$document->getCollection()); break; } break; @@ -82,14 +82,14 @@ class DeletesV1 extends Worker case DELETE_TYPE_AUDIT: $datetime = $this->args['datetime'] ?? null; - if (!empty($datetime)) { + if (! empty($datetime)) { $this->deleteAuditLogs($datetime); } $document = new Document($this->args['document'] ?? []); - if (!$document->isEmpty()) { - $this->deleteAuditLogsByResource('document/' . $document->getId(), $project); + if (! $document->isEmpty()) { + $this->deleteAuditLogsByResource('document/'.$document->getId(), $project); } break; @@ -125,7 +125,7 @@ class DeletesV1 extends Worker $this->deleteSchedules($this->args['datetime']); break; default: - Console::error('No delete operation for type: ' . $type); + Console::error('No delete operation for type: '.$type); break; } } @@ -153,7 +153,8 @@ class DeletesV1 extends Worker if ($project->isEmpty()) { $this->getConsoleDB()->deleteDocument('schedules', $document->getId()); - Console::success('Deleted schedule for deleted project ' . $document->getAttribute('projectId')); + Console::success('Deleted schedule for deleted project '.$document->getAttribute('projectId')); + return; } @@ -161,15 +162,16 @@ class DeletesV1 extends Worker if ($function->isEmpty()) { $this->getConsoleDB()->deleteDocument('schedules', $document->getId()); - Console::success('Deleted schedule for function ' . $document->getAttribute('resourceId')); + Console::success('Deleted schedule for function '.$document->getAttribute('resourceId')); } } ); } /** - * @param Document $project - * @param string $resource + * @param Document $project + * @param string $resource + * * @throws Exception */ protected function deleteCacheByResource(Document $project, string $resource): void @@ -180,19 +182,19 @@ class DeletesV1 extends Worker if ($document) { $cache = new Cache( - new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId) + new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId) ); $this->deleteById( $document, $dbForProject, function ($document) use ($cache, $projectId) { - $path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId(); + $path = APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId.DIRECTORY_SEPARATOR.$document->getId(); if ($cache->purge($document->getId())) { - Console::success('Deleting cache file: ' . $path); + Console::success('Deleting cache file: '.$path); } else { - Console::error('Failed to delete cache file: ' . $path); + Console::error('Failed to delete cache file: '.$path); } } ); @@ -200,7 +202,8 @@ class DeletesV1 extends Worker } /** - * @param string $datetime + * @param string $datetime + * * @throws Exception */ protected function deleteCacheByDate(string $datetime): void @@ -209,7 +212,7 @@ class DeletesV1 extends Worker $projectId = $project->getId(); $dbForProject = $this->getProjectDB($project); $cache = new Cache( - new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId) + new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId) ); $query = [ @@ -221,22 +224,21 @@ class DeletesV1 extends Worker $query, $dbForProject, function (Document $document) use ($cache, $projectId) { - $path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId(); + $path = APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId.DIRECTORY_SEPARATOR.$document->getId(); if ($cache->purge($document->getId())) { - Console::success('Deleting cache file: ' . $path); + Console::success('Deleting cache file: '.$path); } else { - Console::error('Failed to delete cache file: ' . $path); + Console::error('Failed to delete cache file: '.$path); } } ); }); } - /** - * @param Document $document database document - * @param Document $project + * @param Document $document database document + * @param Document $project */ protected function deleteDatabase(Document $document, Document $project): void { @@ -245,18 +247,18 @@ class DeletesV1 extends Worker $dbForProject = $this->getProjectDB($project); - $this->deleteByGroup('database_' . $document->getInternalId(), [], $dbForProject, function ($document) use ($project) { + $this->deleteByGroup('database_'.$document->getInternalId(), [], $dbForProject, function ($document) use ($project) { $this->deleteCollection($document, $project); }); - $dbForProject->deleteCollection('database_' . $document->getInternalId()); + $dbForProject->deleteCollection('database_'.$document->getInternalId()); - $this->deleteAuditLogsByResource('database/' . $databaseId, $project); + $this->deleteAuditLogsByResource('database/'.$databaseId, $project); } /** - * @param Document $document teams document - * @param Document $project + * @param Document $document teams document + * @param Document $project */ protected function deleteCollection(Document $document, Document $project): void { @@ -273,32 +275,33 @@ class DeletesV1 extends Worker ); foreach ($relationships as $relationship) { - if (!$relationship['twoWay']) { + if (! $relationship['twoWay']) { continue; } - $relatedCollection = $dbForProject->getDocument('database_' . $databaseInternalId, $relationship['relatedCollection']); - $dbForProject->deleteDocument('attributes', $databaseInternalId . '_' . $relatedCollection->getInternalId() . '_' . $relationship['twoWayKey']); - $dbForProject->deleteCachedDocument('database_' . $databaseInternalId, $relatedCollection->getId()); - $dbForProject->deleteCachedCollection('database_' . $databaseInternalId . '_collection_' . $relatedCollection->getInternalId()); + $relatedCollection = $dbForProject->getDocument('database_'.$databaseInternalId, $relationship['relatedCollection']); + $dbForProject->deleteDocument('attributes', $databaseInternalId.'_'.$relatedCollection->getInternalId().'_'.$relationship['twoWayKey']); + $dbForProject->deleteCachedDocument('database_'.$databaseInternalId, $relatedCollection->getId()); + $dbForProject->deleteCachedCollection('database_'.$databaseInternalId.'_collection_'.$relatedCollection->getInternalId()); } - $dbForProject->deleteCollection('database_' . $databaseInternalId . '_collection_' . $document->getInternalId()); + $dbForProject->deleteCollection('database_'.$databaseInternalId.'_collection_'.$document->getInternalId()); $this->deleteByGroup('attributes', [ Query::equal('databaseInternalId', [$databaseInternalId]), - Query::equal('collectionInternalId', [$collectionInternalId]) + Query::equal('collectionInternalId', [$collectionInternalId]), ], $dbForProject); $this->deleteByGroup('indexes', [ Query::equal('databaseInternalId', [$databaseInternalId]), - Query::equal('collectionInternalId', [$collectionInternalId]) + Query::equal('collectionInternalId', [$collectionInternalId]), ], $dbForProject); - $this->deleteAuditLogsByResource('database/' . $databaseId . '/collection/' . $collectionId, $project); + $this->deleteAuditLogsByResource('database/'.$databaseId.'/collection/'.$collectionId, $project); } /** - * @param string $hourlyUsageRetentionDatetime + * @param string $hourlyUsageRetentionDatetime + * * @throws Exception */ protected function deleteUsageStats(string $hourlyUsageRetentionDatetime) @@ -314,8 +317,8 @@ class DeletesV1 extends Worker } /** - * @param Document $document teams document - * @param Document $project + * @param Document $document teams document + * @param Document $project */ protected function deleteMemberships(Document $document, Document $project): void { @@ -326,7 +329,7 @@ class DeletesV1 extends Worker $this->deleteByGroup( 'memberships', [ - Query::equal('teamInternalId', [$teamInternalId]) + Query::equal('teamInternalId', [$teamInternalId]), ], $dbForProject, function (Document $membership) use ($dbForProject) { @@ -337,8 +340,9 @@ class DeletesV1 extends Worker } /** - * @param \Utopia\Database\Document $document + * @param \Utopia\Database\Document $document * @return void + * * @throws \Exception */ protected function deleteProjectsByTeam(Document $document): void @@ -346,7 +350,7 @@ class DeletesV1 extends Worker $dbForConsole = $this->getConsoleDB(); $projects = $dbForConsole->find('projects', [ - Query::equal('teamInternalId', [$document->getInternalId()]) + Query::equal('teamInternalId', [$document->getInternalId()]), ]); foreach ($projects as $project) { @@ -356,7 +360,8 @@ class DeletesV1 extends Worker } /** - * @param Document $document project document + * @param Document $document project document + * * @throws Exception */ protected function deleteProject(Document $document): void @@ -368,7 +373,7 @@ class DeletesV1 extends Worker $dbForConsole = $this->getConsoleDB(); $domains = $dbForConsole->find('domains', [ - Query::equal('projectInternalId', [$projectInternalId]) + Query::equal('projectInternalId', [$projectInternalId]), ]); foreach ($domains as $domain) { @@ -392,22 +397,22 @@ class DeletesV1 extends Worker // Delete Platforms $this->deleteByGroup('platforms', [ - Query::equal('projectInternalId', [$projectInternalId]) + Query::equal('projectInternalId', [$projectInternalId]), ], $dbForConsole); // Delete Domains $this->deleteByGroup('domains', [ - Query::equal('projectInternalId', [$projectInternalId]) + Query::equal('projectInternalId', [$projectInternalId]), ], $dbForConsole); // Delete Keys $this->deleteByGroup('keys', [ - Query::equal('projectInternalId', [$projectInternalId]) + Query::equal('projectInternalId', [$projectInternalId]), ], $dbForConsole); // Delete Webhooks $this->deleteByGroup('webhooks', [ - Query::equal('projectInternalId', [$projectInternalId]) + Query::equal('projectInternalId', [$projectInternalId]), ], $dbForConsole); // Delete metadata tables @@ -431,8 +436,8 @@ class DeletesV1 extends Worker } /** - * @param Document $document user document - * @param Document $project + * @param Document $document user document + * @param Document $project */ protected function deleteUser(Document $document, Document $project): void { @@ -443,19 +448,19 @@ class DeletesV1 extends Worker // Delete all sessions of this user from the sessions table and update the sessions field of the user record $this->deleteByGroup('sessions', [ - Query::equal('userInternalId', [$userInternalId]) + Query::equal('userInternalId', [$userInternalId]), ], $dbForProject); $dbForProject->deleteCachedDocument('users', $userId); // Delete Memberships and decrement team membership counts $this->deleteByGroup('memberships', [ - Query::equal('userInternalId', [$userInternalId]) + Query::equal('userInternalId', [$userInternalId]), ], $dbForProject, function (Document $document) use ($dbForProject) { if ($document->getAttribute('confirm')) { // Count only confirmed members $teamId = $document->getAttribute('teamId'); $team = $dbForProject->getDocument('teams', $teamId); - if (!$team->isEmpty()) { + if (! $team->isEmpty()) { $team = $dbForProject->updateDocument( 'teams', $teamId, @@ -468,17 +473,18 @@ class DeletesV1 extends Worker // Delete tokens $this->deleteByGroup('tokens', [ - Query::equal('userInternalId', [$userInternalId]) + Query::equal('userInternalId', [$userInternalId]), ], $dbForProject); // Delete identities $this->deleteByGroup('identities', [ - Query::equal('userInternalId', [$userInternalId]) + Query::equal('userInternalId', [$userInternalId]), ], $dbForProject); } /** - * @param string $datetime + * @param string $datetime + * * @throws Exception */ protected function deleteExecutionLogs(string $datetime): void @@ -487,7 +493,7 @@ class DeletesV1 extends Worker $dbForProject = $this->getProjectDB($project); // Delete Executions $this->deleteByGroup('executions', [ - Query::lessThan('$createdAt', $datetime) + Query::lessThan('$createdAt', $datetime), ], $dbForProject); }); } @@ -505,13 +511,14 @@ class DeletesV1 extends Worker // Delete Sessions $this->deleteByGroup('sessions', [ - Query::lessThan('$createdAt', $expired) + Query::lessThan('$createdAt', $expired), ], $dbForProject); }); } /** - * @param string $datetime + * @param string $datetime + * * @throws Exception */ protected function deleteRealtimeUsage(string $datetime): void @@ -520,13 +527,14 @@ class DeletesV1 extends Worker $dbForProject = $this->getProjectDB($project); // Delete Dead Realtime Logs $this->deleteByGroup('realtime', [ - Query::lessThan('timestamp', $datetime) + Query::lessThan('timestamp', $datetime), ], $dbForProject); }); } /** - * @param string $datetime + * @param string $datetime + * * @throws Exception */ protected function deleteAbuseLogs(string $datetime): void @@ -538,17 +546,18 @@ class DeletesV1 extends Worker $this->deleteForProjectIds(function (Document $project) use ($datetime) { $projectId = $project->getId(); $dbForProject = $this->getProjectDB($project); - $timeLimit = new TimeLimit("", 0, 1, $dbForProject); + $timeLimit = new TimeLimit('', 0, 1, $dbForProject); $abuse = new Abuse($timeLimit); $status = $abuse->cleanup($datetime); - if (!$status) { - throw new Exception('Failed to delete Abuse logs for project ' . $projectId); + if (! $status) { + throw new Exception('Failed to delete Abuse logs for project '.$projectId); } }); } /** - * @param string $datetime + * @param string $datetime + * * @throws Exception */ protected function deleteAuditLogs(string $datetime): void @@ -562,28 +571,28 @@ class DeletesV1 extends Worker $dbForProject = $this->getProjectDB($project); $audit = new Audit($dbForProject); $status = $audit->cleanup($datetime); - if (!$status) { - throw new Exception('Failed to delete Audit logs for project' . $projectId); + if (! $status) { + throw new Exception('Failed to delete Audit logs for project'.$projectId); } }); } /** - * @param string $resource - * @param Document $project + * @param string $resource + * @param Document $project */ protected function deleteAuditLogsByResource(string $resource, Document $project): void { $dbForProject = $this->getProjectDB($project); $this->deleteByGroup(Audit::COLLECTION, [ - Query::equal('resource', [$resource]) + Query::equal('resource', [$resource]), ], $dbForProject); } /** - * @param Document $document function document - * @param Document $project + * @param Document $document function document + * @param Document $project */ protected function deleteFunction(Document $document, Document $project): void { @@ -595,41 +604,41 @@ class DeletesV1 extends Worker /** * Delete Variables */ - Console::info("Deleting variables for function " . $functionId); + Console::info('Deleting variables for function '.$functionId); $this->deleteByGroup('variables', [ - Query::equal('functionInternalId', [$functionInternalId]) + Query::equal('functionInternalId', [$functionInternalId]), ], $dbForProject); /** * Delete Deployments */ - Console::info("Deleting deployments for function " . $functionId); + Console::info('Deleting deployments for function '.$functionId); $storageFunctions = $this->getFunctionsDevice($projectId); $deploymentIds = []; $this->deleteByGroup('deployments', [ - Query::equal('resourceId', [$functionId]) + Query::equal('resourceId', [$functionId]), ], $dbForProject, function (Document $document) use ($storageFunctions, &$deploymentIds) { $deploymentIds[] = $document->getId(); if ($storageFunctions->delete($document->getAttribute('path', ''), true)) { - Console::success('Deleted deployment files: ' . $document->getAttribute('path', '')); + Console::success('Deleted deployment files: '.$document->getAttribute('path', '')); } else { - Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', '')); + Console::error('Failed to delete deployment files: '.$document->getAttribute('path', '')); } }); /** * Delete builds */ - Console::info("Deleting builds for function " . $functionId); + Console::info('Deleting builds for function '.$functionId); $storageBuilds = $this->getBuildsDevice($projectId); foreach ($deploymentIds as $deploymentId) { $this->deleteByGroup('builds', [ - Query::equal('deploymentId', [$deploymentId]) - ], $dbForProject, function (Document $document) use ($storageBuilds, $deploymentId) { + Query::equal('deploymentId', [$deploymentId]), + ], $dbForProject, function (Document $document) use ($storageBuilds) { if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) { - Console::success('Deleted build files: ' . $document->getAttribute('outputPath', '')); + Console::success('Deleted build files: '.$document->getAttribute('outputPath', '')); } else { - Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', '')); + Console::error('Failed to delete build files: '.$document->getAttribute('outputPath', '')); } }); } @@ -637,17 +646,17 @@ class DeletesV1 extends Worker /** * Delete Executions */ - Console::info("Deleting executions for function " . $functionId); + Console::info('Deleting executions for function '.$functionId); $this->deleteByGroup('executions', [ - Query::equal('functionId', [$functionId]) + Query::equal('functionId', [$functionId]), ], $dbForProject); // TODO: Request executor to delete runtime } /** - * @param Document $document deployment document - * @param Document $project + * @param Document $document deployment document + * @param Document $project */ protected function deleteDeployment(Document $document, Document $project): void { @@ -659,45 +668,44 @@ class DeletesV1 extends Worker /** * Delete deployment files */ - Console::info("Deleting deployment files for deployment " . $deploymentId); + Console::info('Deleting deployment files for deployment '.$deploymentId); $storageFunctions = $this->getFunctionsDevice($projectId); if ($storageFunctions->delete($document->getAttribute('path', ''), true)) { - Console::success('Deleted deployment files: ' . $document->getAttribute('path', '')); + Console::success('Deleted deployment files: '.$document->getAttribute('path', '')); } else { - Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', '')); + Console::error('Failed to delete deployment files: '.$document->getAttribute('path', '')); } /** * Delete builds */ - Console::info("Deleting builds for deployment " . $deploymentId); + Console::info('Deleting builds for deployment '.$deploymentId); $storageBuilds = $this->getBuildsDevice($projectId); $this->deleteByGroup('builds', [ - Query::equal('deploymentId', [$deploymentId]) + Query::equal('deploymentId', [$deploymentId]), ], $dbForProject, function (Document $document) use ($storageBuilds) { if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) { - Console::success('Deleted build files: ' . $document->getAttribute('outputPath', '')); + Console::success('Deleted build files: '.$document->getAttribute('outputPath', '')); } else { - Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', '')); + Console::error('Failed to delete build files: '.$document->getAttribute('outputPath', '')); } }); // TODO: Request executor to delete runtime } - /** - * @param Document $document to be deleted - * @param Database $database to delete it from - * @param callable|null $callback to perform after document is deleted - * + * @param Document $document to be deleted + * @param Database $database to delete it from + * @param callable|null $callback to perform after document is deleted * @return bool + * * @throws \Utopia\Database\Exception\Authorization */ protected function deleteById(Document $document, Database $database, callable $callback = null): bool { if ($database->deleteDocument($document->getCollection(), $document->getId())) { - Console::success('Deleted document "' . $document->getId() . '" successfully'); + Console::success('Deleted document "'.$document->getId().'" successfully'); if (is_callable($callback)) { $callback($document); @@ -705,13 +713,15 @@ class DeletesV1 extends Worker return true; } else { - Console::error('Failed to delete document: ' . $document->getId()); + Console::error('Failed to delete document: '.$document->getId()); + return false; } } /** - * @param callable $callback + * @param callable $callback + * * @throws Exception */ protected function deleteForProjectIds(callable $callback): void @@ -733,7 +743,7 @@ class DeletesV1 extends Worker /** @var string[] $projectIds */ $sum = count($projects); - Console::info('Executing delete function for chunk #' . $chunk . '. Found ' . $sum . ' projects'); + Console::info('Executing delete function for chunk #'.$chunk.'. Found '.$sum.' projects'); foreach ($projects as $project) { $callback($project); $count++; @@ -741,14 +751,15 @@ class DeletesV1 extends Worker } $executionEnd = \microtime(true); - Console::info("Found {$count} projects " . ($executionEnd - $executionStart) . " seconds"); + Console::info("Found {$count} projects ".($executionEnd - $executionStart).' seconds'); } /** - * @param string $collection collectionID - * @param array $queries - * @param Database $database - * @param callable|null $callback + * @param string $collection collectionID + * @param array $queries + * @param Database $database + * @param callable|null $callback + * * @throws Exception */ protected function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null): void @@ -769,7 +780,7 @@ class DeletesV1 extends Worker $sum = count($results); - Console::info('Deleting chunk #' . $chunk . '. Found ' . $sum . ' documents in collection ' . $database->getNamespace() . '_' . $collection); + Console::info('Deleting chunk #'.$chunk.'. Found '.$sum.' documents in collection '.$database->getNamespace().'_'.$collection); foreach ($results as $document) { $this->deleteById($document, $database, $callback); @@ -782,14 +793,14 @@ class DeletesV1 extends Worker $executionEnd = \microtime(true); - Console::info("Deleted {$count} document by group in " . ($executionEnd - $executionStart) . " seconds"); + Console::info("Deleted {$count} document by group in ".($executionEnd - $executionStart).' seconds'); } /** - * @param string $collection collectionID - * @param Query[] $queries - * @param Database $database - * @param callable $callback + * @param string $collection collectionID + * @param Query[] $queries + * @param Database $database + * @param callable $callback */ protected function listByGroup(string $collection, array $queries, Database $database, callable $callback = null): void { @@ -829,11 +840,12 @@ class DeletesV1 extends Worker $executionEnd = \microtime(true); - Console::info("Listed {$count} document by group in " . ($executionEnd - $executionStart) . " seconds"); + Console::info("Listed {$count} document by group in ".($executionEnd - $executionStart).' seconds'); } /** - * @param Document $document certificates document + * @param Document $document certificates document + * * @throws \Utopia\Database\Exception\Authorization */ protected function deleteCertificates(Document $document): void @@ -843,10 +855,10 @@ class DeletesV1 extends Worker // If domain has certificate generated if (isset($document['certificateId'])) { $domainUsingCertificate = $consoleDB->findOne('domains', [ - Query::equal('certificateId', [$document['certificateId']]) + Query::equal('certificateId', [$document['certificateId']]), ]); - if (!$domainUsingCertificate) { + if (! $domainUsingCertificate) { $mainDomain = App::getEnv('_APP_DOMAIN_TARGET', ''); if ($mainDomain === $document->getAttribute('domain')) { $domainUsingCertificate = $mainDomain; @@ -856,13 +868,14 @@ class DeletesV1 extends Worker // If certificate is still used by some domain, mark we can't delete. // Current domain should not be found, because we only have copy. Original domain is already deleted from database. if ($domainUsingCertificate) { - Console::warning("Skipping certificate deletion, because a domain is still using it."); + Console::warning('Skipping certificate deletion, because a domain is still using it.'); + return; } } $domain = $document->getAttribute('domain'); - $directory = APP_STORAGE_CERTIFICATES . '/' . $domain; + $directory = APP_STORAGE_CERTIFICATES.'/'.$domain; $checkTraversal = realpath($directory) === $directory; if ($domain && $checkTraversal && is_dir($directory)) { @@ -872,7 +885,7 @@ class DeletesV1 extends Worker } // Delete files, so Traefik is aware of change - array_map('unlink', glob($directory . '/*.*')); + array_map('unlink', glob($directory.'/*.*')); rmdir($directory); Console::info("Deleted certificate files for {$domain}"); } else { @@ -884,7 +897,7 @@ class DeletesV1 extends Worker { $projectId = $project->getId(); $dbForProject = $this->getProjectDB($project); - $dbForProject->deleteCollection('bucket_' . $document->getInternalId()); + $dbForProject->deleteCollection('bucket_'.$document->getInternalId()); $device = $this->getFilesDevice($projectId); diff --git a/app/workers/functions.php b/app/workers/functions.php index 7dec0ce90c..d5aab70534 100644 --- a/app/workers/functions.php +++ b/app/workers/functions.php @@ -1,11 +1,10 @@ getAttribute('runtime'), $runtimes)) { - throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); + if (! \array_key_exists($function->getAttribute('runtime'), $runtimes)) { + throw new Exception('Runtime "'.$function->getAttribute('runtime', '').'" is not supported'); } $runtime = $runtimes[$function->getAttribute('runtime')]; @@ -109,7 +109,6 @@ Server::setResource('execute', function () { /** * Usage */ - $queueForUsage ->addMetric(METRIC_EXECUTIONS, 1) // per project ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1); // per function @@ -120,6 +119,7 @@ Server::setResource('execute', function () { $vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { $carry[$var->getAttribute('key')] = $var->getAttribute('value'); + return $carry; }, []); @@ -164,7 +164,7 @@ Server::setResource('execute', function () { } catch (\Throwable $th) { $interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt())); $execution - ->setAttribute('duration', (float)$interval->format('%s.%f')) + ->setAttribute('duration', (float) $interval->format('%s.%f')) ->setAttribute('status', 'failed') ->setAttribute('statusCode', $th->getCode()) ->setAttribute('stderr', $th->getMessage()); @@ -195,7 +195,7 @@ Server::setResource('execute', function () { /** Trigger realtime event */ $allEvents = Event::generateEvents('functions.[functionId].executions.[executionId].update', [ 'functionId' => $function->getId(), - 'executionId' => $execution->getId() + 'executionId' => $execution->getId(), ]); $target = Realtime::fromPayload( // Pass first, most verbose event pattern @@ -220,10 +220,9 @@ Server::setResource('execute', function () { /** Trigger usage queue */ $queueForUsage ->setProject($project) - ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000))// per project - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) - ->trigger() - ; + ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int) ($execution->getAttribute('duration') * 1000))// per project + ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int) ($execution->getAttribute('duration') * 1000)) + ->trigger(); }; }); @@ -253,7 +252,7 @@ $server->job() return; } - if (!empty($events)) { + if (! empty($events)) { $limit = 30; $sum = 30; $offset = 0; @@ -262,19 +261,19 @@ $server->job() while ($sum >= $limit) { $functions = $dbForProject->find('functions', [ Query::limit($limit), - Query::offset($offset) + Query::offset($offset), ]); $sum = \count($functions); $offset = $offset + $limit; - Console::log('Fetched ' . $sum . ' functions...'); + Console::log('Fetched '.$sum.' functions...'); foreach ($functions as $function) { - if (!array_intersect($events, $function->getAttribute('events', []))) { + if (! array_intersect($events, $function->getAttribute('events', []))) { continue; } - Console::success('Iterating function: ' . $function->getAttribute('name')); + Console::success('Iterating function: '.$function->getAttribute('name')); try { $execute( log: $log, @@ -291,12 +290,13 @@ $server->job() executionId: null, jwt: null ); - Console::success('Triggered function: ' . $events[0]); + Console::success('Triggered function: '.$events[0]); } catch (\Throwable $th) { - Console::error("Failed to execute " . $function->getId() . " with error: " . $th->getMessage()); + Console::error('Failed to execute '.$function->getId().' with error: '.$th->getMessage()); } } } + return; } diff --git a/app/workers/mails.php b/app/workers/mails.php index e1ce8307ac..d8949c0222 100644 --- a/app/workers/mails.php +++ b/app/workers/mails.php @@ -1,20 +1,20 @@ args['recipient']; $subject = $this->args['subject']; $name = $this->args['name']; @@ -49,7 +49,7 @@ class MailsV1 extends Worker $mail->clearBCCs(); $mail->clearCCs(); - $mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from)); + $mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')) : $from)); $mail->addAddress($recipient, $name); if (isset($smtp['replyTo'])) { $mail->addReplyTo($smtp['replyTo']); @@ -61,7 +61,7 @@ class MailsV1 extends Worker try { $mail->send(); } catch (\Exception $error) { - throw new Exception('Error sending mail: ' . $error->getMessage(), 500); + throw new Exception('Error sending mail: '.$error->getMessage(), 500); } } @@ -77,14 +77,14 @@ class MailsV1 extends Worker $mail->XMailer = 'Appwrite Mailer'; $mail->Host = $smtp['host']; $mail->Port = $smtp['port']; - $mail->SMTPAuth = (!empty($username) && !empty($password)); + $mail->SMTPAuth = (! empty($username) && ! empty($password)); $mail->Username = $username; $mail->Password = $password; $mail->SMTPSecure = $smtp['secure'] === 'tls'; $mail->SMTPAutoTLS = false; $mail->CharSet = 'UTF-8'; - $from = \urldecode($smtp['senderName'] ?? App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')); + $from = \urldecode($smtp['senderName'] ?? App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')); $email = $smtp['senderEmail'] ?? App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); $mail->setFrom($email, $from); diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 84af6fa802..b826dc1c3f 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -2,41 +2,43 @@ use Appwrite\Resque\Worker; use Utopia\CLI\Console; +use Utopia\Messaging\Adapters\Email as EmailAdapter; +use Utopia\Messaging\Adapters\Email\Mailgun; +use Utopia\Messaging\Adapters\Email\SendGrid; +use Utopia\Messaging\Adapters\Push\APNS; +use Utopia\Messaging\Adapters\Push as PushAdapter; +use Utopia\Messaging\Adapters\Push\FCM; use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Adapters\SMS\Msg91; use Utopia\Messaging\Adapters\SMS\Telesign; use Utopia\Messaging\Adapters\SMS\TextMagic; use Utopia\Messaging\Adapters\SMS\Twilio; use Utopia\Messaging\Adapters\SMS\Vonage; -use Utopia\Messaging\Adapters\Push as PushAdapter; -use Utopia\Messaging\Adapters\Push\APNS; -use Utopia\Messaging\Adapters\Push\FCM; -use Utopia\Messaging\Adapters\Email as EmailAdapter; -use Utopia\Messaging\Adapters\Email\Mailgun; -use Utopia\Messaging\Adapters\Email\SendGrid; -require_once __DIR__ . '/../init.php'; +require_once __DIR__.'/../init.php'; Console::title('Messaging V1 Worker'); -Console::success(APP_NAME . ' messaging worker v1 has started' . "\n"); +Console::success(APP_NAME.' messaging worker v1 has started'."\n"); class MessagingV1 extends Worker { protected ?SMSAdapter $sms = null; - protected ?PushAdapter $push = null; - protected ?EmailAdapter $email = null; + protected ?PushAdapter $push = null; + + protected ?EmailAdapter $email = null; protected ?string $from = null; public function getName(): string { - return "mails"; + return 'mails'; } public function sms($record): ?SMSAdapter { $credentials = $record->getAttribute('credentials'); + return match ($record->getAttribute('provider')) { 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), 'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']), @@ -50,6 +52,7 @@ class MessagingV1 extends Worker public function push($record): ?PushAdapter { $credentials = $record->getAttribute('credentials'); + return match ($record->getAttribute('provider')) { 'apns' => new APNS( $credentials['authKey'], @@ -66,6 +69,7 @@ class MessagingV1 extends Worker public function email($record): ?EmailAdapter { $credentials = $record->getAttribute('credentials'); + return match ($record->getAttribute('provider')) { 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain']), 'sendgrid' => new SendGrid($credentials['apiKey']), @@ -92,9 +96,9 @@ class MessagingV1 extends Worker default => null }; - // Query for the provider - // switch on provider name - // call function passing needed credentials returns required provider. + // Query for the provider + // switch on provider name + // call function passing needed credentials returns required provider. $messageId = $this->args['messageId']; $messageRecord = @@ -109,7 +113,6 @@ class MessagingV1 extends Worker default => null }; - $provider->send($message); } @@ -141,7 +144,7 @@ class MessagingV1 extends Worker return [ 'from' => $from, 'to' => $to, - 'body' => $body + 'body' => $body, ]; } @@ -156,7 +159,7 @@ class MessagingV1 extends Worker 'to' => $to, 'title' => $title, 'body' => $body, - 'data' => $data + 'data' => $data, ]; } } diff --git a/app/workers/migrations.php b/app/workers/migrations.php index 0f8194acf8..99529d4fb2 100644 --- a/app/workers/migrations.php +++ b/app/workers/migrations.php @@ -18,10 +18,10 @@ use Utopia\Migration\Sources\NHost; use Utopia\Migration\Sources\Supabase; use Utopia\Migration\Transfer; -require_once __DIR__ . '/../init.php'; +require_once __DIR__.'/../init.php'; Console::title('Migrations V1 Worker'); -Console::success(APP_NAME . ' Migrations worker v1 has started'); +Console::success(APP_NAME.' Migrations worker v1 has started'); class MigrationsV1 extends Worker { diff --git a/app/workers/usage.php b/app/workers/usage.php index 0c9dcbc5aa..3e76d8e8e7 100644 --- a/app/workers/usage.php +++ b/app/workers/usage.php @@ -1,17 +1,17 @@ setNamespace('_' . $projectInternalId); + $dbForProject->setNamespace('_'.$projectInternalId); switch (true) { case $document->getCollection() === 'users': // users $sessions = count($document->getAttribute(METRIC_SESSIONS, 0)); - if (!empty($sessions)) { + if (! empty($sessions)) { $metrics[] = [ 'key' => METRIC_SESSIONS, 'value' => ($sessions * -1), @@ -55,28 +55,28 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools } break; case $document->getCollection() === 'databases': // databases - $collections = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS))); - $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS))); - if (!empty($collections['value'])) { + $collections = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS))); + $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS))); + if (! empty($collections['value'])) { $metrics[] = [ 'key' => METRIC_COLLECTIONS, 'value' => ($collections['value'] * -1), ]; } - if (!empty($documents['value'])) { + if (! empty($documents['value'])) { $metrics[] = [ 'key' => METRIC_DOCUMENTS, 'value' => ($documents['value'] * -1), ]; } break; - case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections + case str_starts_with($document->getCollection(), 'database_') && ! str_contains($document->getCollection(), 'collection'): //collections $parts = explode('_', $document->getCollection()); $databaseInternalId = $parts[1] ?? 0; - $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $document->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS))); + $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $document->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS))); - if (!empty($documents['value'])) { + if (! empty($documents['value'])) { $metrics[] = [ 'key' => METRIC_DOCUMENTS, 'value' => ($documents['value'] * -1), @@ -89,17 +89,17 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools break; case $document->getCollection() === 'buckets': - $files = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES))); - $storage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE))); + $files = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES))); + $storage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE))); - if (!empty($files['value'])) { + if (! empty($files['value'])) { $metrics[] = [ 'key' => METRIC_FILES, 'value' => ($files['value'] * -1), ]; } - if (!empty($storage['value'])) { + if (! empty($storage['value'])) { $metrics[] = [ 'key' => METRIC_FILES_STORAGE, 'value' => ($storage['value'] * -1), @@ -108,57 +108,57 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools break; case $document->getCollection() === 'functions': - $deployments = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS))); - $deploymentsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE))); - $builds = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS))); - $buildsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE))); - $buildsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE))); - $executions = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS))); - $executionsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE))); + $deployments = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS))); + $deploymentsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE))); + $builds = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS))); + $buildsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE))); + $buildsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE))); + $executions = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS))); + $executionsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE))); - if (!empty($deployments['value'])) { + if (! empty($deployments['value'])) { $metrics[] = [ 'key' => METRIC_DEPLOYMENTS, 'value' => ($deployments['value'] * -1), ]; } - if (!empty($deploymentsStorage['value'])) { + if (! empty($deploymentsStorage['value'])) { $metrics[] = [ 'key' => METRIC_DEPLOYMENTS_STORAGE, 'value' => ($deploymentsStorage['value'] * -1), ]; } - if (!empty($builds['value'])) { + if (! empty($builds['value'])) { $metrics[] = [ 'key' => METRIC_BUILDS, 'value' => ($builds['value'] * -1), ]; } - if (!empty($buildsStorage['value'])) { + if (! empty($buildsStorage['value'])) { $metrics[] = [ 'key' => METRIC_BUILDS_STORAGE, 'value' => ($buildsStorage['value'] * -1), ]; } - if (!empty($buildsCompute['value'])) { + if (! empty($buildsCompute['value'])) { $metrics[] = [ 'key' => METRIC_BUILDS_COMPUTE, 'value' => ($buildsCompute['value'] * -1), ]; } - if (!empty($executions['value'])) { + if (! empty($executions['value'])) { $metrics[] = [ 'key' => METRIC_EXECUTIONS, 'value' => ($executions['value'] * -1), ]; } - if (!empty($executionsCompute['value'])) { + if (! empty($executionsCompute['value'])) { $metrics[] = [ 'key' => METRIC_EXECUTIONS_COMPUTE, 'value' => ($executionsCompute['value'] * -1), @@ -169,20 +169,18 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools break; } } catch (\Exception $e) { - console::error("[reducer] " . " {DateTime::now()} " . " {$projectInternalId} " . " {$e->getMessage()}"); + console::error('[reducer] '.' {DateTime::now()} '." {$projectInternalId} "." {$e->getMessage()}"); } finally { $pools->reclaim(); } }; }, ['cache', 'register', 'pools']); - $server->job() ->inject('message') ->inject('reduce') ->action(function (Message $message, callable $reduce) use (&$stats) { - $payload = $message->getPayload() ?? []; $project = new Document($payload['project'] ?? []); $projectId = $project->getInternalId(); @@ -191,18 +189,19 @@ $server->job() continue; } - $reduce( - database: $project->getAttribute('database'), - projectInternalId: $project->getInternalId(), - document: new Document($document), - metrics: $payload['metrics'], - ); + $reduce( + database: $project->getAttribute('database'), + projectInternalId: $project->getInternalId(), + document: new Document($document), + metrics: $payload['metrics'], + ); } $stats[$projectId]['database'] = $project->getAttribute('database'); foreach ($payload['metrics'] ?? [] as $metric) { - if (!isset($stats[$projectId]['keys'][$metric['key']])) { + if (! isset($stats[$projectId]['keys'][$metric['key']])) { $stats[$projectId]['keys'][$metric['key']] = $metric['value']; + continue; } $stats[$projectId]['keys'][$metric['key']] += $metric['value']; @@ -215,8 +214,7 @@ $server ->inject('cache') ->inject('pools') ->action(function ($register, $cache, $pools) use ($periods, &$stats) { - Timer::tick(30000, function () use ($register, $cache, $pools, $periods, &$stats) { - + Timer::tick(30000, function () use ($cache, $pools, $periods, &$stats) { $offset = count($stats); $projects = array_slice($stats, 0, $offset, true); array_splice($stats, 0, $offset); @@ -231,7 +229,7 @@ $server $cache ); - $dbForProject->setNamespace('_' . $projectInternalId); + $dbForProject->setNamespace('_'.$projectInternalId); foreach ($project['keys'] ?? [] as $key => $value) { if ($value == 0) { @@ -270,7 +268,7 @@ $server } } } - if (!empty($project['keys'])) { + if (! empty($project['keys'])) { $dbForProject->createDocument('statsLogger', new Document([ 'time' => DateTime::now(), 'metrics' => $project['keys'], @@ -278,7 +276,7 @@ $server } } catch (\Exception $e) { $now = DateTime::now(); - console::error("[Error] " . " Time: {$now} " . " projectInternalId: {$projectInternalId}" . " File: {$e->getFile()}" . " Line: {$e->getLine()} " . " message: {$e->getMessage()}"); + console::error('[Error] '." Time: {$now} "." projectInternalId: {$projectInternalId}"." File: {$e->getFile()}"." Line: {$e->getLine()} "." message: {$e->getMessage()}"); } finally { $pools->reclaim(); } diff --git a/app/workers/webhooks.php b/app/workers/webhooks.php index 4048581c0c..33fd4e5f6c 100644 --- a/app/workers/webhooks.php +++ b/app/workers/webhooks.php @@ -5,10 +5,10 @@ use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Document; -require_once __DIR__ . '/../init.php'; +require_once __DIR__.'/../init.php'; Console::title('Webhooks V1 Worker'); -Console::success(APP_NAME . ' webhooks worker v1 has started'); +Console::success(APP_NAME.' webhooks worker v1 has started'); class WebhooksV1 extends Worker { @@ -16,7 +16,7 @@ class WebhooksV1 extends Worker public function getName(): string { - return "webhooks"; + return 'webhooks'; } public function init(): void @@ -36,7 +36,7 @@ class WebhooksV1 extends Worker } } - if (!empty($this->errors)) { + if (! empty($this->errors)) { throw new Exception(\implode(" / \n\n", $this->errors)); } } @@ -45,7 +45,7 @@ class WebhooksV1 extends Worker { $url = \rawurldecode($webhook->getAttribute('url')); $signatureKey = $webhook->getAttribute('signatureKey'); - $signature = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $signature = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $httpUser = $webhook->getAttribute('httpUser'); $httpPass = $webhook->getAttribute('httpPass'); $ch = \curl_init($webhook->getAttribute('url')); @@ -64,28 +64,28 @@ class WebhooksV1 extends Worker CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', - 'Content-Length: ' . \strlen($payload), - 'X-' . APP_NAME . '-Webhook-Id: ' . $webhook->getId(), - 'X-' . APP_NAME . '-Webhook-Events: ' . implode(',', $events), - 'X-' . APP_NAME . '-Webhook-Name: ' . $webhook->getAttribute('name', ''), - 'X-' . APP_NAME . '-Webhook-User-Id: ' . $user->getId(), - 'X-' . APP_NAME . '-Webhook-Project-Id: ' . $project->getId(), - 'X-' . APP_NAME . '-Webhook-Signature: ' . $signature, + 'Content-Length: '.\strlen($payload), + 'X-'.APP_NAME.'-Webhook-Id: '.$webhook->getId(), + 'X-'.APP_NAME.'-Webhook-Events: '.implode(',', $events), + 'X-'.APP_NAME.'-Webhook-Name: '.$webhook->getAttribute('name', ''), + 'X-'.APP_NAME.'-Webhook-User-Id: '.$user->getId(), + 'X-'.APP_NAME.'-Webhook-Project-Id: '.$project->getId(), + 'X-'.APP_NAME.'-Webhook-Signature: '.$signature, ] ); - if (!$webhook->getAttribute('security', true)) { + if (! $webhook->getAttribute('security', true)) { \curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); \curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - if (!empty($httpUser) && !empty($httpPass)) { + if (! empty($httpUser) && ! empty($httpPass)) { \curl_setopt($ch, CURLOPT_USERPWD, "$httpUser:$httpPass"); \curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } if (false === \curl_exec($ch)) { - $this->errors[] = \curl_error($ch) . ' in events ' . implode(', ', $events) . ' for webhook ' . $webhook->getAttribute('name'); + $this->errors[] = \curl_error($ch).' in events '.implode(', ', $events).' for webhook '.$webhook->getAttribute('name'); } \curl_close($ch); diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index e97c271ae2..98a0cf27d8 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -9,8 +9,8 @@ use Appwrite\Auth\Hash\Phpass; use Appwrite\Auth\Hash\Scrypt; use Appwrite\Auth\Hash\Scryptmodified; use Appwrite\Auth\Hash\Sha; -use Utopia\Database\Document; use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Roles; @@ -25,49 +25,69 @@ class Auth 'phpass', 'scrypt', 'scryptMod', - 'plaintext' + 'plaintext', ]; public const DEFAULT_ALGO = 'argon2'; + public const DEFAULT_ALGO_OPTIONS = ['type' => 'argon2', 'memoryCost' => 2048, 'timeCost' => 4, 'threads' => 3]; /** * User Roles. */ public const USER_ROLE_ANY = 'any'; + public const USER_ROLE_GUESTS = 'guests'; + public const USER_ROLE_USERS = 'users'; + public const USER_ROLE_ADMIN = 'admin'; + public const USER_ROLE_DEVELOPER = 'developer'; + public const USER_ROLE_OWNER = 'owner'; + public const USER_ROLE_APPS = 'apps'; + public const USER_ROLE_SYSTEM = 'system'; /** * Token Types. */ public const TOKEN_TYPE_LOGIN = 1; // Deprecated + public const TOKEN_TYPE_VERIFICATION = 2; + public const TOKEN_TYPE_RECOVERY = 3; + public const TOKEN_TYPE_INVITE = 4; + public const TOKEN_TYPE_MAGIC_URL = 5; + public const TOKEN_TYPE_PHONE = 6; /** * Session Providers. */ public const SESSION_PROVIDER_EMAIL = 'email'; + public const SESSION_PROVIDER_ANONYMOUS = 'anonymous'; + public const SESSION_PROVIDER_MAGIC_URL = 'magic-url'; + public const SESSION_PROVIDER_PHONE = 'phone'; /** * Token Expiration times. */ public const TOKEN_EXPIRATION_LOGIN_LONG = 31536000; /* 1 year */ + public const TOKEN_EXPIRATION_LOGIN_SHORT = 3600; /* 1 hour */ + public const TOKEN_EXPIRATION_RECOVERY = 3600; /* 1 hour */ + public const TOKEN_EXPIRATION_CONFIRM = 3600 * 24 * 7; /* 7 days */ + public const TOKEN_EXPIRATION_PHONE = 60 * 15; /* 15 minutes */ /** @@ -93,7 +113,6 @@ class Auth * Set Cookie Name. * * @param $string - * * @return string */ public static function setCookieName($string) @@ -104,9 +123,8 @@ class Auth /** * Encode Session. * - * @param string $id - * @param string $secret - * + * @param string $id + * @param string $secret * @return string */ public static function encodeSession($id, $secret) @@ -120,8 +138,7 @@ class Auth /** * Decode Session. * - * @param string $session - * + * @param string $session * @return array * * @throws \Exception @@ -131,7 +148,7 @@ class Auth $session = \json_decode(\base64_decode($session), true); $default = ['id' => null, 'secret' => '']; - if (!\is_array($session)) { + if (! \is_array($session)) { return $default; } @@ -144,7 +161,6 @@ class Auth * One-way encryption * * @param $string - * * @return string */ public static function hash(string $string) @@ -157,10 +173,9 @@ class Auth * * One way string hashing for user passwords * - * @param string $string - * @param string $algo hashing algorithm to use - * @param array $options algo-specific options - * + * @param string $string + * @param string $algo hashing algorithm to use + * @param array $options algo-specific options * @return bool|string|null */ public static function passwordHash(string $string, string $algo, array $options = []) @@ -171,45 +186,51 @@ class Auth $options = Auth::DEFAULT_ALGO_OPTIONS; } - if (!\in_array($algo, Auth::SUPPORTED_ALGOS)) { - throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.'); + if (! \in_array($algo, Auth::SUPPORTED_ALGOS)) { + throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.'); } switch ($algo) { case 'argon2': $hasher = new Argon2($options); + return $hasher->hash($string); case 'bcrypt': $hasher = new Bcrypt($options); + return $hasher->hash($string); case 'md5': $hasher = new Md5($options); + return $hasher->hash($string); case 'sha': $hasher = new Sha($options); + return $hasher->hash($string); case 'phpass': $hasher = new Phpass($options); + return $hasher->hash($string); case 'scrypt': $hasher = new Scrypt($options); + return $hasher->hash($string); case 'scryptMod': $hasher = new Scryptmodified($options); + return $hasher->hash($string); default: - throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.'); + throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.'); } } /** * Password verify. * - * @param string $plain - * @param string $hash - * @param string $algo hashing algorithm used to hash - * @param array $options algo-specific options - * + * @param string $plain + * @param string $hash + * @param string $algo hashing algorithm used to hash + * @param array $options algo-specific options * @return bool */ public static function passwordVerify(string $plain, string $hash, string $algo, array $options = []) @@ -220,34 +241,41 @@ class Auth $options = Auth::DEFAULT_ALGO_OPTIONS; } - if (!\in_array($algo, Auth::SUPPORTED_ALGOS)) { - throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.'); + if (! \in_array($algo, Auth::SUPPORTED_ALGOS)) { + throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.'); } switch ($algo) { case 'argon2': $hasher = new Argon2($options); + return $hasher->verify($plain, $hash); case 'bcrypt': $hasher = new Bcrypt($options); + return $hasher->verify($plain, $hash); case 'md5': $hasher = new Md5($options); + return $hasher->verify($plain, $hash); case 'sha': $hasher = new Sha($options); + return $hasher->verify($plain, $hash); case 'phpass': $hasher = new Phpass($options); + return $hasher->verify($plain, $hash); case 'scrypt': $hasher = new Scrypt($options); + return $hasher->verify($plain, $hash); case 'scryptMod': $hasher = new Scryptmodified($options); + return $hasher->verify($plain, $hash); default: - throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.'); + throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.'); } } @@ -256,8 +284,7 @@ class Auth * * Generate random password string * - * @param int $length - * + * @param int $length * @return string */ public static function passwordGenerator(int $length = 20): string @@ -270,8 +297,7 @@ class Auth * * Generate random password string * - * @param int $length - * + * @param int $length * @return string */ public static function tokenGenerator(int $length = 128): string @@ -284,8 +310,7 @@ class Auth * * Generate random code string * - * @param int $length - * + * @param int $length * @return string */ public static function codeGenerator(int $length = 6): string @@ -302,10 +327,9 @@ class Auth /** * Verify token and check that its not expired. * - * @param array $tokens - * @param int $type - * @param string $secret - * + * @param array $tokens + * @param int $type + * @param string $secret * @return bool|string */ public static function tokenVerify(array $tokens, int $type, string $secret) @@ -320,7 +344,7 @@ class Auth $token->getAttribute('secret') === self::hash($secret) && DateTime::formatTz($token->getAttribute('expire')) >= DateTime::formatTz(DateTime::now()) ) { - return (string)$token->getId(); + return (string) $token->getId(); } } @@ -349,10 +373,9 @@ class Auth /** * Verify session and check that its not expired. * - * @param array $sessions - * @param string $secret - * @param string $expires - * + * @param array $sessions + * @param string $secret + * @param string $expires * @return bool|string */ public static function sessionVerify(array $sessions, string $secret, int $expires) @@ -375,8 +398,7 @@ class Auth /** * Is Privileged User? * - * @param array $roles - * + * @param array $roles * @return bool */ public static function isPrivilegedUser(array $roles): bool @@ -395,8 +417,7 @@ class Auth /** * Is App User? * - * @param array $roles - * + * @param array $roles * @return bool */ public static function isAppUser(array $roles): bool @@ -411,14 +432,14 @@ class Auth /** * Returns all roles for a user. * - * @param Document $user + * @param Document $user * @return array */ public static function getRoles(Document $user): array { $roles = []; - if (!self::isPrivilegedUser(Authorization::getRoles()) && !self::isAppUser(Authorization::getRoles())) { + if (! self::isPrivilegedUser(Authorization::getRoles()) && ! self::isAppUser(Authorization::getRoles())) { if ($user->getId()) { $roles[] = Role::user($user->getId())->toString(); $roles[] = Role::users()->toString(); @@ -439,7 +460,7 @@ class Auth } foreach ($user->getAttribute('memberships', []) as $node) { - if (!isset($node['confirm']) || !$node['confirm']) { + if (! isset($node['confirm']) || ! $node['confirm']) { continue; } @@ -456,7 +477,7 @@ class Auth } foreach ($user->getAttribute('labels', []) as $label) { - $roles[] = 'label:' . $label; + $roles[] = 'label:'.$label; } return $roles; diff --git a/src/Appwrite/Auth/Hash.php b/src/Appwrite/Auth/Hash.php index 7134057581..caf4771fcd 100644 --- a/src/Appwrite/Auth/Hash.php +++ b/src/Appwrite/Auth/Hash.php @@ -5,13 +5,13 @@ namespace Appwrite\Auth; abstract class Hash { /** - * @var array $options Hashing-algo specific options - */ + * @var array Hashing-algo specific options + */ protected array $options = []; /** - * @param array $options Hashing-algo specific options - */ + * @param array $options Hashing-algo specific options + */ public function __construct(array $options = []) { $this->setOptions($options); @@ -20,11 +20,12 @@ abstract class Hash /** * Set hashing algo options * - * @param array $options Hashing-algo specific options - */ + * @param array $options Hashing-algo specific options + */ public function setOptions(array $options): self { $this->options = \array_merge([], $this->getDefaultOptions(), $options); + return $this; } @@ -32,24 +33,22 @@ abstract class Hash * Get hashing algo options * * @return array $options Hashing-algo specific options - */ + */ public function getOptions(): array { return $this->options; } /** - * @param string $password Input password to hash - * + * @param string $password Input password to hash * @return string hash */ abstract public function hash(string $password): string; /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * - * @return boolean true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * @return bool true if password matches hash */ abstract public function verify(string $password, string $hash): bool; diff --git a/src/Appwrite/Auth/Hash/Argon2.php b/src/Appwrite/Auth/Hash/Argon2.php index c723b077b1..0e9c2fcf36 100644 --- a/src/Appwrite/Auth/Hash/Argon2.php +++ b/src/Appwrite/Auth/Hash/Argon2.php @@ -15,8 +15,7 @@ use Appwrite\Auth\Hash; class Argon2 extends Hash { /** - * @param string $password Input password to hash - * + * @param string $password Input password to hash * @return string hash */ public function hash(string $password): string @@ -25,10 +24,9 @@ class Argon2 extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * - * @return boolean true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * @return bool true if password matches hash */ public function verify(string $password, string $hash): bool { diff --git a/src/Appwrite/Auth/Hash/Bcrypt.php b/src/Appwrite/Auth/Hash/Bcrypt.php index 8b6177f33a..c54cf3d452 100644 --- a/src/Appwrite/Auth/Hash/Bcrypt.php +++ b/src/Appwrite/Auth/Hash/Bcrypt.php @@ -14,8 +14,7 @@ use Appwrite\Auth\Hash; class Bcrypt extends Hash { /** - * @param string $password Input password to hash - * + * @param string $password Input password to hash * @return string hash */ public function hash(string $password): string @@ -24,10 +23,9 @@ class Bcrypt extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * - * @return boolean true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * @return bool true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -41,6 +39,6 @@ class Bcrypt extends Hash */ public function getDefaultOptions(): array { - return [ 'cost' => 8 ]; + return ['cost' => 8]; } } diff --git a/src/Appwrite/Auth/Hash/Md5.php b/src/Appwrite/Auth/Hash/Md5.php index 8ade3dd5e2..0f6fe5c30d 100644 --- a/src/Appwrite/Auth/Hash/Md5.php +++ b/src/Appwrite/Auth/Hash/Md5.php @@ -12,8 +12,7 @@ use Appwrite\Auth\Hash; class Md5 extends Hash { /** - * @param string $password Input password to hash - * + * @param string $password Input password to hash * @return string hash */ public function hash(string $password): string @@ -22,10 +21,9 @@ class Md5 extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * - * @return boolean true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * @return bool true if password matches hash */ public function verify(string $password, string $hash): bool { diff --git a/src/Appwrite/Auth/Hash/Phpass.php b/src/Appwrite/Auth/Hash/Phpass.php index 187e4a27a6..ded4e407ff 100644 --- a/src/Appwrite/Auth/Hash/Phpass.php +++ b/src/Appwrite/Auth/Hash/Phpass.php @@ -39,6 +39,7 @@ class Phpass extends Hash * Alphabet used in itoa64 conversions. * * @var string + * * @since 0.1.0 */ protected string $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; @@ -59,8 +60,7 @@ class Phpass extends Hash } /** - * @param string $password Input password to hash - * + * @param string $password Input password to hash * @return string hash */ public function hash(string $password): string @@ -68,7 +68,7 @@ class Phpass extends Hash $options = $this->getDefaultOptions(); $random = ''; - if (CRYPT_BLOWFISH === 1 && !$options['portable_hashes']) { + if (CRYPT_BLOWFISH === 1 && ! $options['portable_hashes']) { $random = $this->getRandomBytes(16, $options); $hash = crypt($password, $this->gensaltBlowfish($random, $options)); if (strlen($hash) === 60) { @@ -92,10 +92,9 @@ class Phpass extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * - * @return boolean true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * @return bool true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -114,15 +113,16 @@ class Phpass extends Hash } /** - * @param int $count + * @param int $count + * @return string $output * - * @return String $output * @since 0.1.0 + * * @throws Exception Thows an Exception if the $count parameter is not a positive integer. */ protected function getRandomBytes(int $count, array $options): string { - if (!is_int($count) || $count < 1) { + if (! is_int($count) || $count < 1) { throw new \Exception('Argument count must be a positive integer'); } $output = ''; @@ -135,7 +135,7 @@ class Phpass extends Hash $output = ''; for ($i = 0; $i < $count; $i += 16) { - $options['iteration_count_log2'] = md5(microtime() . $options['iteration_count_log2']); + $options['iteration_count_log2'] = md5(microtime().$options['iteration_count_log2']); $output .= md5($options['iteration_count_log2'], true); } @@ -146,47 +146,48 @@ class Phpass extends Hash } /** - * @param String $input - * @param int $count + * @param string $input + * @param int $count + * @return string $output * - * @return String $output * @since 0.1.0 + * * @throws Exception Thows an Exception if the $count parameter is not a positive integer. */ protected function encode64($input, $count) { - if (!is_int($count) || $count < 1) { + if (! is_int($count) || $count < 1) { throw new \Exception('Argument count must be a positive integer'); } $output = ''; $i = 0; do { $value = ord($input[$i++]); - $output .= $this->itoa64[$value & 0x3f]; + $output .= $this->itoa64[$value & 0x3F]; if ($i < $count) { $value |= ord($input[$i]) << 8; } - $output .= $this->itoa64[($value >> 6) & 0x3f]; + $output .= $this->itoa64[($value >> 6) & 0x3F]; if ($i++ >= $count) { break; } if ($i < $count) { $value |= ord($input[$i]) << 16; } - $output .= $this->itoa64[($value >> 12) & 0x3f]; + $output .= $this->itoa64[($value >> 12) & 0x3F]; if ($i++ >= $count) { break; } - $output .= $this->itoa64[($value >> 18) & 0x3f]; + $output .= $this->itoa64[($value >> 18) & 0x3F]; } while ($i < $count); return $output; } /** - * @param String $input + * @param string $input + * @return string $output * - * @return String $output * @since 0.1.0 */ private function gensaltPrivate($input, $options) @@ -199,10 +200,10 @@ class Phpass extends Hash } /** - * @param String $password - * @param String $setting + * @param string $password + * @param string $setting + * @return string $output * - * @return String $output * @since 0.1.0 */ private function cryptPrivate($password, $setting) @@ -233,9 +234,9 @@ class Phpass extends Hash * consequently in lower iteration counts and hashes that are * quicker to crack (by non-PHP code). */ - $hash = md5($salt . $password, true); + $hash = md5($salt.$password, true); do { - $hash = md5($hash . $password, true); + $hash = md5($hash.$password, true); } while (--$count); $output = substr($setting, 0, 12); $output .= $this->encode64($hash, 16); @@ -244,9 +245,9 @@ class Phpass extends Hash } /** - * @param String $input + * @param string $input + * @return string $output * - * @return String $output * @since 0.1.0 */ private function gensaltBlowfish($input, $options) @@ -278,11 +279,11 @@ class Phpass extends Hash $c2 = ord($input[$i++]); $c1 |= $c2 >> 4; $output .= $itoa64[$c1]; - $c1 = ($c2 & 0x0f) << 2; + $c1 = ($c2 & 0x0F) << 2; $c2 = ord($input[$i++]); $c1 |= $c2 >> 6; $output .= $itoa64[$c1]; - $output .= $itoa64[$c2 & 0x3f]; + $output .= $itoa64[$c2 & 0x3F]; } while (1); return $output; diff --git a/src/Appwrite/Auth/Hash/Scrypt.php b/src/Appwrite/Auth/Hash/Scrypt.php index 821b1fba69..8c50c16341 100644 --- a/src/Appwrite/Auth/Hash/Scrypt.php +++ b/src/Appwrite/Auth/Hash/Scrypt.php @@ -17,8 +17,7 @@ use Appwrite\Auth\Hash; class Scrypt extends Hash { /** - * @param string $password Input password to hash - * + * @param string $password Input password to hash * @return string hash */ public function hash(string $password): string @@ -29,10 +28,9 @@ class Scrypt extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * - * @return boolean true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * @return bool true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -46,6 +44,6 @@ class Scrypt extends Hash */ public function getDefaultOptions(): array { - return [ 'costCpu' => 8, 'costMemory' => 14, 'costParallel' => 1, 'length' => 64 ]; + return ['costCpu' => 8, 'costMemory' => 14, 'costParallel' => 1, 'length' => 64]; } } diff --git a/src/Appwrite/Auth/Hash/Scryptmodified.php b/src/Appwrite/Auth/Hash/Scryptmodified.php index 2d1cd4f165..9260913aed 100644 --- a/src/Appwrite/Auth/Hash/Scryptmodified.php +++ b/src/Appwrite/Auth/Hash/Scryptmodified.php @@ -16,8 +16,7 @@ use Appwrite\Auth\Hash; class Scryptmodified extends Hash { /** - * @param string $password Input password to hash - * + * @param string $password Input password to hash * @return string hash */ public function hash(string $password): string @@ -33,10 +32,9 @@ class Scryptmodified extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * - * @return boolean true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * @return bool true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -50,7 +48,7 @@ class Scryptmodified extends Hash */ public function getDefaultOptions(): array { - return [ ]; + return []; } private function generateDerivedKey(string $password) @@ -60,7 +58,7 @@ class Scryptmodified extends Hash $saltBytes = \base64_decode($options['salt']); $saltSeparatorBytes = \base64_decode($options['saltSeparator']); - $derivedKey = \scrypt(\utf8_encode($password), $saltBytes . $saltSeparatorBytes, 16384, 8, 1, 64); + $derivedKey = \scrypt(\utf8_encode($password), $saltBytes.$saltSeparatorBytes, 16384, 8, 1, 64); $derivedKey = \hex2bin($derivedKey); return $derivedKey; diff --git a/src/Appwrite/Auth/Hash/Sha.php b/src/Appwrite/Auth/Hash/Sha.php index c2ae3b52c1..331c4fe6f2 100644 --- a/src/Appwrite/Auth/Hash/Sha.php +++ b/src/Appwrite/Auth/Hash/Sha.php @@ -16,8 +16,7 @@ use Appwrite\Auth\Hash; class Sha extends Hash { /** - * @param string $password Input password to hash - * + * @param string $password Input password to hash * @return string hash */ public function hash(string $password): string @@ -28,10 +27,9 @@ class Sha extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * - * @return boolean true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * @return bool true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -45,6 +43,6 @@ class Sha extends Hash */ public function getDefaultOptions(): array { - return [ 'version' => 'sha3-512' ]; + return ['version' => 'sha3-512']; } } diff --git a/src/Appwrite/Auth/OAuth2.php b/src/Appwrite/Auth/OAuth2.php index c737e183f8..37f6416fb5 100644 --- a/src/Appwrite/Auth/OAuth2.php +++ b/src/Appwrite/Auth/OAuth2.php @@ -34,11 +34,11 @@ abstract class OAuth2 /** * OAuth2 constructor. * - * @param string $appId - * @param string $appSecret - * @param string $callback - * @param array $state - * @param array $scopes + * @param string $appId + * @param string $appSecret + * @param string $callback + * @param array $state + * @param array $scopes */ public function __construct(string $appId, string $appSecret, string $callback, array $state = [], array $scopes = []) { @@ -62,29 +62,25 @@ abstract class OAuth2 abstract public function getLoginURL(): string; /** - * @param string $code - * + * @param string $code * @return array */ abstract protected function getTokens(string $code): array; /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ abstract public function refreshTokens(string $refreshToken): array; /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ abstract public function getUserID(string $accessToken): string; /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ abstract public function getUserEmail(string $accessToken): string; @@ -92,28 +88,25 @@ abstract class OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ abstract public function isEmailVerified(string $accessToken): bool; /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ abstract public function getUserName(string $accessToken): string; /** * @param $scope - * * @return $this */ protected function addScope(string $scope): OAuth2 { // Add a scope to the scopes array if it isn't already present - if (!\in_array($scope, $this->scopes)) { + if (! \in_array($scope, $this->scopes)) { $this->scopes[] = $scope; } @@ -129,8 +122,7 @@ abstract class OAuth2 } /** - * @param string $code - * + * @param string $code * @return string */ public function getAccessToken(string $code): string @@ -141,8 +133,7 @@ abstract class OAuth2 } /** - * @param string $code - * + * @param string $code * @return string */ public function getRefreshToken(string $code): string @@ -153,8 +144,7 @@ abstract class OAuth2 } /** - * @param string $code - * + * @param string $code * @return string */ public function getAccessTokenExpiry(string $code): int @@ -169,7 +159,6 @@ abstract class OAuth2 // json_decoding /** * @param $state - * * @return array */ public function parseState(string $state) @@ -178,11 +167,10 @@ abstract class OAuth2 } /** - * @param string $method - * @param string $url - * @param array $headers - * @param string $payload - * + * @param string $method + * @param string $url + * @param array $headers + * @param string $payload * @return string */ protected function request(string $method, string $url = '', array $headers = [], string $payload = ''): string @@ -194,11 +182,11 @@ abstract class OAuth2 \curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); \curl_setopt($ch, CURLOPT_USERAGENT, 'Appwrite OAuth2'); - if (!empty($payload)) { + if (! empty($payload)) { \curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); } - $headers[] = 'Content-length: ' . \strlen($payload); + $headers[] = 'Content-length: '.\strlen($payload); \curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // Send the request & save response to $response @@ -212,6 +200,6 @@ abstract class OAuth2 throw new Exception($response, $code); } - return (string)$response; + return (string) $response; } } diff --git a/src/Appwrite/Auth/OAuth2/Amazon.php b/src/Appwrite/Auth/OAuth2/Amazon.php index d1d2cb5a38..c2cdedf2f1 100644 --- a/src/Appwrite/Auth/OAuth2/Amazon.php +++ b/src/Appwrite/Auth/OAuth2/Amazon.php @@ -25,7 +25,7 @@ class Amazon extends OAuth2 * @var array */ protected array $scopes = [ - "profile" + 'profile', ]; /** @@ -37,8 +37,7 @@ class Amazon extends OAuth2 } /** - * @param string $state - * + * @param string $state * @return array */ public function parseState(string $state) @@ -46,24 +45,22 @@ class Amazon extends OAuth2 return \json_decode(\html_entity_decode($state), true); } - /** * @return string */ public function getLoginURL(): string { - return 'https://www.amazon.com/ap/oa?' . \http_build_query([ + return 'https://www.amazon.com/ap/oa?'.\http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state), - 'redirect_uri' => $this->callback + 'redirect_uri' => $this->callback, ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -79,7 +76,7 @@ class Amazon extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'redirect_uri' => $this->callback, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -88,8 +85,7 @@ class Amazon extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -103,7 +99,7 @@ class Amazon extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken + 'refresh_token' => $refreshToken, ]) ), true); @@ -115,8 +111,7 @@ class Amazon extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -127,8 +122,7 @@ class Amazon extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -143,20 +137,18 @@ class Amazon extends OAuth2 * * If present, the email is verified. This was verfied through a manual Amazon sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -167,16 +159,16 @@ class Amazon extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token=' . \urlencode($accessToken)); + $user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token='.\urlencode($accessToken)); $this->user = \json_decode($user, true); } + return $this->user; } } diff --git a/src/Appwrite/Auth/OAuth2/Apple.php b/src/Appwrite/Auth/OAuth2/Apple.php index 2abf61c947..27f41543ae 100644 --- a/src/Appwrite/Auth/OAuth2/Apple.php +++ b/src/Appwrite/Auth/OAuth2/Apple.php @@ -24,8 +24,8 @@ class Apple extends OAuth2 * @var array */ protected array $scopes = [ - "name", - "email" + 'name', + 'email', ]; /** @@ -46,19 +46,18 @@ class Apple extends OAuth2 */ public function getLoginURL(): string { - return 'https://appleid.apple.com/auth/authorize?' . \http_build_query([ + return 'https://appleid.apple.com/auth/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'response_type' => 'code', 'response_mode' => 'form_post', - 'scope' => \implode(' ', $this->getScopes()) + 'scope' => \implode(' ', $this->getScopes()), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -86,8 +85,7 @@ class Apple extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -116,8 +114,7 @@ class Apple extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -126,8 +123,7 @@ class Apple extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -140,8 +136,7 @@ class Apple extends OAuth2 * * @link https://developer.apple.com/forums/thread/121411 * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -154,15 +149,14 @@ class Apple extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string { if ( isset($this->claims['email']) && - !empty($this->claims['email']) && + ! empty($this->claims['email']) && isset($this->claims['email_verified']) && $this->claims['email_verified'] === 'true' ) { @@ -183,7 +177,7 @@ class Apple extends OAuth2 $keyfile = (isset($secret['p8'])) ? $secret['p8'] : ''; // Your p8 Key file $keyID = (isset($secret['keyID'])) ? $secret['keyID'] : ''; // Your Key ID $teamID = (isset($secret['teamID'])) ? $secret['teamID'] : ''; // Your Team ID (see Developer Portal) - $bundleID = $this->appID; // Your Bundle ID + $bundleID = $this->appID; // Your Bundle ID $headers = [ 'alg' => 'ES256', @@ -200,22 +194,21 @@ class Apple extends OAuth2 $pkey = \openssl_pkey_get_private($keyfile); - $payload = $this->encode(\json_encode($headers)) . '.' . $this->encode(\json_encode($claims)); + $payload = $this->encode(\json_encode($headers)).'.'.$this->encode(\json_encode($claims)); $signature = ''; $success = \openssl_sign($payload, $signature, $pkey, OPENSSL_ALGO_SHA256); - if (!$success) { + if (! $success) { return ''; } - return $payload . '.' . $this->encode($this->fromDER($signature, 64)); + return $payload.'.'.$this->encode($this->fromDER($signature, 64)); } /** - * @param string $data - * + * @param string $data * @return string */ protected function encode($data): string @@ -224,7 +217,7 @@ class Apple extends OAuth2 } /** - * @param string $data + * @param string $data */ protected function retrievePositiveInteger(string $data): string { @@ -236,8 +229,8 @@ class Apple extends OAuth2 } /** - * @param string $der - * @param int $partLength + * @param string $der + * @param int $partLength */ protected function fromDER(string $der, int $partLength): string { @@ -270,6 +263,6 @@ class Apple extends OAuth2 $S = $this->retrievePositiveInteger(\mb_substr($hex, 4, $Sl * 2, '8bit')); $S = \str_pad($S, $partLength, '0', STR_PAD_LEFT); - return \pack('H*', $R . $S); + return \pack('H*', $R.$S); } } diff --git a/src/Appwrite/Auth/OAuth2/Auth0.php b/src/Appwrite/Auth/OAuth2/Auth0.php index eba7d18b5f..e2615017bd 100644 --- a/src/Appwrite/Auth/OAuth2/Auth0.php +++ b/src/Appwrite/Auth/OAuth2/Auth0.php @@ -16,7 +16,7 @@ class Auth0 extends OAuth2 'openid', 'profile', 'email', - 'offline_access' + 'offline_access', ]; /** @@ -42,18 +42,17 @@ class Auth0 extends OAuth2 */ public function getLoginURL(): string { - return 'https://' . $this->getAuth0Domain() . '/authorize?' . \http_build_query([ + return 'https://'.$this->getAuth0Domain().'/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), - 'response_type' => 'code' + 'response_type' => 'code', ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -62,7 +61,7 @@ class Auth0 extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://' . $this->getAuth0Domain() . '/oauth/token', + 'https://'.$this->getAuth0Domain().'/oauth/token', $headers, \http_build_query([ 'code' => $code, @@ -70,7 +69,7 @@ class Auth0 extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -78,10 +77,8 @@ class Auth0 extends OAuth2 return $this->tokens; } - /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -89,13 +86,13 @@ class Auth0 extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://' . $this->getAuth0Domain() . '/oauth/token', + 'https://'.$this->getAuth0Domain().'/oauth/token', $headers, \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -107,8 +104,7 @@ class Auth0 extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -119,8 +115,7 @@ class Auth0 extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -135,8 +130,7 @@ class Auth0 extends OAuth2 * * @link https://auth0.com/docs/api/authentication?javascript#user-profile * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -151,8 +145,7 @@ class Auth0 extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -163,15 +156,14 @@ class Auth0 extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; - $user = $this->request('GET', 'https://' . $this->getAuth0Domain() . '/userinfo', $headers); + $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; + $user = $this->request('GET', 'https://'.$this->getAuth0Domain().'/userinfo', $headers); $this->user = \json_decode($user, true); } @@ -214,6 +206,7 @@ class Auth0 extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } + return $secret; } } diff --git a/src/Appwrite/Auth/OAuth2/Authentik.php b/src/Appwrite/Auth/OAuth2/Authentik.php index 16822e2c9f..8a6b13cdef 100644 --- a/src/Appwrite/Auth/OAuth2/Authentik.php +++ b/src/Appwrite/Auth/OAuth2/Authentik.php @@ -16,7 +16,7 @@ class Authentik extends OAuth2 'openid', 'profile', 'email', - 'offline_access' + 'offline_access', ]; /** @@ -42,18 +42,17 @@ class Authentik extends OAuth2 */ public function getLoginURL(): string { - return 'https://' . $this->getAuthentikDomain() . '/application/o/authorize?' . \http_build_query([ + return 'https://'.$this->getAuthentikDomain().'/application/o/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), - 'response_type' => 'code' + 'response_type' => 'code', ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -62,7 +61,7 @@ class Authentik extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://' . $this->getAuthentikDomain() . '/application/o/token/', + 'https://'.$this->getAuthentikDomain().'/application/o/token/', $headers, \http_build_query([ 'code' => $code, @@ -70,17 +69,16 @@ class Authentik extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } + return $this->tokens; } - /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -88,13 +86,13 @@ class Authentik extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://' . $this->getAuthentikDomain() . '/application/o/token/', + 'https://'.$this->getAuthentikDomain().'/application/o/token/', $headers, \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -106,8 +104,7 @@ class Authentik extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -122,8 +119,7 @@ class Authentik extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -140,8 +136,7 @@ class Authentik extends OAuth2 /** * Check if the User email is verified * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -156,8 +151,7 @@ class Authentik extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -171,16 +165,15 @@ class Authentik extends OAuth2 return ''; } - /** - * @param string $accessToken - * + /** + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; - $user = $this->request('GET', 'https://' . $this->getAuthentikDomain() . '/application/o/userinfo/', $headers); + $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; + $user = $this->request('GET', 'https://'.$this->getAuthentikDomain().'/application/o/userinfo/', $headers); $this->user = \json_decode($user, true); } @@ -199,7 +192,7 @@ class Authentik extends OAuth2 return $secret['clientSecret'] ?? ''; } - /** + /** * Extracts the authentik Domain from the JSON stored in appSecret * * @return string @@ -207,6 +200,7 @@ class Authentik extends OAuth2 protected function getAuthentikDomain(): string { $secret = $this->getAppSecret(); + return $secret['authentikDomain'] ?? ''; } @@ -222,6 +216,7 @@ class Authentik extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } + return $secret; } } diff --git a/src/Appwrite/Auth/OAuth2/Autodesk.php b/src/Appwrite/Auth/OAuth2/Autodesk.php index 0b268ead3b..071eee7dcb 100644 --- a/src/Appwrite/Auth/OAuth2/Autodesk.php +++ b/src/Appwrite/Auth/OAuth2/Autodesk.php @@ -36,18 +36,17 @@ class Autodesk extends OAuth2 */ public function getLoginURL(): string { - return 'https://developer.api.autodesk.com/authentication/v1/authorize?' . \http_build_query([ + return 'https://developer.api.autodesk.com/authentication/v1/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state), 'redirect_uri' => $this->callback, - 'response_type' => 'code' + 'response_type' => 'code', ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -63,7 +62,7 @@ class Autodesk extends OAuth2 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, 'code' => $code, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ); @@ -74,8 +73,7 @@ class Autodesk extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -105,8 +103,7 @@ class Autodesk extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -117,8 +114,7 @@ class Autodesk extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -133,8 +129,7 @@ class Autodesk extends OAuth2 * * @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -149,8 +144,7 @@ class Autodesk extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -161,14 +155,13 @@ class Autodesk extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; $user = $this->request('GET', 'https://developer.api.autodesk.com/userprofile/v1/users/@me', $headers); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Bitbucket.php b/src/Appwrite/Auth/OAuth2/Bitbucket.php index 361bc22b65..eea5af4c1b 100644 --- a/src/Appwrite/Auth/OAuth2/Bitbucket.php +++ b/src/Appwrite/Auth/OAuth2/Bitbucket.php @@ -37,7 +37,7 @@ class Bitbucket extends OAuth2 */ public function getLoginURL(): string { - return 'https://bitbucket.org/site/oauth2/authorize?' . \http_build_query([ + return 'https://bitbucket.org/site/oauth2/authorize?'.\http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), @@ -46,8 +46,7 @@ class Bitbucket extends OAuth2 } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -63,7 +62,7 @@ class Bitbucket extends OAuth2 'code' => $code, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -72,8 +71,7 @@ class Bitbucket extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -87,7 +85,7 @@ class Bitbucket extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken + 'refresh_token' => $refreshToken, ]) ), true); @@ -99,8 +97,7 @@ class Bitbucket extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -111,8 +108,7 @@ class Bitbucket extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -125,8 +121,7 @@ class Bitbucket extends OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -141,8 +136,7 @@ class Bitbucket extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -153,17 +147,16 @@ class Bitbucket extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token=' . \urlencode($accessToken)); + $user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token='.\urlencode($accessToken)); $this->user = \json_decode($user, true); - $emails = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token=' . \urlencode($accessToken)); + $emails = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token='.\urlencode($accessToken)); $emails = \json_decode($emails, true); if (isset($emails['values'])) { foreach ($emails['values'] as $email) { @@ -175,6 +168,7 @@ class Bitbucket extends OAuth2 } } } + return $this->user; } } diff --git a/src/Appwrite/Auth/OAuth2/Bitly.php b/src/Appwrite/Auth/OAuth2/Bitly.php index 290876a8cb..b5521cad39 100644 --- a/src/Appwrite/Auth/OAuth2/Bitly.php +++ b/src/Appwrite/Auth/OAuth2/Bitly.php @@ -47,17 +47,16 @@ class Bitly extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint . 'authorize?' . + return $this->endpoint.'authorize?'. \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -65,14 +64,14 @@ class Bitly extends OAuth2 if (empty($this->tokens)) { $response = $this->request( 'POST', - $this->resourceEndpoint . 'oauth/access_token', - ["Content-Type: application/x-www-form-urlencoded"], + $this->resourceEndpoint.'oauth/access_token', + ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ - "client_id" => $this->appID, - "client_secret" => $this->appSecret, - "code" => $code, - "redirect_uri" => $this->callback, - "state" => \json_encode($this->state) + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'code' => $code, + 'redirect_uri' => $this->callback, + 'state' => \json_encode($this->state), ]) ); @@ -85,21 +84,20 @@ class Bitly extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $response = $this->request( 'POST', - $this->resourceEndpoint . 'oauth/access_token', - ["Content-Type: application/x-www-form-urlencoded"], + $this->resourceEndpoint.'oauth/access_token', + ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ - "client_id" => $this->appID, - "client_secret" => $this->appSecret, - "refresh_token" => $refreshToken, - 'grant_type' => 'refresh_token' + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'refresh_token' => $refreshToken, + 'grant_type' => 'refresh_token', ]) ); @@ -115,8 +113,7 @@ class Bitly extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -127,8 +124,7 @@ class Bitly extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -151,8 +147,7 @@ class Bitly extends OAuth2 * * @link https://dev.bitly.com/api-reference#getUser * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -161,8 +156,7 @@ class Bitly extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -173,19 +167,18 @@ class Bitly extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) { $headers = [ - 'Authorization: Bearer ' . \urlencode($accessToken), - "Accept: application/json" + 'Authorization: Bearer '.\urlencode($accessToken), + 'Accept: application/json', ]; if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', $this->resourceEndpoint . "v4/user", $headers), true); + $this->user = \json_decode($this->request('GET', $this->resourceEndpoint.'v4/user', $headers), true); } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Box.php b/src/Appwrite/Auth/OAuth2/Box.php index e88c165833..5d2c5e2b38 100644 --- a/src/Appwrite/Auth/OAuth2/Box.php +++ b/src/Appwrite/Auth/OAuth2/Box.php @@ -49,7 +49,7 @@ class Box extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint . 'authorize?' . + $url = $this->endpoint.'authorize?'. \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, @@ -62,8 +62,7 @@ class Box extends OAuth2 } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -72,15 +71,15 @@ class Box extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'token', + $this->endpoint.'token', $headers, \http_build_query([ - "client_id" => $this->appID, - "client_secret" => $this->appSecret, - "code" => $code, - "grant_type" => "authorization_code", - "scope" => \implode(',', $this->getScopes()), - "redirect_uri" => $this->callback + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'code' => $code, + 'grant_type' => 'authorization_code', + 'scope' => \implode(',', $this->getScopes()), + 'redirect_uri' => $this->callback, ]) ), true); } @@ -89,8 +88,7 @@ class Box extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -98,13 +96,13 @@ class Box extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'token', + $this->endpoint.'token', $headers, \http_build_query([ - "client_id" => $this->appID, - "client_secret" => $this->appSecret, - "refresh_token" => $refreshToken, - "grant_type" => "refresh_token", + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'refresh_token' => $refreshToken, + 'grant_type' => 'refresh_token', ]) ), true); @@ -116,8 +114,7 @@ class Box extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -128,8 +125,7 @@ class Box extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -144,20 +140,18 @@ class Box extends OAuth2 * * If present, the email is verified. This was verfied through a manual Box sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -168,19 +162,18 @@ class Box extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { $header = [ - 'Authorization: Bearer ' . \urlencode($accessToken), + 'Authorization: Bearer '.\urlencode($accessToken), ]; if (empty($this->user)) { $user = $this->request( 'GET', - $this->resourceEndpoint . 'me', + $this->resourceEndpoint.'me', $header ); $this->user = \json_decode($user, true); diff --git a/src/Appwrite/Auth/OAuth2/Dailymotion.php b/src/Appwrite/Auth/OAuth2/Dailymotion.php index 0fc90e3ca1..5ead308fbe 100644 --- a/src/Appwrite/Auth/OAuth2/Dailymotion.php +++ b/src/Appwrite/Auth/OAuth2/Dailymotion.php @@ -24,7 +24,7 @@ class Dailymotion extends OAuth2 */ protected array $scopes = [ 'userinfo', - 'email' + 'email', ]; /** @@ -34,7 +34,7 @@ class Dailymotion extends OAuth2 'email', 'id', 'fullname', - 'verified' + 'verified', ]; /** @@ -68,21 +68,20 @@ class Dailymotion extends OAuth2 */ public function getLoginURL(): string { - $url = $this->authEndpoint . '?' . + $url = $this->authEndpoint.'?'. \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'state' => \json_encode($this->state), 'redirect_uri' => $this->callback, - 'scope' => \implode(' ', $this->getScopes()) + 'scope' => \implode(' ', $this->getScopes()), ]); return $url; } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -90,33 +89,31 @@ class Dailymotion extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth/token', - ["Content-Type: application/x-www-form-urlencoded"], + $this->endpoint.'/oauth/token', + ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'authorization_code', - "client_id" => $this->appID, - "client_secret" => $this->appSecret, - "redirect_uri" => $this->callback, + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'redirect_uri' => $this->callback, 'code' => $code, 'scope' => \implode(' ', $this->getScopes()), ]) ), true); } + return $this->tokens; } - /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { - $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth/token', + $this->endpoint.'/oauth/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'refresh_token', @@ -130,13 +127,11 @@ class Dailymotion extends OAuth2 $this->tokens['refresh_token'] = $refreshToken; } - return $this->tokens; } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -149,8 +144,7 @@ class Dailymotion extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -166,8 +160,7 @@ class Dailymotion extends OAuth2 * * @link https://developers.dailymotion.com/api/#user-fields * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -178,23 +171,20 @@ class Dailymotion extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string { $user = $this->getUser($accessToken); - $username = $user['fullname'] ?? ''; return $username; } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array @@ -202,8 +192,8 @@ class Dailymotion extends OAuth2 if (empty($this->user)) { $user = $this->request( 'GET', - $this->endpoint . '/user/me?fields=' . \implode(',', $this->getFields()), - ['Authorization: Bearer ' . \urlencode($accessToken)], + $this->endpoint.'/user/me?fields='.\implode(',', $this->getFields()), + ['Authorization: Bearer '.\urlencode($accessToken)], ); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Discord.php b/src/Appwrite/Auth/OAuth2/Discord.php index b77ce6a236..b98d5bdc0c 100644 --- a/src/Appwrite/Auth/OAuth2/Discord.php +++ b/src/Appwrite/Auth/OAuth2/Discord.php @@ -28,8 +28,8 @@ class Discord extends OAuth2 * @var array */ protected array $scopes = [ - 'identify', - 'email' + 'identify', + 'email', ]; /** @@ -45,21 +45,20 @@ class Discord extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint . '/oauth2/authorize?' . + $url = $this->endpoint.'/oauth2/authorize?'. \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), - 'redirect_uri' => $this->callback + 'redirect_uri' => $this->callback, ]); return $url; } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -67,7 +66,7 @@ class Discord extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth2/token', + $this->endpoint.'/oauth2/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'authorization_code', @@ -75,7 +74,7 @@ class Discord extends OAuth2 'redirect_uri' => $this->callback, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, - 'scope' => \implode(' ', $this->getScopes()) + 'scope' => \implode(' ', $this->getScopes()), ]) ), true); } @@ -84,15 +83,14 @@ class Discord extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth2/token', + $this->endpoint.'/oauth2/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'refresh_token', @@ -110,8 +108,7 @@ class Discord extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -122,8 +119,7 @@ class Discord extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -138,8 +134,7 @@ class Discord extends OAuth2 * * @link https://discord.com/developers/docs/resources/user * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -154,8 +149,7 @@ class Discord extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -166,8 +160,7 @@ class Discord extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array @@ -175,8 +168,8 @@ class Discord extends OAuth2 if (empty($this->user)) { $user = $this->request( 'GET', - $this->endpoint . '/users/@me', - ['Authorization: Bearer ' . \urlencode($accessToken)] + $this->endpoint.'/users/@me', + ['Authorization: Bearer '.\urlencode($accessToken)] ); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Disqus.php b/src/Appwrite/Auth/OAuth2/Disqus.php index 58b7f48914..eb657298cd 100644 --- a/src/Appwrite/Auth/OAuth2/Disqus.php +++ b/src/Appwrite/Auth/OAuth2/Disqus.php @@ -45,21 +45,20 @@ class Disqus extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint . 'oauth/2.0/authorize/?' . + $url = $this->endpoint.'oauth/2.0/authorize/?'. \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'state' => \json_encode($this->state), 'redirect_uri' => $this->callback, - 'scope' => \implode(',', $this->getScopes()) + 'scope' => \implode(',', $this->getScopes()), ]); return $url; } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -67,7 +66,7 @@ class Disqus extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'oauth/2.0/access_token/', + $this->endpoint.'oauth/2.0/access_token/', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'authorization_code', @@ -79,19 +78,19 @@ class Disqus extends OAuth2 ]) ), true); } + return $this->tokens; } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'oauth/2.0/access_token/?', + $this->endpoint.'oauth/2.0/access_token/?', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'refresh_token', @@ -104,12 +103,12 @@ class Disqus extends OAuth2 if (empty($this->tokens['refresh_token'])) { $this->tokens['refresh_token'] = $refreshToken; } + return $this->tokens; } /** - * @param string $token - * + * @param string $token * @return string */ public function getUserID(string $accessToken): string @@ -122,8 +121,7 @@ class Disqus extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -136,13 +134,11 @@ class Disqus extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { - // Look out for the change in their enpoint. // It's in Beta so they may provide a parameter in the future. // https://disqus.com/api/docs/users/details/ @@ -151,8 +147,7 @@ class Disqus extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -165,8 +160,7 @@ class Disqus extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array @@ -174,10 +168,10 @@ class Disqus extends OAuth2 if (empty($this->user)) { $user = $this->request( 'GET', - $this->endpoint . '3.0/users/details.json?' . \http_build_query([ + $this->endpoint.'3.0/users/details.json?'.\http_build_query([ 'access_token' => $accessToken, 'api_key' => $this->appID, - 'api_secret' => $this->appSecret + 'api_secret' => $this->appSecret, ]), ); $this->user = \json_decode($user, true)['response']; diff --git a/src/Appwrite/Auth/OAuth2/Dropbox.php b/src/Appwrite/Auth/OAuth2/Dropbox.php index ff30b87d8a..156f93e0ee 100644 --- a/src/Appwrite/Auth/OAuth2/Dropbox.php +++ b/src/Appwrite/Auth/OAuth2/Dropbox.php @@ -38,17 +38,16 @@ class Dropbox extends OAuth2 */ public function getLoginURL(): string { - return 'https://www.dropbox.com/oauth2/authorize?' . \http_build_query([ + return 'https://www.dropbox.com/oauth2/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), - 'response_type' => 'code' + 'response_type' => 'code', ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -64,7 +63,7 @@ class Dropbox extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'redirect_uri' => $this->callback, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -73,8 +72,7 @@ class Dropbox extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -88,7 +86,7 @@ class Dropbox extends OAuth2 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -100,8 +98,7 @@ class Dropbox extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -112,8 +109,7 @@ class Dropbox extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -128,8 +124,7 @@ class Dropbox extends OAuth2 * * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -144,8 +139,7 @@ class Dropbox extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -156,14 +150,13 @@ class Dropbox extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; $user = $this->request('POST', 'https://api.dropboxapi.com/2/users/get_current_account', $headers); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Etsy.php b/src/Appwrite/Auth/OAuth2/Etsy.php index 7ff16fcb78..7316cdc1d5 100644 --- a/src/Appwrite/Auth/OAuth2/Etsy.php +++ b/src/Appwrite/Auth/OAuth2/Etsy.php @@ -30,8 +30,8 @@ class Etsy extends OAuth2 * @var array */ protected array $scopes = [ - "email_r", - "profile_r", + 'email_r', + 'profile_r', ]; /** @@ -64,7 +64,7 @@ class Etsy extends OAuth2 */ public function getLoginURL(): string { - return 'https://www.etsy.com/oauth/connect/oauth/authorize?' . \http_build_query([ + return 'https://www.etsy.com/oauth/connect/oauth/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'response_type' => 'code', @@ -76,8 +76,7 @@ class Etsy extends OAuth2 } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -87,7 +86,7 @@ class Etsy extends OAuth2 $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth/token', + $this->endpoint.'/oauth/token', $headers, \http_build_query([ 'grant_type' => 'authorization_code', @@ -103,8 +102,7 @@ class Etsy extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -113,7 +111,7 @@ class Etsy extends OAuth2 $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth/token', + $this->endpoint.'/oauth/token', $headers, \http_build_query([ 'grant_type' => 'refresh_token', @@ -131,7 +129,6 @@ class Etsy extends OAuth2 /** * @param $accessToken - * * @return string */ public function getUserID(string $accessToken): string @@ -143,7 +140,6 @@ class Etsy extends OAuth2 /** * @param $accessToken - * * @return string */ public function getUserEmail(string $accessToken): string @@ -156,20 +152,18 @@ class Etsy extends OAuth2 * * OAuth is only allowed if account has been verified through Etsy, itself. * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** * @param $accessToken - * * @return string */ public function getUserName(string $accessToken): string @@ -178,21 +172,20 @@ class Etsy extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { - if (!empty($this->user)) { + if (! empty($this->user)) { return $this->user; } - $headers = ['Authorization: Bearer ' . $accessToken]; + $headers = ['Authorization: Bearer '.$accessToken]; $this->user = \json_decode($this->request( 'GET', - 'https://api.etsy.com/v3/application/users/' . $this->getUserID($accessToken), + 'https://api.etsy.com/v3/application/users/'.$this->getUserID($accessToken), ), true); return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Exception.php b/src/Appwrite/Auth/OAuth2/Exception.php index 3d5b79d3b0..eddab9d400 100644 --- a/src/Appwrite/Auth/OAuth2/Exception.php +++ b/src/Appwrite/Auth/OAuth2/Exception.php @@ -7,7 +7,9 @@ use Appwrite\Extend\Exception as AppwriteException; class Exception extends AppwriteException { protected string $response = ''; + protected string $error = ''; + protected string $errorDescription = ''; public function __construct(string $response = '', int $code = 0, \Throwable $previous = null) @@ -19,11 +21,11 @@ class Exception extends AppwriteException if (\is_array($decoded['error'])) { $this->error = $decoded['error']['status']; $this->errorDescription = $decoded['error']['message']; - $this->message = $this->error . ': ' . $this->errorDescription; + $this->message = $this->error.': '.$this->errorDescription; } else { $this->error = $decoded['error']; $this->errorDescription = $decoded['error_description']; - $this->message = $this->error . ': ' . $this->errorDescription; + $this->message = $this->error.': '.$this->errorDescription; } } $type = match ($code) { diff --git a/src/Appwrite/Auth/OAuth2/Facebook.php b/src/Appwrite/Auth/OAuth2/Facebook.php index 90fe8e7388..9b10f3be80 100644 --- a/src/Appwrite/Auth/OAuth2/Facebook.php +++ b/src/Appwrite/Auth/OAuth2/Facebook.php @@ -25,7 +25,7 @@ class Facebook extends OAuth2 * @var array */ protected array $scopes = [ - 'email' + 'email', ]; /** @@ -41,17 +41,16 @@ class Facebook extends OAuth2 */ public function getLoginURL(): string { - return 'https://www.facebook.com/' . $this->version . '/dialog/oauth?' . \http_build_query([ + return 'https://www.facebook.com/'.$this->version.'/dialog/oauth?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -59,11 +58,11 @@ class Facebook extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'GET', - 'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' . \http_build_query([ + 'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, - 'code' => $code + 'code' => $code, ]) ), true); } @@ -72,20 +71,19 @@ class Facebook extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'GET', - 'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' . \http_build_query([ + 'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -97,8 +95,7 @@ class Facebook extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -109,8 +106,7 @@ class Facebook extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -125,20 +121,18 @@ class Facebook extends OAuth2 * * If present, the email is verified. This was verfied through a manual Facebook sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -149,14 +143,13 @@ class Facebook extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://graph.facebook.com/' . $this->version . '/me?fields=email,name&access_token=' . \urlencode($accessToken)); + $user = $this->request('GET', 'https://graph.facebook.com/'.$this->version.'/me?fields=email,name&access_token='.\urlencode($accessToken)); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Firebase.php b/src/Appwrite/Auth/OAuth2/Firebase.php index 0a813881be..96638e83a3 100644 --- a/src/Appwrite/Auth/OAuth2/Firebase.php +++ b/src/Appwrite/Auth/OAuth2/Firebase.php @@ -24,7 +24,7 @@ class Firebase extends OAuth2 'https://www.googleapis.com/auth/datastore', 'https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/identitytoolkit', - 'https://www.googleapis.com/auth/userinfo.profile' + 'https://www.googleapis.com/auth/userinfo.profile', ]; /** @@ -40,7 +40,7 @@ class Firebase extends OAuth2 */ public function getLoginURL(): string { - return 'https://accounts.google.com/o/oauth2/v2/auth?' . \http_build_query([ + return 'https://accounts.google.com/o/oauth2/v2/auth?'.\http_build_query([ 'access_type' => 'offline', 'client_id' => $this->appID, 'redirect_uri' => $this->callback, @@ -52,8 +52,7 @@ class Firebase extends OAuth2 } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -68,19 +67,18 @@ class Firebase extends OAuth2 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, 'code' => $code, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ); - $this->tokens = \json_decode($response, true); + $this->tokens = \json_decode($response, true); } return $this->tokens; } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -93,7 +91,7 @@ class Firebase extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken + 'refresh_token' => $refreshToken, ]) ); @@ -108,10 +106,8 @@ class Firebase extends OAuth2 return $this->tokens; } - /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -122,8 +118,7 @@ class Firebase extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -133,14 +128,12 @@ class Firebase extends OAuth2 return $user['email'] ?? ''; } - /** * Check if the OAuth email is verified * * @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -155,8 +148,7 @@ class Firebase extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -167,8 +159,7 @@ class Firebase extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) @@ -176,7 +167,7 @@ class Firebase extends OAuth2 if (empty($this->user)) { $response = $this->request( 'GET', - 'https://www.googleapis.com/oauth2/v1/userinfo?access_token=' . \urlencode($accessToken), + 'https://www.googleapis.com/oauth2/v1/userinfo?access_token='.\urlencode($accessToken), [], ); @@ -188,7 +179,7 @@ class Firebase extends OAuth2 public function getProjects(string $accessToken): array { - $projects = $this->request('GET', 'https://firebase.googleapis.com/v1beta1/projects', ['Authorization: Bearer ' . \urlencode($accessToken)]); + $projects = $this->request('GET', 'https://firebase.googleapis.com/v1beta1/projects', ['Authorization: Bearer '.\urlencode($accessToken)]); $projects = \json_decode($projects, true); @@ -201,9 +192,9 @@ class Firebase extends OAuth2 public function assignIAMRoles(string $accessToken, string $email, string $projectId) { // Get IAM Roles - $iamRoles = $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/' . $projectId . ':getIamPolicy', [ - 'Authorization: Bearer ' . \urlencode($accessToken), - 'Content-Type: application/json' + $iamRoles = $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/'.$projectId.':getIamPolicy', [ + 'Authorization: Bearer '.\urlencode($accessToken), + 'Content-Type: application/json', ]); $iamRoles = \json_decode($iamRoles, true); @@ -211,23 +202,23 @@ class Firebase extends OAuth2 $iamRoles['bindings'][] = [ 'role' => 'roles/identitytoolkit.admin', 'members' => [ - 'serviceAccount:' . $email - ] + 'serviceAccount:'.$email, + ], ]; $iamRoles['bindings'][] = [ 'role' => 'roles/firebase.admin', 'members' => [ - 'serviceAccount:' . $email - ] + 'serviceAccount:'.$email, + ], ]; // Set IAM Roles - $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/' . $projectId . ':setIamPolicy', [ - 'Authorization: Bearer ' . \urlencode($accessToken), - 'Content-Type: application/json' + $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/'.$projectId.':setIamPolicy', [ + 'Authorization: Bearer '.\urlencode($accessToken), + 'Content-Type: application/json', ], json_encode([ - 'policy' => $iamRoles + 'policy' => $iamRoles, ])); } @@ -236,16 +227,16 @@ class Firebase extends OAuth2 // Create Service Account $response = $this->request( 'POST', - 'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts', + 'https://iam.googleapis.com/v1/projects/'.$projectId.'/serviceAccounts', [ - 'Authorization: Bearer ' . \urlencode($accessToken), - 'Content-Type: application/json' + 'Authorization: Bearer '.\urlencode($accessToken), + 'Content-Type: application/json', ], json_encode([ 'accountId' => 'appwrite-migrations', 'serviceAccount' => [ - 'displayName' => 'Appwrite Migrations' - ] + 'displayName' => 'Appwrite Migrations', + ], ]) ); @@ -256,10 +247,10 @@ class Firebase extends OAuth2 // Create Service Account Key $responseKey = $this->request( 'POST', - 'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts/' . $response['email'] . '/keys', + 'https://iam.googleapis.com/v1/projects/'.$projectId.'/serviceAccounts/'.$response['email'].'/keys', [ - 'Authorization: Bearer ' . \urlencode($accessToken), - 'Content-Type: application/json' + 'Authorization: Bearer '.\urlencode($accessToken), + 'Content-Type: application/json', ] ); diff --git a/src/Appwrite/Auth/OAuth2/Github.php b/src/Appwrite/Auth/OAuth2/Github.php index 8b9208fc06..ab67e17aa0 100644 --- a/src/Appwrite/Auth/OAuth2/Github.php +++ b/src/Appwrite/Auth/OAuth2/Github.php @@ -36,17 +36,16 @@ class Github extends OAuth2 */ public function getLoginURL(): string { - return 'https://github.com/login/oauth/authorize?' . \http_build_query([ + return 'https://github.com/login/oauth/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -60,7 +59,7 @@ class Github extends OAuth2 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, - 'code' => $code + 'code' => $code, ]) ); @@ -73,8 +72,7 @@ class Github extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -87,7 +85,7 @@ class Github extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken + 'refresh_token' => $refreshToken, ]) ); @@ -103,8 +101,7 @@ class Github extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -115,8 +112,7 @@ class Github extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -131,8 +127,7 @@ class Github extends OAuth2 * * @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -147,8 +142,7 @@ class Github extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -159,8 +153,7 @@ class Github extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserSlug(string $accessToken): string @@ -171,16 +164,15 @@ class Github extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) { if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token ' . \urlencode($accessToken)]), true); + $this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token '.\urlencode($accessToken)]), true); - $emails = $this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token ' . \urlencode($accessToken)]); + $emails = $this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token '.\urlencode($accessToken)]); $emails = \json_decode($emails, true); @@ -197,10 +189,10 @@ class Github extends OAuth2 } } - if (!empty($primaryEmail)) { + if (! empty($primaryEmail)) { $this->user['email'] = $primaryEmail['email']; $this->user['verified'] = $primaryEmail['verified']; - } elseif (!empty($verifiedEmail)) { + } elseif (! empty($verifiedEmail)) { $this->user['email'] = $verifiedEmail['email']; $this->user['verified'] = $verifiedEmail['verified']; } diff --git a/src/Appwrite/Auth/OAuth2/Gitlab.php b/src/Appwrite/Auth/OAuth2/Gitlab.php index 7d98bf1921..f96348c98b 100644 --- a/src/Appwrite/Auth/OAuth2/Gitlab.php +++ b/src/Appwrite/Auth/OAuth2/Gitlab.php @@ -23,7 +23,7 @@ class Gitlab extends OAuth2 * @var array */ protected array $scopes = [ - 'read_user' + 'read_user', ]; /** @@ -39,18 +39,17 @@ class Gitlab extends OAuth2 */ public function getLoginURL(): string { - return $this->getEndpoint() . '/oauth/authorize?' . \http_build_query([ + return $this->getEndpoint().'/oauth/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state), - 'response_type' => 'code' + 'response_type' => 'code', ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -58,12 +57,12 @@ class Gitlab extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->getEndpoint() . '/oauth/token?' . \http_build_query([ + $this->getEndpoint().'/oauth/token?'.\http_build_query([ 'code' => $code, 'client_id' => $this->appID, 'client_secret' => $this->getAppSecret()['clientSecret'], 'redirect_uri' => $this->callback, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -72,19 +71,18 @@ class Gitlab extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->getEndpoint() . '/oauth/token?' . \http_build_query([ + $this->getEndpoint().'/oauth/token?'.\http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getAppSecret()['clientSecret'], - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -96,8 +94,7 @@ class Gitlab extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -112,8 +109,7 @@ class Gitlab extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -128,8 +124,7 @@ class Gitlab extends OAuth2 * * @link https://docs.gitlab.com/ee/api/users.html#list-current-user-for-normal-users * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -144,8 +139,7 @@ class Gitlab extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -156,14 +150,13 @@ class Gitlab extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', $this->getEndpoint() . '/api/v4/user?access_token=' . \urlencode($accessToken)); + $user = $this->request('GET', $this->getEndpoint().'/api/v4/user?access_token='.\urlencode($accessToken)); $this->user = \json_decode($user, true); } @@ -182,10 +175,10 @@ class Gitlab extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } + return $secret; } - /** * Extracts the Tenant Id from the JSON stored in appSecret. Defaults to 'common' as a fallback * @@ -196,6 +189,7 @@ class Gitlab extends OAuth2 $defaultEndpoint = 'https://gitlab.com'; $secret = $this->getAppSecret(); $endpoint = $secret['endpoint'] ?? $defaultEndpoint; + return empty($endpoint) ? $defaultEndpoint : $endpoint; } } diff --git a/src/Appwrite/Auth/OAuth2/Google.php b/src/Appwrite/Auth/OAuth2/Google.php index c6f621b814..c56f1660c4 100644 --- a/src/Appwrite/Auth/OAuth2/Google.php +++ b/src/Appwrite/Auth/OAuth2/Google.php @@ -22,7 +22,7 @@ class Google extends OAuth2 protected array $scopes = [ 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', - 'openid' + 'openid', ]; /** @@ -48,18 +48,17 @@ class Google extends OAuth2 */ public function getLoginURL(): string { - return 'https://accounts.google.com/o/oauth2/v2/auth?' . \http_build_query([ + return 'https://accounts.google.com/o/oauth2/v2/auth?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state), - 'response_type' => 'code' + 'response_type' => 'code', ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -67,13 +66,13 @@ class Google extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - 'https://oauth2.googleapis.com/token?' . \http_build_query([ + 'https://oauth2.googleapis.com/token?'.\http_build_query([ 'code' => $code, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'redirect_uri' => $this->callback, 'scope' => null, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -82,19 +81,18 @@ class Google extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - 'https://oauth2.googleapis.com/token?' . \http_build_query([ + 'https://oauth2.googleapis.com/token?'.\http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -106,8 +104,7 @@ class Google extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -118,8 +115,7 @@ class Google extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -134,8 +130,7 @@ class Google extends OAuth2 * * @link https://www.oauth.com/oauth2-servers/signing-in-with-google/verifying-the-user-info/ * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -150,8 +145,7 @@ class Google extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -162,14 +156,13 @@ class Google extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' . \urlencode($accessToken)); + $user = $this->request('GET', 'https://www.googleapis.com/oauth2/v3/userinfo?access_token='.\urlencode($accessToken)); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Linkedin.php b/src/Appwrite/Auth/OAuth2/Linkedin.php index 340cab2df0..c4e899b5ca 100644 --- a/src/Appwrite/Auth/OAuth2/Linkedin.php +++ b/src/Appwrite/Auth/OAuth2/Linkedin.php @@ -50,7 +50,7 @@ class Linkedin extends OAuth2 */ public function getLoginURL(): string { - return 'https://www.linkedin.com/oauth/v2/authorization?' . \http_build_query([ + return 'https://www.linkedin.com/oauth/v2/authorization?'.\http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'redirect_uri' => $this->callback, @@ -60,8 +60,7 @@ class Linkedin extends OAuth2 } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -80,12 +79,12 @@ class Linkedin extends OAuth2 ]) ), true); } + return $this->tokens; } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -106,12 +105,12 @@ class Linkedin extends OAuth2 if (empty($this->tokens['refresh_token'])) { $this->tokens['refresh_token'] = $refreshToken; } + return $this->tokens; } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -122,13 +121,12 @@ class Linkedin extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string { - $email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer ' . \urlencode($accessToken)]), true); + $email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer '.\urlencode($accessToken)]), true); return $email['elements'][0]['handle~']['emailAddress'] ?? ''; } @@ -138,20 +136,18 @@ class Linkedin extends OAuth2 * * If present, the email is verified. This was verfied through a manual Linkedin sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -164,21 +160,20 @@ class Linkedin extends OAuth2 } if (isset($user['localizedLastName'])) { - $name = (empty($name)) ? $user['localizedLastName'] : $name . ' ' . $user['localizedLastName']; + $name = (empty($name)) ? $user['localizedLastName'] : $name.' '.$user['localizedLastName']; } return $name; } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) { if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer ' . \urlencode($accessToken)]), true); + $this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer '.\urlencode($accessToken)]), true); } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Microsoft.php b/src/Appwrite/Auth/OAuth2/Microsoft.php index bc05843b37..89b77c1925 100644 --- a/src/Appwrite/Auth/OAuth2/Microsoft.php +++ b/src/Appwrite/Auth/OAuth2/Microsoft.php @@ -25,7 +25,7 @@ class Microsoft extends OAuth2 */ protected array $scopes = [ 'offline_access', - 'user.read' + 'user.read', ]; /** @@ -41,19 +41,18 @@ class Microsoft extends OAuth2 */ public function getLoginURL(): string { - return 'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/authorize?' . \http_build_query([ + return 'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), 'response_type' => 'code', - 'response_mode' => 'query' + 'response_mode' => 'query', ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -62,7 +61,7 @@ class Microsoft extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/token', + 'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/token', $headers, \http_build_query([ 'code' => $code, @@ -70,7 +69,7 @@ class Microsoft extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -79,8 +78,7 @@ class Microsoft extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -88,13 +86,13 @@ class Microsoft extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/token', + 'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/token', $headers, \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -106,8 +104,7 @@ class Microsoft extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -118,8 +115,7 @@ class Microsoft extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -134,20 +130,18 @@ class Microsoft extends OAuth2 * * If present, the email is verified. This was verfied through a manual Microsoft sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -158,14 +152,13 @@ class Microsoft extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; $user = $this->request('GET', 'https://graph.microsoft.com/v1.0/me', $headers); $this->user = \json_decode($user, true); } @@ -185,6 +178,7 @@ class Microsoft extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } + return $secret; } diff --git a/src/Appwrite/Auth/OAuth2/Mock.php b/src/Appwrite/Auth/OAuth2/Mock.php index d2cb8c1c2a..b0b2e3b8d1 100644 --- a/src/Appwrite/Auth/OAuth2/Mock.php +++ b/src/Appwrite/Auth/OAuth2/Mock.php @@ -3,7 +3,6 @@ namespace Appwrite\Auth\OAuth2; use Appwrite\Auth\OAuth2; -use Utopia\Exception; class Mock extends OAuth2 { @@ -16,7 +15,7 @@ class Mock extends OAuth2 * @var array */ protected array $scopes = [ - 'email' + 'email', ]; /** @@ -42,17 +41,16 @@ class Mock extends OAuth2 */ public function getLoginURL(): string { - return 'http://localhost/' . $this->version . '/mock/tests/general/oauth2?' . \http_build_query([ + return 'http://localhost/'.$this->version.'/mock/tests/general/oauth2?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -60,12 +58,12 @@ class Mock extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'GET', - 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' . + 'http://localhost/'.$this->version.'/mock/tests/general/oauth2/token?'. \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, - 'code' => $code + 'code' => $code, ]) ), true); } @@ -74,20 +72,19 @@ class Mock extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'GET', - 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' . + 'http://localhost/'.$this->version.'/mock/tests/general/oauth2/token?'. \http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -99,8 +96,7 @@ class Mock extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -111,8 +107,7 @@ class Mock extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -125,8 +120,7 @@ class Mock extends OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -135,8 +129,7 @@ class Mock extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -147,14 +140,13 @@ class Mock extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/user?token=' . \urlencode($accessToken)); + $user = $this->request('GET', 'http://localhost/'.$this->version.'/mock/tests/general/oauth2/user?token='.\urlencode($accessToken)); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Notion.php b/src/Appwrite/Auth/OAuth2/Notion.php index c2f1ee98e4..17c1dd7f18 100644 --- a/src/Appwrite/Auth/OAuth2/Notion.php +++ b/src/Appwrite/Auth/OAuth2/Notion.php @@ -44,32 +44,31 @@ class Notion extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint . '/oauth/authorize?' . \http_build_query([ + return $this->endpoint.'/oauth/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'response_type' => 'code', 'state' => \json_encode($this->state), - 'owner' => 'user' + 'owner' => 'user', ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { - $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)]; + $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth/token', + $this->endpoint.'/oauth/token', $headers, \http_build_query([ 'grant_type' => 'authorization_code', 'redirect_uri' => $this->callback, - 'code' => $code + 'code' => $code, ]) ), true); } @@ -78,16 +77,15 @@ class Notion extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { - $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)]; + $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth/token', + $this->endpoint.'/oauth/token', $headers, \http_build_query([ 'grant_type' => 'refresh_token', @@ -103,8 +101,7 @@ class Notion extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -115,8 +112,7 @@ class Notion extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -131,20 +127,18 @@ class Notion extends OAuth2 * * If present, the email is verified. This was verfied through a manual Notion sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -155,19 +149,18 @@ class Notion extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { $headers = [ - 'Notion-Version: ' . $this->version, - 'Authorization: Bearer ' . \urlencode($accessToken) + 'Notion-Version: '.$this->version, + 'Authorization: Bearer '.\urlencode($accessToken), ]; if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', $this->endpoint . '/users/me', $headers), true); + $this->user = \json_decode($this->request('GET', $this->endpoint.'/users/me', $headers), true); } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Oidc.php b/src/Appwrite/Auth/OAuth2/Oidc.php index de2eab65c8..dfdf9aeff0 100644 --- a/src/Appwrite/Auth/OAuth2/Oidc.php +++ b/src/Appwrite/Auth/OAuth2/Oidc.php @@ -43,7 +43,7 @@ class Oidc extends OAuth2 */ public function getLoginURL(): string { - return $this->getAuthorizationEndpoint() . '?' . \http_build_query([ + return $this->getAuthorizationEndpoint().'?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), @@ -53,8 +53,7 @@ class Oidc extends OAuth2 } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -71,17 +70,16 @@ class Oidc extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } + return $this->tokens; } - /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -95,7 +93,7 @@ class Oidc extends OAuth2 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -107,8 +105,7 @@ class Oidc extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -123,8 +120,7 @@ class Oidc extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -141,8 +137,7 @@ class Oidc extends OAuth2 /** * Check if the User email is verified * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -153,8 +148,7 @@ class Oidc extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -168,15 +162,14 @@ class Oidc extends OAuth2 return ''; } - /** - * @param string $accessToken - * + /** + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; $user = $this->request('GET', $this->getUserinfoEndpoint(), $headers); $this->user = \json_decode($user, true); } @@ -196,7 +189,7 @@ class Oidc extends OAuth2 return $secret['clientSecret'] ?? ''; } - /** + /** * Extracts the well known endpoint from the JSON stored in appSecret. * * @return string @@ -204,13 +197,14 @@ class Oidc extends OAuth2 protected function getWellKnownEndpoint(): string { $secret = $this->getAppSecret(); + return $secret['wellKnownEndpoint'] ?? ''; } /** - * Extracts the authorization endpoint from the JSON stored in appSecret. - * - * If one is not provided, it will be retrieved from the well-known configuration. + * Extracts the authorization endpoint from the JSON stored in appSecret. + * + * If one is not provided, it will be retrieved from the well-known configuration. * * @return string */ @@ -219,56 +213,59 @@ class Oidc extends OAuth2 $secret = $this->getAppSecret(); $endpoint = $secret['authorizationEndpoint'] ?? ''; - if (!empty($endpoint)) { + if (! empty($endpoint)) { return $endpoint; } $wellKnownConfiguration = $this->getWellKnownConfiguration(); + return $wellKnownConfiguration['authorization_endpoint'] ?? ''; } /** - * Extracts the token endpoint from the JSON stored in appSecret. - * - * If one is not provided, it will be retrieved from the well-known configuration. - * - * @return string - */ + * Extracts the token endpoint from the JSON stored in appSecret. + * + * If one is not provided, it will be retrieved from the well-known configuration. + * + * @return string + */ protected function getTokenEndpoint(): string { $secret = $this->getAppSecret(); $endpoint = $secret['tokenEndpoint'] ?? ''; - if (!empty($endpoint)) { + if (! empty($endpoint)) { return $endpoint; } $wellKnownConfiguration = $this->getWellKnownConfiguration(); + return $wellKnownConfiguration['token_endpoint'] ?? ''; } /** - * Extracts the userinfo endpoint from the JSON stored in appSecret. - * - * If one is not provided, it will be retrieved from the well-known configuration. - * - * @return string - */ + * Extracts the userinfo endpoint from the JSON stored in appSecret. + * + * If one is not provided, it will be retrieved from the well-known configuration. + * + * @return string + */ protected function getUserinfoEndpoint(): string { $secret = $this->getAppSecret(); $endpoint = $secret['userinfoEndpoint'] ?? ''; - if (!empty($endpoint)) { + if (! empty($endpoint)) { return $endpoint; } $wellKnownConfiguration = $this->getWellKnownConfiguration(); + return $wellKnownConfiguration['userinfo_endpoint'] ?? ''; } - /** - * Get the well-known configuration using the well known endpoint - */ + /** + * Get the well-known configuration using the well known endpoint + */ protected function getWellKnownConfiguration(): array { if (empty($this->wellKnownConfiguration)) { @@ -291,6 +288,7 @@ class Oidc extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } + return $secret; } } diff --git a/src/Appwrite/Auth/OAuth2/Okta.php b/src/Appwrite/Auth/OAuth2/Okta.php index 610d9847f2..367c64e764 100644 --- a/src/Appwrite/Auth/OAuth2/Okta.php +++ b/src/Appwrite/Auth/OAuth2/Okta.php @@ -16,7 +16,7 @@ class Okta extends OAuth2 'openid', 'profile', 'email', - 'offline_access' + 'offline_access', ]; /** @@ -42,18 +42,17 @@ class Okta extends OAuth2 */ public function getLoginURL(): string { - return 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/authorize?' . \http_build_query([ + return 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), - 'response_type' => 'code' + 'response_type' => 'code', ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -62,7 +61,7 @@ class Okta extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token', + 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token', $headers, \http_build_query([ 'code' => $code, @@ -70,7 +69,7 @@ class Okta extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -78,10 +77,8 @@ class Okta extends OAuth2 return $this->tokens; } - /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -89,13 +86,13 @@ class Okta extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token', + 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token', $headers, \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -107,8 +104,7 @@ class Okta extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -119,8 +115,7 @@ class Okta extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -135,8 +130,7 @@ class Okta extends OAuth2 * * @link https://developer.okta.com/docs/reference/api/oidc/#userinfo * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -151,8 +145,7 @@ class Okta extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -163,15 +156,14 @@ class Okta extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; - $user = $this->request('GET', 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/userinfo', $headers); + $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; + $user = $this->request('GET', 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/userinfo', $headers); $this->user = \json_decode($user, true); } @@ -226,6 +218,7 @@ class Okta extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } + return $secret; } } diff --git a/src/Appwrite/Auth/OAuth2/Paypal.php b/src/Appwrite/Auth/OAuth2/Paypal.php index 5d5bd0a06f..e55ed05ac4 100644 --- a/src/Appwrite/Auth/OAuth2/Paypal.php +++ b/src/Appwrite/Auth/OAuth2/Paypal.php @@ -46,7 +46,7 @@ class Paypal extends OAuth2 protected array $scopes = [ 'openid', 'profile', - 'email' + 'email', ]; /** @@ -62,14 +62,14 @@ class Paypal extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint[$this->environment] . 'connect/?' . + $url = $this->endpoint[$this->environment].'connect/?'. \http_build_query([ 'flowEntry' => 'static', 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), // paypal is not accepting localhost string into return uri - 'redirect_uri' => \str_replace("localhost", "127.0.0.1", $this->callback), + 'redirect_uri' => \str_replace('localhost', '127.0.0.1', $this->callback), 'state' => \json_encode($this->state), ]); @@ -77,8 +77,7 @@ class Paypal extends OAuth2 } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -86,8 +85,8 @@ class Paypal extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->resourceEndpoint[$this->environment] . 'oauth2/token', - ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)], + $this->resourceEndpoint[$this->environment].'oauth2/token', + ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)], \http_build_query([ 'code' => $code, 'grant_type' => 'authorization_code', @@ -99,16 +98,15 @@ class Paypal extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->resourceEndpoint[$this->environment] . 'oauth2/token', - ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)], + $this->resourceEndpoint[$this->environment].'oauth2/token', + ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)], \http_build_query([ 'refresh_token' => $refreshToken, 'grant_type' => 'refresh_token', @@ -123,8 +121,7 @@ class Paypal extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -135,8 +132,7 @@ class Paypal extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -148,7 +144,7 @@ class Paypal extends OAuth2 return $email['primary'] === true; }); - if (!empty($email)) { + if (! empty($email)) { return $email[0]['value']; } } @@ -161,8 +157,7 @@ class Paypal extends OAuth2 * * @link https://developer.paypal.com/docs/api/identity/v1/#userinfo_get * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -177,8 +172,7 @@ class Paypal extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -189,20 +183,19 @@ class Paypal extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { $header = [ 'Content-Type: application/json', - 'Authorization: Bearer ' . \urlencode($accessToken), + 'Authorization: Bearer '.\urlencode($accessToken), ]; if (empty($this->user)) { $user = $this->request( 'GET', - $this->resourceEndpoint[$this->environment] . 'identity/oauth2/userinfo?schema=paypalv1.1', + $this->resourceEndpoint[$this->environment].'identity/oauth2/userinfo?schema=paypalv1.1', $header ); $this->user = \json_decode($user, true); diff --git a/src/Appwrite/Auth/OAuth2/PaypalSandbox.php b/src/Appwrite/Auth/OAuth2/PaypalSandbox.php index 0f56a09c21..e5ab612c0d 100644 --- a/src/Appwrite/Auth/OAuth2/PaypalSandbox.php +++ b/src/Appwrite/Auth/OAuth2/PaypalSandbox.php @@ -2,8 +2,6 @@ namespace Appwrite\Auth\OAuth2; -use Appwrite\Auth\OAuth2\Paypal; - class PaypalSandbox extends Paypal { protected string $environment = 'sandbox'; diff --git a/src/Appwrite/Auth/OAuth2/Podio.php b/src/Appwrite/Auth/OAuth2/Podio.php index e4194238d1..f3ba81968e 100644 --- a/src/Appwrite/Auth/OAuth2/Podio.php +++ b/src/Appwrite/Auth/OAuth2/Podio.php @@ -51,19 +51,18 @@ class Podio extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint . '/authorize?' . + $url = $this->endpoint.'/authorize?'. \http_build_query([ 'client_id' => $this->appID, 'state' => \json_encode($this->state), - 'redirect_uri' => $this->callback + 'redirect_uri' => $this->callback, ]); return $url; } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -71,14 +70,14 @@ class Podio extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->apiEndpoint . '/oauth/token', + $this->apiEndpoint.'/oauth/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'authorization_code', 'code' => $code, 'redirect_uri' => $this->callback, 'client_id' => $this->appID, - 'client_secret' => $this->appSecret + 'client_secret' => $this->appSecret, ]) ), true); } @@ -87,15 +86,14 @@ class Podio extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->apiEndpoint . '/oauth/token', + $this->apiEndpoint.'/oauth/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'refresh_token', @@ -113,8 +111,7 @@ class Podio extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -125,8 +122,7 @@ class Podio extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -139,8 +135,7 @@ class Podio extends OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -148,7 +143,7 @@ class Podio extends OAuth2 $user = $this->getUser($accessToken); $mails = $user['mails']; - $mainMailIndex = \array_search($user['mail'], \array_map(fn($m) => $m['mail'], $mails)); + $mainMailIndex = \array_search($user['mail'], \array_map(fn ($m) => $m['mail'], $mails)); $mainMain = $mails[$mainMailIndex]; if ($mainMain['verified'] ?? false) { @@ -159,8 +154,7 @@ class Podio extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -171,8 +165,7 @@ class Podio extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array @@ -180,14 +173,14 @@ class Podio extends OAuth2 if (empty($this->user)) { $user = \json_decode($this->request( 'GET', - $this->apiEndpoint . '/user', - ['Authorization: Bearer ' . \urlencode($accessToken)] + $this->apiEndpoint.'/user', + ['Authorization: Bearer '.\urlencode($accessToken)] ), true); $profile = \json_decode($this->request( 'GET', - $this->apiEndpoint . '/user/profile', - ['Authorization: Bearer ' . \urlencode($accessToken)] + $this->apiEndpoint.'/user/profile', + ['Authorization: Bearer '.\urlencode($accessToken)] ), true); $this->user = $user; diff --git a/src/Appwrite/Auth/OAuth2/Salesforce.php b/src/Appwrite/Auth/OAuth2/Salesforce.php index 564fc51139..5fede655df 100644 --- a/src/Appwrite/Auth/OAuth2/Salesforce.php +++ b/src/Appwrite/Auth/OAuth2/Salesforce.php @@ -25,7 +25,7 @@ class Salesforce extends OAuth2 * @var array */ protected array $scopes = [ - "openid" + 'openid', ]; /** @@ -37,8 +37,7 @@ class Salesforce extends OAuth2 } /** - * @param string $state - * + * @param string $state * @return array */ public function parseState(string $state) @@ -46,31 +45,29 @@ class Salesforce extends OAuth2 return \json_decode(\html_entity_decode($state), true); } - /** * @return string */ public function getLoginURL(): string { - return 'https://login.salesforce.com/services/oauth2/authorize?' . \http_build_query([ + return 'https://login.salesforce.com/services/oauth2/authorize?'.\http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { $headers = [ - 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), + 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( @@ -80,7 +77,7 @@ class Salesforce extends OAuth2 \http_build_query([ 'code' => $code, 'redirect_uri' => $this->callback, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -89,14 +86,13 @@ class Salesforce extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $headers = [ - 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), + 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( @@ -105,7 +101,7 @@ class Salesforce extends OAuth2 $headers, \http_build_query([ 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -117,8 +113,7 @@ class Salesforce extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -129,8 +124,7 @@ class Salesforce extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -145,8 +139,7 @@ class Salesforce extends OAuth2 * * @link https://help.salesforce.com/s/articleView?id=sf.remoteaccess_using_userinfo_endpoint.htm&type=5 * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -161,8 +154,7 @@ class Salesforce extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -173,16 +165,16 @@ class Salesforce extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token=' . \urlencode($accessToken)); + $user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token='.\urlencode($accessToken)); $this->user = \json_decode($user, true); } + return $this->user; } } diff --git a/src/Appwrite/Auth/OAuth2/Slack.php b/src/Appwrite/Auth/OAuth2/Slack.php index 8898f4d1f7..ee6d43c0cc 100644 --- a/src/Appwrite/Auth/OAuth2/Slack.php +++ b/src/Appwrite/Auth/OAuth2/Slack.php @@ -23,7 +23,7 @@ class Slack extends OAuth2 'identity.avatar', 'identity.basic', 'identity.email', - 'identity.team' + 'identity.team', ]; /** @@ -40,17 +40,16 @@ class Slack extends OAuth2 public function getLoginURL(): string { // https://api.slack.com/docs/oauth#step_1_-_sending_users_to_authorize_and_or_install - return 'https://slack.com/oauth/authorize?' . \http_build_query([ + return 'https://slack.com/oauth/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -59,11 +58,11 @@ class Slack extends OAuth2 // https://api.slack.com/docs/oauth#step_3_-_exchanging_a_verification_code_for_an_access_token $this->tokens = \json_decode($this->request( 'GET', - 'https://slack.com/api/oauth.access?' . \http_build_query([ + 'https://slack.com/api/oauth.access?'.\http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'code' => $code, - 'redirect_uri' => $this->callback + 'redirect_uri' => $this->callback, ]) ), true); } @@ -72,19 +71,18 @@ class Slack extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'GET', - 'https://slack.com/api/oauth.access?' . \http_build_query([ + 'https://slack.com/api/oauth.access?'.\http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -96,8 +94,7 @@ class Slack extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -108,8 +105,7 @@ class Slack extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -126,20 +122,18 @@ class Slack extends OAuth2 * * @link https://slack.com/help/articles/207262907-Change-your-email-address * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -152,8 +146,7 @@ class Slack extends OAuth2 /** * @link https://api.slack.com/methods/users.identity * - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array @@ -161,7 +154,7 @@ class Slack extends OAuth2 if (empty($this->user)) { $user = $this->request( 'GET', - 'https://slack.com/api/users.identity?token=' . \urlencode($accessToken) + 'https://slack.com/api/users.identity?token='.\urlencode($accessToken) ); $this->user = \json_decode($user, true); diff --git a/src/Appwrite/Auth/OAuth2/Spotify.php b/src/Appwrite/Auth/OAuth2/Spotify.php index d8e23cf0f0..a8d5c531ab 100644 --- a/src/Appwrite/Auth/OAuth2/Spotify.php +++ b/src/Appwrite/Auth/OAuth2/Spotify.php @@ -49,33 +49,32 @@ class Spotify extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint . 'authorize?' . + return $this->endpoint.'authorize?'. \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { - $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)]; + $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'api/token', + $this->endpoint.'api/token', $headers, \http_build_query([ - "code" => $code, - "grant_type" => "authorization_code", - "redirect_uri" => $this->callback + 'code' => $code, + 'grant_type' => 'authorization_code', + 'redirect_uri' => $this->callback, ]) ), true); } @@ -84,20 +83,19 @@ class Spotify extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { - $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)]; + $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'api/token', + $this->endpoint.'api/token', $headers, \http_build_query([ - "refresh_token" => $refreshToken, - "grant_type" => "refresh_token", + 'refresh_token' => $refreshToken, + 'grant_type' => 'refresh_token', ]) ), true); @@ -109,8 +107,7 @@ class Spotify extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -121,8 +118,7 @@ class Spotify extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -139,8 +135,7 @@ class Spotify extends OAuth2 * * @link https://developer.spotify.com/documentation/web-api/reference/#/operations/get-current-users-profile * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -149,8 +144,7 @@ class Spotify extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -161,8 +155,7 @@ class Spotify extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) @@ -170,8 +163,8 @@ class Spotify extends OAuth2 if (empty($this->user)) { $this->user = \json_decode($this->request( 'GET', - $this->resourceEndpoint . 'me', - ['Authorization: Bearer ' . \urlencode($accessToken)] + $this->resourceEndpoint.'me', + ['Authorization: Bearer '.\urlencode($accessToken)] ), true); } diff --git a/src/Appwrite/Auth/OAuth2/Stripe.php b/src/Appwrite/Auth/OAuth2/Stripe.php index 5a959dbfcb..42260cad1e 100644 --- a/src/Appwrite/Auth/OAuth2/Stripe.php +++ b/src/Appwrite/Auth/OAuth2/Stripe.php @@ -3,7 +3,6 @@ namespace Appwrite\Auth\OAuth2; use Appwrite\Auth\OAuth2; -use Utopia\Exception; class Stripe extends OAuth2 { @@ -50,18 +49,17 @@ class Stripe extends OAuth2 */ public function getLoginURL(): string { - return 'https://connect.stripe.com/oauth/authorize?' . \http_build_query([ + return 'https://connect.stripe.com/oauth/authorize?'.\http_build_query([ 'response_type' => 'code', // The only option at the moment is "code." 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -73,7 +71,7 @@ class Stripe extends OAuth2 [], \http_build_query([ 'grant_type' => $this->grantType['authorize'], - 'code' => $code + 'code' => $code, ]) ), true); @@ -84,8 +82,7 @@ class Stripe extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -105,12 +102,12 @@ class Stripe extends OAuth2 } $this->stripeAccountId = $this->tokens['stripe_user_id']; + return $this->tokens; } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -121,8 +118,7 @@ class Stripe extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -141,20 +137,18 @@ class Stripe extends OAuth2 * * If present, the email is verified. This was verfied through a manual Stripe sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -165,18 +159,17 @@ class Stripe extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) { - if (empty($this->user) && !empty($this->stripeAccountId)) { + if (empty($this->user) && ! empty($this->stripeAccountId)) { $this->user = \json_decode( $this->request( 'GET', - 'https://api.stripe.com/v1/accounts/' . $this->stripeAccountId, - ['Authorization: Bearer ' . \urlencode($accessToken)] + 'https://api.stripe.com/v1/accounts/'.$this->stripeAccountId, + ['Authorization: Bearer '.\urlencode($accessToken)] ), true ); diff --git a/src/Appwrite/Auth/OAuth2/Tradeshift.php b/src/Appwrite/Auth/OAuth2/Tradeshift.php index 8d0bfa8784..350c152e4c 100644 --- a/src/Appwrite/Auth/OAuth2/Tradeshift.php +++ b/src/Appwrite/Auth/OAuth2/Tradeshift.php @@ -10,6 +10,7 @@ use Appwrite\Auth\OAuth2; class Tradeshift extends OAuth2 { public const TRADESHIFT_SANDBOX_API_DOMAIN = 'api-sandbox.tradeshift.com'; + public const TRADESHIFT_API_DOMAIN = 'api.tradeshift.com'; private array $apiDomain = [ @@ -18,13 +19,13 @@ class Tradeshift extends OAuth2 ]; private array $endpoint = [ - 'sandbox' => 'https://' . self::TRADESHIFT_SANDBOX_API_DOMAIN . '/tradeshift/', - 'live' => 'https://' . self::TRADESHIFT_API_DOMAIN . '/tradeshift/', + 'sandbox' => 'https://'.self::TRADESHIFT_SANDBOX_API_DOMAIN.'/tradeshift/', + 'live' => 'https://'.self::TRADESHIFT_API_DOMAIN.'/tradeshift/', ]; private array $resourceEndpoint = [ - 'sandbox' => 'https://' . self::TRADESHIFT_SANDBOX_API_DOMAIN . '/tradeshift/rest/external/', - 'live' => 'https://' . self::TRADESHIFT_API_DOMAIN . '/tradeshift/rest/external/', + 'sandbox' => 'https://'.self::TRADESHIFT_SANDBOX_API_DOMAIN.'/tradeshift/rest/external/', + 'live' => 'https://'.self::TRADESHIFT_API_DOMAIN.'/tradeshift/rest/external/', ]; protected string $environment = 'live'; @@ -64,18 +65,17 @@ class Tradeshift extends OAuth2 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), - 'redirect_uri' => \str_replace("localhost", "127.0.0.1", $this->callback), + 'redirect_uri' => \str_replace('localhost', '127.0.0.1', $this->callback), 'state' => \json_encode($this->state), ]); - $url = $this->endpoint[$this->environment] . 'auth/login?' . $httpQuery; + $url = $this->endpoint[$this->environment].'auth/login?'.$httpQuery; return $url; } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -83,8 +83,8 @@ class Tradeshift extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint[$this->environment] . 'auth/token', - ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)], + $this->endpoint[$this->environment].'auth/token', + ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)], \http_build_query([ 'grant_type' => 'authorization_code', 'code' => $code, @@ -96,16 +96,15 @@ class Tradeshift extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint[$this->environment] . 'auth/token', - ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)], + $this->endpoint[$this->environment].'auth/token', + ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)], \http_build_query([ 'grant_type' => 'refresh_token', 'refresh_token' => $refreshToken, @@ -120,8 +119,7 @@ class Tradeshift extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -132,8 +130,7 @@ class Tradeshift extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -148,20 +145,18 @@ class Tradeshift extends OAuth2 * * If present, the email is verified. This was verfied through a manual Tradeshift sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUser($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -171,12 +166,11 @@ class Tradeshift extends OAuth2 $firstName = $user['FirstName'] ?? ''; $lastName = $user['LastName'] ?? ''; - return $firstName . ' ' . $lastName; + return $firstName.' '.$lastName; } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array @@ -184,14 +178,14 @@ class Tradeshift extends OAuth2 $header = [ 'Content-Type: application/json', 'Accept: application/json', - 'Host: ' . urlencode($this->apiDomain[$this->environment]), - 'Authorization: Bearer ' . $accessToken, + 'Host: '.urlencode($this->apiDomain[$this->environment]), + 'Authorization: Bearer '.$accessToken, ]; if (empty($this->user)) { $response = $this->request( 'GET', - $this->resourceEndpoint[$this->environment] . 'account/info/user', + $this->resourceEndpoint[$this->environment].'account/info/user', $header ); $this->user = \json_decode($response, true); diff --git a/src/Appwrite/Auth/OAuth2/TradeshiftBox.php b/src/Appwrite/Auth/OAuth2/TradeshiftBox.php index 27a4c0a456..d960acf2d3 100644 --- a/src/Appwrite/Auth/OAuth2/TradeshiftBox.php +++ b/src/Appwrite/Auth/OAuth2/TradeshiftBox.php @@ -2,8 +2,6 @@ namespace Appwrite\Auth\OAuth2; -use Appwrite\Auth\OAuth2\Tradeshift; - class TradeshiftBox extends Tradeshift { protected string $environment = 'sandbox'; diff --git a/src/Appwrite/Auth/OAuth2/Twitch.php b/src/Appwrite/Auth/OAuth2/Twitch.php index ed73054c31..dad2efe800 100644 --- a/src/Appwrite/Auth/OAuth2/Twitch.php +++ b/src/Appwrite/Auth/OAuth2/Twitch.php @@ -49,20 +49,19 @@ class Twitch extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint . 'authorize?' . + return $this->endpoint.'authorize?'. \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'redirect_uri' => $this->callback, 'force_verify' => true, - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -70,12 +69,12 @@ class Twitch extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'token?' . \http_build_query([ - "client_id" => $this->appID, - "client_secret" => $this->appSecret, - "code" => $code, - "grant_type" => "authorization_code", - "redirect_uri" => $this->callback + $this->endpoint.'token?'.\http_build_query([ + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'code' => $code, + 'grant_type' => 'authorization_code', + 'redirect_uri' => $this->callback, ]) ), true); } @@ -84,19 +83,18 @@ class Twitch extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'token?' . \http_build_query([ - "client_id" => $this->appID, - "client_secret" => $this->appSecret, - "refresh_token" => $refreshToken, - "grant_type" => "refresh_token", + $this->endpoint.'token?'.\http_build_query([ + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'refresh_token' => $refreshToken, + 'grant_type' => 'refresh_token', ]) ), true); @@ -108,8 +106,7 @@ class Twitch extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -120,8 +117,7 @@ class Twitch extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -138,20 +134,18 @@ class Twitch extends OAuth2 * * @link https://dev.twitch.tv/docs/api/reference#get-users * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -162,8 +156,7 @@ class Twitch extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) @@ -173,8 +166,8 @@ class Twitch extends OAuth2 'GET', $this->resourceEndpoint, [ - 'Authorization: Bearer ' . \urlencode($accessToken), - 'Client-Id: ' . \urlencode($this->appID) + 'Authorization: Bearer '.\urlencode($accessToken), + 'Client-Id: '.\urlencode($this->appID), ] ), true); diff --git a/src/Appwrite/Auth/OAuth2/WordPress.php b/src/Appwrite/Auth/OAuth2/WordPress.php index 1bd55916fc..084b890a5d 100644 --- a/src/Appwrite/Auth/OAuth2/WordPress.php +++ b/src/Appwrite/Auth/OAuth2/WordPress.php @@ -39,18 +39,17 @@ class WordPress extends OAuth2 */ public function getLoginURL(): string { - return 'https://public-api.wordpress.com/oauth2/authorize?' . \http_build_query([ + return 'https://public-api.wordpress.com/oauth2/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'response_type' => 'code', 'scope' => $this->getScopes(), - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -65,7 +64,7 @@ class WordPress extends OAuth2 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, 'grant_type' => 'authorization_code', - 'code' => $code + 'code' => $code, ]) ), true); } @@ -74,8 +73,7 @@ class WordPress extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -88,7 +86,7 @@ class WordPress extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken + 'refresh_token' => $refreshToken, ]) ), true); @@ -100,8 +98,7 @@ class WordPress extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -112,8 +109,7 @@ class WordPress extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -132,8 +128,7 @@ class WordPress extends OAuth2 * * @link https://developer.wordpress.com/docs/api/1.1/get/me/ * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -148,8 +143,7 @@ class WordPress extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -160,14 +154,13 @@ class WordPress extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) { if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', 'https://public-api.wordpress.com/rest/v1/me', ['Authorization: Bearer ' . $accessToken]), true); + $this->user = \json_decode($this->request('GET', 'https://public-api.wordpress.com/rest/v1/me', ['Authorization: Bearer '.$accessToken]), true); } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Yahoo.php b/src/Appwrite/Auth/OAuth2/Yahoo.php index c70a2fb6c9..82496d666c 100644 --- a/src/Appwrite/Auth/OAuth2/Yahoo.php +++ b/src/Appwrite/Auth/OAuth2/Yahoo.php @@ -45,10 +45,8 @@ class Yahoo extends OAuth2 return 'yahoo'; } - /** * @param $state - * * @return array */ public function parseState(string $state) @@ -61,37 +59,36 @@ class Yahoo extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint . 'request_auth?' . + return $this->endpoint.'request_auth?'. \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { $headers = [ - 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), + 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'get_token', + $this->endpoint.'get_token', $headers, \http_build_query([ - "code" => $code, - "grant_type" => "authorization_code", - "redirect_uri" => $this->callback + 'code' => $code, + 'grant_type' => 'authorization_code', + 'redirect_uri' => $this->callback, ]) ), true); } @@ -100,24 +97,23 @@ class Yahoo extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $headers = [ - 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), + 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'get_token', + $this->endpoint.'get_token', $headers, \http_build_query([ - "refresh_token" => $refreshToken, - "grant_type" => "refresh_token", + 'refresh_token' => $refreshToken, + 'grant_type' => 'refresh_token', ]) ), true); @@ -129,8 +125,7 @@ class Yahoo extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -141,8 +136,7 @@ class Yahoo extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -157,20 +151,18 @@ class Yahoo extends OAuth2 * * If present, the email is verified. This was verfied through a manual Yahoo sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -181,8 +173,7 @@ class Yahoo extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) @@ -191,7 +182,7 @@ class Yahoo extends OAuth2 $this->user = \json_decode($this->request( 'GET', $this->resourceEndpoint, - ['Authorization: Bearer ' . \urlencode($accessToken)] + ['Authorization: Bearer '.\urlencode($accessToken)] ), true); } diff --git a/src/Appwrite/Auth/OAuth2/Yammer.php b/src/Appwrite/Auth/OAuth2/Yammer.php index 9e1827bc58..c6d1ba2837 100644 --- a/src/Appwrite/Auth/OAuth2/Yammer.php +++ b/src/Appwrite/Auth/OAuth2/Yammer.php @@ -37,18 +37,17 @@ class Yammer extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint . 'oauth2/authorize?' . + return $this->endpoint.'oauth2/authorize?'. \http_build_query([ 'client_id' => $this->appID, 'response_type' => 'code', 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array @@ -57,13 +56,13 @@ class Yammer extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'access_token?', + $this->endpoint.'access_token?', $headers, \http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'code' => $code, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -72,8 +71,7 @@ class Yammer extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array @@ -81,13 +79,13 @@ class Yammer extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . 'access_token?', + $this->endpoint.'access_token?', $headers, \http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token' + 'grant_type' => 'refresh_token', ]) ), true); @@ -99,8 +97,7 @@ class Yammer extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -111,8 +108,7 @@ class Yammer extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -127,20 +123,18 @@ class Yammer extends OAuth2 * * If present, the email is verified. This was verfied through a manual Yammer sign up process * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return !empty($email); + return ! empty($email); } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -151,14 +145,13 @@ class Yammer extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; $user = $this->request('GET', 'https://www.yammer.com/api/v1/users/current.json', $headers); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Yandex.php b/src/Appwrite/Auth/OAuth2/Yandex.php index a6a2e2e550..13e1fb4dfc 100644 --- a/src/Appwrite/Auth/OAuth2/Yandex.php +++ b/src/Appwrite/Auth/OAuth2/Yandex.php @@ -8,7 +8,6 @@ use Appwrite\Auth\OAuth2; // https://tech.yandex.com/passport/doc/dg/reference/request-docpage/ // https://tech.yandex.com/oauth/doc/dg/reference/web-client-docpage/ - class Yandex extends OAuth2 { /** @@ -35,8 +34,7 @@ class Yandex extends OAuth2 } /** - * @param string $state - * + * @param string $state * @return array */ public function parseState(string $state) @@ -44,30 +42,28 @@ class Yandex extends OAuth2 return \json_decode(\html_entity_decode($state), true); } - /** * @return string */ public function getLoginURL(): string { - return 'https://oauth.yandex.com/authorize?' . \http_build_query([ + return 'https://oauth.yandex.com/authorize?'.\http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state) + 'state' => \json_encode($this->state), ]); } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { $headers = [ - 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), + 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( @@ -76,7 +72,7 @@ class Yandex extends OAuth2 $headers, \http_build_query([ 'code' => $code, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); } @@ -85,14 +81,13 @@ class Yandex extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { $headers = [ - 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), + 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( @@ -101,7 +96,7 @@ class Yandex extends OAuth2 $headers, \http_build_query([ 'refresh_token' => $refreshToken, - 'grant_type' => 'authorization_code' + 'grant_type' => 'authorization_code', ]) ), true); @@ -113,8 +108,7 @@ class Yandex extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -125,8 +119,7 @@ class Yandex extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -139,8 +132,7 @@ class Yandex extends OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -149,8 +141,7 @@ class Yandex extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string @@ -161,19 +152,19 @@ class Yandex extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://login.yandex.ru/info?' . \http_build_query([ + $user = $this->request('GET', 'https://login.yandex.ru/info?'.\http_build_query([ 'format' => 'json', - 'oauth_token' => $accessToken + 'oauth_token' => $accessToken, ])); $this->user = \json_decode($user, true); } + return $this->user; } } diff --git a/src/Appwrite/Auth/OAuth2/Zoom.php b/src/Appwrite/Auth/OAuth2/Zoom.php index 9dad22212a..01ade69a48 100644 --- a/src/Appwrite/Auth/OAuth2/Zoom.php +++ b/src/Appwrite/Auth/OAuth2/Zoom.php @@ -30,7 +30,7 @@ class Zoom extends OAuth2 * @var array */ protected array $scopes = [ - 'user_info:read' + 'user_info:read', ]; /** @@ -46,7 +46,7 @@ class Zoom extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint . '/oauth/authorize?' . \http_build_query([ + return $this->endpoint.'/oauth/authorize?'.\http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'response_type' => 'code', @@ -56,22 +56,21 @@ class Zoom extends OAuth2 } /** - * @param string $code - * + * @param string $code * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { - $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded']; + $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth/token', + $this->endpoint.'/oauth/token', $headers, \http_build_query([ 'grant_type' => 'authorization_code', 'redirect_uri' => $this->callback, - 'code' => $code + 'code' => $code, ]) ), true); } @@ -80,16 +79,15 @@ class Zoom extends OAuth2 } /** - * @param string $refreshToken - * + * @param string $refreshToken * @return array */ public function refreshTokens(string $refreshToken): array { - $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded']; + $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint . '/oauth/token', + $this->endpoint.'/oauth/token', $headers, \http_build_query([ 'grant_type' => 'refresh_token', @@ -105,8 +103,7 @@ class Zoom extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserID(string $accessToken): string @@ -117,8 +114,7 @@ class Zoom extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserEmail(string $accessToken): string @@ -133,8 +129,7 @@ class Zoom extends OAuth2 * * @link https://marketplace.zoom.us/docs/api-reference/zoom-api/methods/#operation/user * - * @param string $accessToken - * + * @param string $accessToken * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -149,26 +144,24 @@ class Zoom extends OAuth2 } /** - * @param string $accessToken - * + * @param string $accessToken * @return string */ public function getUserName(string $accessToken): string { $response = $this->getUser($accessToken); - return ($response['first_name'] ?? '') . ' ' . ($response['last_name'] ?? ''); + return ($response['first_name'] ?? '').' '.($response['last_name'] ?? ''); } /** - * @param string $accessToken - * + * @param string $accessToken * @return array */ protected function getUser(string $accessToken) { $headers = [ - 'Authorization: Bearer ' . \urlencode($accessToken) + 'Authorization: Bearer '.\urlencode($accessToken), ]; if (empty($this->user)) { diff --git a/src/Appwrite/Auth/Validator/Password.php b/src/Appwrite/Auth/Validator/Password.php index 93a9f74114..e997d03f81 100644 --- a/src/Appwrite/Auth/Validator/Password.php +++ b/src/Appwrite/Auth/Validator/Password.php @@ -26,13 +26,12 @@ class Password extends Validator /** * Is valid. * - * @param mixed $value - * + * @param mixed $value * @return bool */ public function isValid($value): bool { - if (!\is_string($value)) { + if (! \is_string($value)) { return false; } diff --git a/src/Appwrite/Auth/Validator/PasswordDictionary.php b/src/Appwrite/Auth/Validator/PasswordDictionary.php index 003d68bc73..27feeeca36 100644 --- a/src/Appwrite/Auth/Validator/PasswordDictionary.php +++ b/src/Appwrite/Auth/Validator/PasswordDictionary.php @@ -10,6 +10,7 @@ namespace Appwrite\Auth\Validator; class PasswordDictionary extends Password { protected array $dictionary; + protected bool $enabled; public function __construct(array $dictionary, bool $enabled = false) @@ -33,19 +34,19 @@ class PasswordDictionary extends Password /** * Is valid. * - * @param mixed $value - * + * @param mixed $value * @return bool */ public function isValid($value): bool { - if (!parent::isValid($value)) { + if (! parent::isValid($value)) { return false; } if ($this->enabled && array_key_exists($value, $this->dictionary)) { return false; } + return true; } diff --git a/src/Appwrite/Auth/Validator/PasswordHistory.php b/src/Appwrite/Auth/Validator/PasswordHistory.php index 8cfabf4666..d78abe6689 100644 --- a/src/Appwrite/Auth/Validator/PasswordHistory.php +++ b/src/Appwrite/Auth/Validator/PasswordHistory.php @@ -12,7 +12,9 @@ use Appwrite\Auth\Auth; class PasswordHistory extends Password { protected array $history; + protected string $algo; + protected array $algoOptions; public function __construct(array $history, string $algo, array $algoOptions = []) @@ -37,8 +39,7 @@ class PasswordHistory extends Password /** * Is valid. * - * @param mixed $value - * + * @param mixed $value * @return bool */ public function isValid($value): bool @@ -48,6 +49,7 @@ class PasswordHistory extends Password return false; } } + return true; } diff --git a/src/Appwrite/Auth/Validator/PersonalData.php b/src/Appwrite/Auth/Validator/PersonalData.php index 6f8ed0a8c9..911d8f5515 100644 --- a/src/Appwrite/Auth/Validator/PersonalData.php +++ b/src/Appwrite/Auth/Validator/PersonalData.php @@ -31,17 +31,16 @@ class PersonalData extends Password /** * Is valid. * - * @param mixed $value - * + * @param mixed $value * @return bool */ public function isValid($password): bool { - if (!parent::isValid($password)) { + if (! parent::isValid($password)) { return false; } - if (!$this->strict) { + if (! $this->strict) { $password = strtolower($password); $this->userId = strtolower($this->userId); $this->email = strtolower($this->email); diff --git a/src/Appwrite/Auth/Validator/Phone.php b/src/Appwrite/Auth/Validator/Phone.php index 32c3ca3398..49d78ac8c6 100644 --- a/src/Appwrite/Auth/Validator/Phone.php +++ b/src/Appwrite/Auth/Validator/Phone.php @@ -26,13 +26,12 @@ class Phone extends Validator /** * Is valid. * - * @param mixed $value - * + * @param mixed $value * @return bool */ public function isValid($value): bool { - return is_string($value) && !!\preg_match('/^\+[1-9]\d{1,14}$/', $value); + return is_string($value) && (bool) \preg_match('/^\+[1-9]\d{1,14}$/', $value); } /** diff --git a/src/Appwrite/Detector/Detector.php b/src/Appwrite/Detector/Detector.php index 62f7a0a04b..ed1be7325b 100644 --- a/src/Appwrite/Detector/Detector.php +++ b/src/Appwrite/Detector/Detector.php @@ -17,7 +17,7 @@ class Detector protected $detctor; /** - * @param string $userAgent + * @param string $userAgent */ public function __construct(string $userAgent) { @@ -54,7 +54,7 @@ class Detector 'type' => 'desktop', 'short_name' => 'cli', 'name' => 'Appwrite CLI', - 'version' => $version + 'version' => $version, ]; } else { $client = $this->getDetector()->getClient(); @@ -89,7 +89,7 @@ class Detector */ protected function getDetector(): DeviceDetector { - if (!$this->detctor) { + if (! $this->detctor) { $this->detctor = new DeviceDetector($this->userAgent); $this->detctor->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) $this->detctor->parse(); @@ -103,7 +103,7 @@ class Detector * It is needed if we want bots to be processed as a simple clients. So we can detect if it is mobile client, * or desktop, or enything else. By default all this information is not retrieved for the bots. * - * @param bool $skip + * @param bool $skip */ public function skipBotDetection(bool $skip = true): void { diff --git a/src/Appwrite/Docker/Compose.php b/src/Appwrite/Docker/Compose.php index 64441805de..0b4a8b16b9 100644 --- a/src/Appwrite/Docker/Compose.php +++ b/src/Appwrite/Docker/Compose.php @@ -13,7 +13,7 @@ class Compose protected $compose = []; /** - * @var string $data + * @var string */ public function __construct(string $data) { @@ -48,7 +48,7 @@ class Compose */ public function getService(string $name): Service { - if (!isset($this->compose['services'][$name])) { + if (! isset($this->compose['services'][$name])) { throw new Exception('Service not found'); } diff --git a/src/Appwrite/Docker/Compose/Service.php b/src/Appwrite/Docker/Compose/Service.php index a3f9c91253..32c12b82b1 100644 --- a/src/Appwrite/Docker/Compose/Service.php +++ b/src/Appwrite/Docker/Compose/Service.php @@ -12,7 +12,7 @@ class Service protected $service = []; /** - * @var string $path + * @var string */ public function __construct(array $service) { @@ -54,7 +54,8 @@ class Service public function getImageVersion(): string { $image = $this->getImage(); - return substr($image, ((int)strpos($image, ':')) + 1); + + return substr($image, ((int) strpos($image, ':')) + 1); } /** diff --git a/src/Appwrite/Docker/Env.php b/src/Appwrite/Docker/Env.php index bce12a95e6..6351ce4f78 100644 --- a/src/Appwrite/Docker/Env.php +++ b/src/Appwrite/Docker/Env.php @@ -2,8 +2,6 @@ namespace Appwrite\Docker; -use Exception; - class Env { /** @@ -12,7 +10,7 @@ class Env protected $vars = []; /** - * @var string $data + * @var string */ public function __construct(string $data) { @@ -30,9 +28,8 @@ class Env } /** - * @param string $key - * @param mixed $value - * + * @param string $key + * @param mixed $value * @return $this */ public function setVar(string $key, $value): self @@ -43,8 +40,7 @@ class Env } /** - * @param string $key - * + * @param string $key * @return string */ public function getVar(string $key): string @@ -70,7 +66,7 @@ class Env $output = ''; foreach ($this->vars as $key => $value) { - $output .= $key . '=' . $value . "\n"; + $output .= $key.'='.$value."\n"; } return $output; diff --git a/src/Appwrite/Event/Audit.php b/src/Appwrite/Event/Audit.php index 254f7c294a..da396bba17 100644 --- a/src/Appwrite/Event/Audit.php +++ b/src/Appwrite/Event/Audit.php @@ -7,8 +7,11 @@ use Resque; class Audit extends Event { protected string $resource = ''; + protected string $mode = ''; + protected string $userAgent = ''; + protected string $ip = ''; public function __construct() @@ -19,7 +22,7 @@ class Audit extends Event /** * Set resource for this audit event. * - * @param string $resource + * @param string $resource * @return self */ public function setResource(string $resource): self @@ -42,7 +45,7 @@ class Audit extends Event /** * Set mode for this audit event * - * @param string $mode + * @param string $mode * @return self */ public function setMode(string $mode): self @@ -65,7 +68,7 @@ class Audit extends Event /** * Set user agent for this audit event. * - * @param string $userAgent + * @param string $userAgent * @return self */ public function setUserAgent(string $userAgent): self @@ -88,7 +91,7 @@ class Audit extends Event /** * Set IP for this audit event. * - * @param string $ip + * @param string $ip * @return self */ public function setIP(string $ip): self @@ -112,6 +115,7 @@ class Audit extends Event * Executes the event and sends it to the audit worker. * * @return string|bool + * * @throws \InvalidArgumentException */ public function trigger(): string|bool diff --git a/src/Appwrite/Event/Build.php b/src/Appwrite/Event/Build.php index 4d4b338118..92e4659dd7 100644 --- a/src/Appwrite/Event/Build.php +++ b/src/Appwrite/Event/Build.php @@ -8,7 +8,9 @@ use Utopia\Database\Document; class Build extends Event { protected string $type = ''; + protected ?Document $resource = null; + protected ?Document $deployment = null; public function __construct() @@ -19,7 +21,7 @@ class Build extends Event /** * Sets resource document for the build event. * - * @param Document $resource + * @param Document $resource * @return self */ public function setResource(Document $resource): self @@ -42,7 +44,7 @@ class Build extends Event /** * Sets deployment for the build event. * - * @param Document $deployment + * @param Document $deployment * @return self */ public function setDeployment(Document $deployment): self @@ -65,7 +67,7 @@ class Build extends Event /** * Sets type for the build event. * - * @param string $type Can be `BUILD_TYPE_DEPLOYMENT` or `BUILD_TYPE_RETRY`. + * @param string $type Can be `BUILD_TYPE_DEPLOYMENT` or `BUILD_TYPE_RETRY`. * @return self */ public function setType(string $type): self @@ -89,6 +91,7 @@ class Build extends Event * Executes the function event and sends it to the functions worker. * * @return string|bool + * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -97,7 +100,7 @@ class Build extends Event 'project' => $this->project, 'resource' => $this->resource, 'deployment' => $this->deployment, - 'type' => $this->type + 'type' => $this->type, ]); } } diff --git a/src/Appwrite/Event/Certificate.php b/src/Appwrite/Event/Certificate.php index d3d9091804..c39adbed8f 100644 --- a/src/Appwrite/Event/Certificate.php +++ b/src/Appwrite/Event/Certificate.php @@ -8,6 +8,7 @@ use Utopia\Database\Document; class Certificate extends Event { protected bool $skipRenewCheck = false; + protected ?Document $domain = null; public function __construct() @@ -18,7 +19,7 @@ class Certificate extends Event /** * Set domain for this certificates event. * - * @param Document $domain + * @param Document $domain * @return self */ public function setDomain(Document $domain): self @@ -41,7 +42,7 @@ class Certificate extends Event /** * Set if the certificate needs to be validated. * - * @param bool $skipRenewCheck + * @param bool $skipRenewCheck * @return self */ public function setSkipRenewCheck(bool $skipRenewCheck): self @@ -65,6 +66,7 @@ class Certificate extends Event * Executes the event and sends it to the certificates worker. * * @return string|bool + * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -72,7 +74,7 @@ class Certificate extends Event return Resque::enqueue($this->queue, $this->class, [ 'project' => $this->project, 'domain' => $this->domain, - 'skipRenewCheck' => $this->skipRenewCheck + 'skipRenewCheck' => $this->skipRenewCheck, ]); } } diff --git a/src/Appwrite/Event/Database.php b/src/Appwrite/Event/Database.php index 1822f06c71..cc83263d71 100644 --- a/src/Appwrite/Event/Database.php +++ b/src/Appwrite/Event/Database.php @@ -8,8 +8,11 @@ use Utopia\Database\Document; class Database extends Event { protected string $type = ''; + protected ?Document $database = null; + protected ?Document $collection = null; + protected ?Document $document = null; public function __construct() @@ -20,7 +23,7 @@ class Database extends Event /** * Sets the type for this database event (use the constants starting with DATABASE_TYPE_*). * - * @param string $type + * @param string $type * @return self */ public function setType(string $type): self @@ -32,6 +35,7 @@ class Database extends Event /** * Returns the set type for the database event. + * * @return string */ public function getType(): string @@ -42,19 +46,20 @@ class Database extends Event /** * Set the database for this event * - * @param Document $database + * @param Document $database * @return self */ public function setDatabase(Document $database): self { $this->database = $database; + return $this; } /** * Set the collection for this database event. * - * @param Document $collection + * @param Document $collection * @return self */ public function setCollection(Document $collection): self @@ -77,7 +82,7 @@ class Database extends Event /** * Set the document for this database event. * - * @param Document $document + * @param Document $document * @return self */ public function setDocument(Document $document): self @@ -89,6 +94,7 @@ class Database extends Event /** * Returns set document for this database event. + * * @return null|Document */ public function getDocument(): ?Document @@ -100,6 +106,7 @@ class Database extends Event * Executes the event and send it to the database worker. * * @return string|bool + * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -111,7 +118,7 @@ class Database extends Event 'collection' => $this->collection, 'document' => $this->document, 'database' => $this->database, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) + 'events' => Event::generateEvents($this->getEvent(), $this->getParams()), ]); } } diff --git a/src/Appwrite/Event/Delete.php b/src/Appwrite/Event/Delete.php index d1519121a6..dee01ed6bf 100644 --- a/src/Appwrite/Event/Delete.php +++ b/src/Appwrite/Event/Delete.php @@ -8,11 +8,14 @@ use Utopia\Database\Document; class Delete extends Event { protected string $type = ''; - protected ?Document $document = null; - protected ?string $resource = null; - protected ?string $datetime = null; - protected ?string $hourlyUsageRetentionDatetime = null; + protected ?Document $document = null; + + protected ?string $resource = null; + + protected ?string $datetime = null; + + protected ?string $hourlyUsageRetentionDatetime = null; public function __construct() { @@ -22,7 +25,7 @@ class Delete extends Event /** * Sets the type for the delete event (use the constants starting with DELETE_TYPE_*). * - * @param string $type + * @param string $type * @return self */ public function setType(string $type): self @@ -45,31 +48,33 @@ class Delete extends Event /** * set Datetime. * - * @param string $datetime + * @param string $datetime * @return self */ public function setDatetime(string $datetime): self { $this->datetime = $datetime; + return $this; } /** * Sets datetime for 1h interval. * - * @param string $datetime + * @param string $datetime * @return self */ public function setUsageRetentionHourlyDateTime(string $datetime): self { $this->hourlyUsageRetentionDatetime = $datetime; + return $this; } /** * Sets the document for the delete event. * - * @param Document $document + * @param Document $document * @return self */ public function setDocument(Document $document): self @@ -92,7 +97,7 @@ class Delete extends Event /** * Sets the resource for the delete event. * - * @param string $resource + * @param string $resource * @return self */ public function setResource(string $resource): self @@ -112,11 +117,11 @@ class Delete extends Event return $this->document; } - /** * Executes this event and sends it to the deletes worker. * * @return string|bool + * * @throws \InvalidArgumentException */ public function trigger(): string|bool diff --git a/src/Appwrite/Event/Event.php b/src/Appwrite/Event/Event.php index 23dde49637..0000cc482d 100644 --- a/src/Appwrite/Event/Event.php +++ b/src/Appwrite/Event/Event.php @@ -9,51 +9,70 @@ use Utopia\Database\Document; class Event { public const DATABASE_QUEUE_NAME = 'v1-database'; + public const DATABASE_CLASS_NAME = 'DatabaseV1'; public const DELETE_QUEUE_NAME = 'v1-deletes'; + public const DELETE_CLASS_NAME = 'DeletesV1'; public const AUDITS_QUEUE_NAME = 'v1-audits'; + public const AUDITS_CLASS_NAME = 'AuditsV1'; public const MAILS_QUEUE_NAME = 'v1-mails'; + public const MAILS_CLASS_NAME = 'MailsV1'; public const FUNCTIONS_QUEUE_NAME = 'v1-functions'; + public const FUNCTIONS_CLASS_NAME = 'FunctionsV1'; public const USAGE_QUEUE_NAME = 'v1-usage'; + public const USAGE_CLASS_NAME = 'UsageV1'; public const WEBHOOK_QUEUE_NAME = 'v1-webhooks'; + public const WEBHOOK_CLASS_NAME = 'WebhooksV1'; public const CERTIFICATES_QUEUE_NAME = 'v1-certificates'; + public const CERTIFICATES_CLASS_NAME = 'CertificatesV1'; public const BUILDS_QUEUE_NAME = 'v1-builds'; + public const BUILDS_CLASS_NAME = 'BuildsV1'; public const MESSAGING_QUEUE_NAME = 'v1-messaging'; + public const MESSAGING_CLASS_NAME = 'MessagingV1'; public const MIGRATIONS_QUEUE_NAME = 'v1-migrations'; + public const MIGRATIONS_CLASS_NAME = 'MigrationsV1'; protected string $queue = ''; + protected string $class = ''; + protected string $event = ''; + protected array $params = []; + protected array $payload = []; + protected array $context = []; + protected ?Document $project = null; + protected ?Document $user = null; + protected bool $paused = false; /** - * @param string $queue - * @param string $class + * @param string $queue + * @param string $class * @return void */ public function __construct(string $queue, string $class) @@ -65,7 +84,7 @@ class Event /** * Set queue used for this event. * - * @param string $queue + * @param string $queue * @return Event */ public function setQueue(string $queue): self @@ -87,7 +106,8 @@ class Event /** * Set event name used for this event. - * @param string $event + * + * @param string $event * @return Event */ public function setEvent(string $event): self @@ -110,7 +130,7 @@ class Event /** * Set project for this event. * - * @param Document $project + * @param Document $project * @return self */ public function setProject(Document $project): self @@ -133,7 +153,7 @@ class Event /** * Set user for this event. * - * @param Document $user + * @param Document $user * @return self */ public function setUser(Document $user): self @@ -156,7 +176,7 @@ class Event /** * Set payload for this event. * - * @param array $payload + * @param array $payload * @return self */ public function setPayload(array $payload): self @@ -179,8 +199,8 @@ class Event /** * Set context for this event. * - * @param string $key - * @param Document $context + * @param string $key + * @param Document $context * @return self */ public function setContext(string $key, Document $context): self @@ -193,8 +213,7 @@ class Event /** * Get context for this event. * - * @param string $key - * + * @param string $key * @return null|Document */ public function getContext(string $key): ?Document @@ -204,7 +223,8 @@ class Event /** * Set class used for this event. - * @param string $class + * + * @param string $class * @return self */ public function setClass(string $class): self @@ -227,8 +247,8 @@ class Event /** * Set param of event. * - * @param string $key - * @param mixed $value + * @param string $key + * @param mixed $value * @return self */ public function setParam(string $key, mixed $value): self @@ -241,7 +261,7 @@ class Event /** * Get param of event. * - * @param string $key + * @param string $key * @return mixed */ public function getParam(string $key): mixed @@ -263,6 +283,7 @@ class Event * Execute Event. * * @return string|bool + * * @throws InvalidArgumentException */ public function trigger(): string|bool @@ -276,7 +297,7 @@ class Event 'user' => $this->user, 'payload' => $this->payload, 'context' => $this->context, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) + 'events' => Event::generateEvents($this->getEvent(), $this->getParams()), ]); } @@ -295,7 +316,7 @@ class Event /** * Parses event pattern and returns the parts in their respective section. * - * @param string $pattern + * @param string $pattern * @return array */ public static function parseEventPattern(string $pattern): array @@ -324,13 +345,13 @@ class Event } } - if ($hasSubResource && !$hasSubSubResource) { + if ($hasSubResource && ! $hasSubSubResource) { if ($count === 6) { $attribute = $parts[5]; } } - if (!$hasSubResource) { + if (! $hasSubResource) { if ($count === 4) { $attribute = $parts[3]; } @@ -342,7 +363,7 @@ class Event $subSubResource ??= false; $attribute ??= false; $action = match (true) { - !$hasSubResource && $count > 2 => $parts[2], + ! $hasSubResource && $count > 2 => $parts[2], $hasSubSubResource => $parts[6] ?? false, $hasSubResource && $count > 4 => $parts[4], default => false @@ -363,9 +384,10 @@ class Event /** * Generates all possible events from a pattern. * - * @param string $pattern - * @param array $params + * @param string $pattern + * @param array $params * @return array + * * @throws \InvalidArgumentException */ public static function generateEvents(string $pattern, array $params = []): array @@ -386,15 +408,15 @@ class Event $action = $parsed['action']; $attribute = $parsed['attribute']; - if ($resource && !\in_array(\trim($resource, "\[\]"), $paramKeys)) { + if ($resource && ! \in_array(\trim($resource, "\[\]"), $paramKeys)) { throw new InvalidArgumentException("{$resource} is missing from the params."); } - if ($subResource && !\in_array(\trim($subResource, "\[\]"), $paramKeys)) { + if ($subResource && ! \in_array(\trim($subResource, "\[\]"), $paramKeys)) { throw new InvalidArgumentException("{$subResource} is missing from the params."); } - if ($subSubResource && !\in_array(\trim($subSubResource, "\[\]"), $paramKeys)) { + if ($subSubResource && ! \in_array(\trim($subSubResource, "\[\]"), $paramKeys)) { throw new InvalidArgumentException("{$subSubResource} is missing from the params."); } @@ -448,9 +470,9 @@ class Event if ($subCurrent === $current || $subCurrent === $key) { continue; } - $filtered1 = \array_filter($paramKeys, fn(string $k) => $k === $subCurrent); + $filtered1 = \array_filter($paramKeys, fn (string $k) => $k === $subCurrent); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered1, '*', $eventPattern)); - $filtered2 = \array_filter($paramKeys, fn(string $k) => $k === $current); + $filtered2 = \array_filter($paramKeys, fn (string $k) => $k === $current); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered2, '*', \str_replace($filtered1, '*', $eventPattern))); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered2, '*', $eventPattern)); } @@ -458,7 +480,7 @@ class Event if ($current === $key) { continue; } - $filtered = \array_filter($paramKeys, fn(string $k) => $k === $current); + $filtered = \array_filter($paramKeys, fn (string $k) => $k === $current); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered, '*', $eventPattern)); } } diff --git a/src/Appwrite/Event/Func.php b/src/Appwrite/Event/Func.php index d121b47a4a..dea2381cda 100644 --- a/src/Appwrite/Event/Func.php +++ b/src/Appwrite/Event/Func.php @@ -9,9 +9,13 @@ use Utopia\Queue\Connection; class Func extends Event { protected string $jwt = ''; + protected string $type = ''; + protected string $data = ''; + protected ?Document $function = null; + protected ?Document $execution = null; public function __construct(protected Connection $connection) @@ -22,7 +26,7 @@ class Func extends Event /** * Sets function document for the function event. * - * @param Document $function + * @param Document $function * @return self */ public function setFunction(Document $function): self @@ -45,7 +49,7 @@ class Func extends Event /** * Sets execution for the function event. * - * @param Document $execution + * @param Document $execution * @return self */ public function setExecution(Document $execution): self @@ -68,7 +72,7 @@ class Func extends Event /** * Sets type for the function event. * - * @param string $type Can be `schedule`, `event` or `http`. + * @param string $type Can be `schedule`, `event` or `http`. * @return self */ public function setType(string $type): self @@ -91,7 +95,7 @@ class Func extends Event /** * Sets custom data for the function event. * - * @param string $data + * @param string $data * @return self */ public function setData(string $data): self @@ -114,7 +118,7 @@ class Func extends Event /** * Sets JWT for the function event. * - * @param string $jwt + * @param string $jwt * @return self */ public function setJWT(string $jwt): self @@ -138,6 +142,7 @@ class Func extends Event * Executes the function event and sends it to the functions worker. * * @return string|bool + * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -166,10 +171,8 @@ class Func extends Event /** * Generate a function event from a base event * - * @param Event $event - * + * @param Event $event * @return self - * */ public function from(Event $event): self { @@ -178,6 +181,7 @@ class Func extends Event $this->payload = $event->getPayload(); $this->event = $event->getEvent(); $this->params = $event->getParams(); + return $this; } } diff --git a/src/Appwrite/Event/Mail.php b/src/Appwrite/Event/Mail.php index 37b42704c5..68a6cfe2a3 100644 --- a/src/Appwrite/Event/Mail.php +++ b/src/Appwrite/Event/Mail.php @@ -3,15 +3,19 @@ namespace Appwrite\Event; use Resque; -use Utopia\Database\Document; class Mail extends Event { protected string $recipient = ''; + protected string $from = ''; + protected string $name = ''; + protected string $subject = ''; + protected string $body = ''; + protected array $smtp = []; public function __construct() @@ -22,7 +26,7 @@ class Mail extends Event /** * Sets subject for the mail event. * - * @param string $subject + * @param string $subject * @return self */ public function setSubject(string $subject): self @@ -45,7 +49,7 @@ class Mail extends Event /** * Sets recipient for the mail event. * - * @param string $recipient + * @param string $recipient * @return self */ public function setRecipient(string $recipient): self @@ -68,7 +72,7 @@ class Mail extends Event /** * Sets from for the mail event. * - * @param string $from + * @param string $from * @return self */ public function setFrom(string $from): self @@ -91,7 +95,7 @@ class Mail extends Event /** * Sets body for the mail event. * - * @param string $body + * @param string $body * @return self */ public function setBody(string $body): self @@ -114,7 +118,7 @@ class Mail extends Event /** * Sets name for the mail event. * - * @param string $name + * @param string $name * @return self */ public function setName(string $name): self @@ -137,12 +141,13 @@ class Mail extends Event /** * Set SMTP Host * - * @param string $host + * @param string $host * @return self */ public function setSmtpHost(string $host): self { $this->smtp['host'] = $host; + return $this; } @@ -155,54 +160,59 @@ class Mail extends Event public function setSmtpPort(int $port): self { $this->smtp['port'] = $port; + return $this; } /** * Set SMTP username * - * @param string $username + * @param string $username * @return self */ public function setSmtpUsername(string $username): self { $this->smtp['username']; + return $this; } /** * Set SMTP password * - * @param string $password + * @param string $password * @return self */ public function setSmtpPassword(string $password): self { $this->smtp['password']; + return $this; } /** * Set SMTP sender email * - * @param string $senderEmail + * @param string $senderEmail * @return self */ public function setSmtpSenderEmail(string $senderEmail): self { $this->smtp['senderEmail'] = $senderEmail; + return $this; } /** * Set SMTP reply to * - * @param string $replyTo + * @param string $replyTo * @return self */ public function setSmtpReplyTo(string $replyTo): self { $this->smtp['replyTo'] = $replyTo; + return $this; } @@ -219,7 +229,7 @@ class Mail extends Event /** * Get SMTP port * - * @return integer + * @return int */ public function getSmtpPort(): int { @@ -270,6 +280,7 @@ class Mail extends Event * Executes the event and sends it to the mails worker. * * @return string|bool + * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -281,7 +292,7 @@ class Mail extends Event 'subject' => $this->subject, 'body' => $this->body, 'smtp' => $this->smtp, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) + 'events' => Event::generateEvents($this->getEvent(), $this->getParams()), ]); } } diff --git a/src/Appwrite/Event/Migration.php b/src/Appwrite/Event/Migration.php index 4d53f16796..ebe15483d0 100644 --- a/src/Appwrite/Event/Migration.php +++ b/src/Appwrite/Event/Migration.php @@ -10,6 +10,7 @@ use Utopia\Database\Document; class Migration extends Event { protected string $type = ''; + protected ?Document $migration = null; public function __construct() @@ -20,7 +21,7 @@ class Migration extends Event /** * Sets migration document for the migration event. * - * @param Document $migration + * @param Document $migration * @return self */ public function setMigration(Document $migration): self @@ -43,8 +44,7 @@ class Migration extends Event /** * Sets migration type for the migration event. * - * @param string $type - * + * @param string $type * @return self */ public function setType(string $type): self @@ -68,6 +68,7 @@ class Migration extends Event * Executes the migration event and sends it to the migrations worker. * * @return string|bool + * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -75,15 +76,16 @@ class Migration extends Event return Resque::enqueue($this->queue, $this->class, [ 'project' => $this->project, 'user' => $this->user, - 'migration' => $this->migration + 'migration' => $this->migration, ]); } /** * Schedules the migration event and schedules it in the migrations worker queue. * - * @param \DateTime|int $at + * @param \DateTime|int $at * @return void + * * @throws \Resque_Exception * @throws \ResqueScheduler_InvalidTimestampException */ @@ -92,7 +94,7 @@ class Migration extends Event ResqueScheduler::enqueueAt($at, $this->queue, $this->class, [ 'project' => $this->project, 'user' => $this->user, - 'migration' => $this->migration + 'migration' => $this->migration, ]); } } diff --git a/src/Appwrite/Event/Phone.php b/src/Appwrite/Event/Phone.php index 8baa5120c9..87bee4bc37 100644 --- a/src/Appwrite/Event/Phone.php +++ b/src/Appwrite/Event/Phone.php @@ -7,6 +7,7 @@ use Resque; class Phone extends Event { protected string $recipient = ''; + protected string $message = ''; public function __construct() @@ -17,7 +18,7 @@ class Phone extends Event /** * Sets recipient for the messaging event. * - * @param string $recipient + * @param string $recipient * @return self */ public function setRecipient(string $recipient): self @@ -40,7 +41,7 @@ class Phone extends Event /** * Sets url for the messaging event. * - * @param string $message + * @param string $message * @return self */ public function setMessage(string $message): self @@ -64,6 +65,7 @@ class Phone extends Event * Executes the event and sends it to the messaging worker. * * @return string|bool + * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -74,7 +76,7 @@ class Phone extends Event 'payload' => $this->payload, 'recipient' => $this->recipient, 'message' => $this->message, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) + 'events' => Event::generateEvents($this->getEvent(), $this->getParams()), ]); } } diff --git a/src/Appwrite/Event/Usage.php b/src/Appwrite/Event/Usage.php index b302b88808..01f576896b 100644 --- a/src/Appwrite/Event/Usage.php +++ b/src/Appwrite/Event/Usage.php @@ -2,14 +2,15 @@ namespace Appwrite\Event; +use Utopia\Database\Document; use Utopia\Queue\Client; use Utopia\Queue\Connection; -use Utopia\Database\Document; class Usage extends Event { protected array $metrics = []; - protected array $reduce = []; + + protected array $reduce = []; public function __construct(protected Connection $connection) { @@ -19,7 +20,7 @@ class Usage extends Event /** * Add reduce. * - * @param Document $document + * @param Document $document * @return self */ public function addReduce(Document $document): self @@ -32,8 +33,8 @@ class Usage extends Event /** * Add metric. * - * @param string $key - * @param int $value + * @param string $key + * @param int $value * @return self */ public function addMetric(string $key, int $value): self @@ -57,7 +58,7 @@ class Usage extends Event return $client->enqueue([ 'project' => $this->getProject(), - 'reduce' => $this->reduce, + 'reduce' => $this->reduce, 'metrics' => $this->metrics, ]); } diff --git a/src/Appwrite/Event/Validator/Event.php b/src/Appwrite/Event/Validator/Event.php index 3f22900486..7e8ef316cc 100644 --- a/src/Appwrite/Event/Validator/Event.php +++ b/src/Appwrite/Event/Validator/Event.php @@ -27,8 +27,7 @@ class Event extends Validator /** * Is valid. * - * @param mixed $value - * + * @param mixed $value * @return bool */ public function isValid($value): bool @@ -48,6 +47,7 @@ class Event extends Validator if ($type == 'functions') { $this->message = 'Triggering a function on a function event is not allowed.'; + return false; } @@ -55,7 +55,7 @@ class Event extends Validator $hasSubResource = $count > 3 && ($events[$type]['$resource'] ?? false) && ($events[$type][$parts[2]]['$resource'] ?? false); $hasSubSubResource = $count > 5 && $hasSubResource && ($events[$type][$parts[2]][$parts[4]]['$resource'] ?? false); - if (!$type || !$resource) { + if (! $type || ! $resource) { return false; } @@ -72,13 +72,13 @@ class Event extends Validator } } - if ($hasSubResource && !$hasSubSubResource) { + if ($hasSubResource && ! $hasSubSubResource) { if ($count === 6) { $attribute = $parts[5]; } } - if (!$hasSubResource) { + if (! $hasSubResource) { if ($count === 4) { $attribute = $parts[3]; } @@ -91,36 +91,36 @@ class Event extends Validator $attribute ??= false; $action = match (true) { - !$hasSubResource && $count > 2 => $parts[2], + ! $hasSubResource && $count > 2 => $parts[2], $hasSubSubResource => $parts[6] ?? false, $hasSubResource && $count > 4 => $parts[4], default => false }; - if (!\array_key_exists($type, $events)) { + if (! \array_key_exists($type, $events)) { return false; } if ($subType) { - if ($action && !\array_key_exists($action, $events[$type][$subType])) { + if ($action && ! \array_key_exists($action, $events[$type][$subType])) { return false; } - if (!($subResource) || !\array_key_exists($subType, $events[$type])) { + if (! ($subResource) || ! \array_key_exists($subType, $events[$type])) { return false; } } else { - if ($action && !\array_key_exists($action, $events[$type])) { + if ($action && ! \array_key_exists($action, $events[$type])) { return false; } } if ($attribute) { if (($subType)) { - if (!\array_key_exists($attribute, $events[$type][$subType][$action])) { + if (! \array_key_exists($attribute, $events[$type][$subType][$action])) { return false; } } else { - if (!\array_key_exists($attribute, $events[$type][$action])) { + if (! \array_key_exists($attribute, $events[$type][$action])) { return false; } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index d5803f5fbf..4b1be708c3 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -36,187 +36,295 @@ class Exception extends \Exception */ /** General */ - public const GENERAL_UNKNOWN = 'general_unknown'; - public const GENERAL_MOCK = 'general_mock'; - public const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; - public const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; - public const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; - public const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; - public const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; - public const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; - public const GENERAL_PHONE_DISABLED = 'general_phone_disabled'; - public const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; - public const GENERAL_QUERY_LIMIT_EXCEEDED = 'general_query_limit_exceeded'; - public const GENERAL_QUERY_INVALID = 'general_query_invalid'; - public const GENERAL_ROUTE_NOT_FOUND = 'general_route_not_found'; - public const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found'; - public const GENERAL_SERVER_ERROR = 'general_server_error'; - public const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported'; - public const GENERAL_CODES_DISABLED = 'general_codes_disabled'; - public const GENERAL_USAGE_DISABLED = 'general_usage_disabled'; + public const GENERAL_UNKNOWN = 'general_unknown'; + + public const GENERAL_MOCK = 'general_mock'; + + public const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; + + public const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; + + public const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; + + public const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; + + public const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; + + public const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; + + public const GENERAL_PHONE_DISABLED = 'general_phone_disabled'; + + public const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; + + public const GENERAL_QUERY_LIMIT_EXCEEDED = 'general_query_limit_exceeded'; + + public const GENERAL_QUERY_INVALID = 'general_query_invalid'; + + public const GENERAL_ROUTE_NOT_FOUND = 'general_route_not_found'; + + public const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found'; + + public const GENERAL_SERVER_ERROR = 'general_server_error'; + + public const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported'; + + public const GENERAL_CODES_DISABLED = 'general_codes_disabled'; + + public const GENERAL_USAGE_DISABLED = 'general_usage_disabled'; /** Users */ - public const USER_COUNT_EXCEEDED = 'user_count_exceeded'; - public const USER_JWT_INVALID = 'user_jwt_invalid'; - public const USER_ALREADY_EXISTS = 'user_already_exists'; - public const USER_BLOCKED = 'user_blocked'; - public const USER_INVALID_TOKEN = 'user_invalid_token'; - public const USER_PASSWORD_RESET_REQUIRED = 'user_password_reset_required'; - public const USER_EMAIL_NOT_WHITELISTED = 'user_email_not_whitelisted'; - public const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; - public const USER_INVALID_CODE = 'user_invalid_code'; - public const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; + public const USER_COUNT_EXCEEDED = 'user_count_exceeded'; + + public const USER_JWT_INVALID = 'user_jwt_invalid'; + + public const USER_ALREADY_EXISTS = 'user_already_exists'; + + public const USER_BLOCKED = 'user_blocked'; + + public const USER_INVALID_TOKEN = 'user_invalid_token'; + + public const USER_PASSWORD_RESET_REQUIRED = 'user_password_reset_required'; + + public const USER_EMAIL_NOT_WHITELISTED = 'user_email_not_whitelisted'; + + public const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; + + public const USER_INVALID_CODE = 'user_invalid_code'; + + public const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; + public const USER_ANONYMOUS_CONSOLE_PROHIBITED = 'user_anonymous_console_prohibited'; - public const USER_SESSION_ALREADY_EXISTS = 'user_session_already_exists'; - public const USER_NOT_FOUND = 'user_not_found'; - public const USER_PASSWORD_RECENTLY_USED = 'password_recently_used'; - public const USER_PASSWORD_PERSONAL_DATA = 'password_personal_data'; - public const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; - public const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; - public const USER_SESSION_NOT_FOUND = 'user_session_not_found'; - public const USER_IDENTITY_NOT_FOUND = 'user_identity_not_found'; - public const USER_UNAUTHORIZED = 'user_unauthorized'; - public const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; - public const USER_PHONE_ALREADY_EXISTS = 'user_phone_already_exists'; - public const USER_PHONE_NOT_FOUND = 'user_phone_not_found'; - public const USER_MISSING_ID = 'user_missing_id'; - public const USER_OAUTH2_BAD_REQUEST = 'user_oauth2_bad_request'; - public const USER_OAUTH2_UNAUTHORIZED = 'user_oauth2_unauthorized'; - public const USER_OAUTH2_PROVIDER_ERROR = 'user_oauth2_provider_error'; - public const USER_TARGET_NOT_FOUND = 'user_target_not_found'; - public const USER_TARGET_ALREADY_EXISTS = 'user_target_already_exists'; + + public const USER_SESSION_ALREADY_EXISTS = 'user_session_already_exists'; + + public const USER_NOT_FOUND = 'user_not_found'; + + public const USER_PASSWORD_RECENTLY_USED = 'password_recently_used'; + + public const USER_PASSWORD_PERSONAL_DATA = 'password_personal_data'; + + public const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; + + public const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; + + public const USER_SESSION_NOT_FOUND = 'user_session_not_found'; + + public const USER_IDENTITY_NOT_FOUND = 'user_identity_not_found'; + + public const USER_UNAUTHORIZED = 'user_unauthorized'; + + public const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; + + public const USER_PHONE_ALREADY_EXISTS = 'user_phone_already_exists'; + + public const USER_PHONE_NOT_FOUND = 'user_phone_not_found'; + + public const USER_MISSING_ID = 'user_missing_id'; + + public const USER_OAUTH2_BAD_REQUEST = 'user_oauth2_bad_request'; + + public const USER_OAUTH2_UNAUTHORIZED = 'user_oauth2_unauthorized'; + + public const USER_OAUTH2_PROVIDER_ERROR = 'user_oauth2_provider_error'; + + public const USER_TARGET_NOT_FOUND = 'user_target_not_found'; + + public const USER_TARGET_ALREADY_EXISTS = 'user_target_already_exists'; + /** Teams */ - public const TEAM_NOT_FOUND = 'team_not_found'; - public const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; - public const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; - public const TEAM_INVALID_SECRET = 'team_invalid_secret'; - public const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; - public const TEAM_INVITE_MISMATCH = 'team_invite_mismatch'; - public const TEAM_ALREADY_EXISTS = 'team_already_exists'; + public const TEAM_NOT_FOUND = 'team_not_found'; + + public const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; + + public const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; + + public const TEAM_INVALID_SECRET = 'team_invalid_secret'; + + public const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; + + public const TEAM_INVITE_MISMATCH = 'team_invite_mismatch'; + + public const TEAM_ALREADY_EXISTS = 'team_already_exists'; /** Membership */ - public const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; - public const MEMBERSHIP_ALREADY_CONFIRMED = 'membership_already_confirmed'; + public const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; + + public const MEMBERSHIP_ALREADY_CONFIRMED = 'membership_already_confirmed'; /** Avatars */ - public const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; - public const AVATAR_NOT_FOUND = 'avatar_not_found'; - public const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; - public const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; - public const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; + public const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; + + public const AVATAR_NOT_FOUND = 'avatar_not_found'; + + public const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; + + public const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; + + public const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; /** Storage */ - public const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; - public const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; - public const STORAGE_FILE_EMPTY = 'storage_file_empty'; - public const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; - public const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; - public const STORAGE_INVALID_FILE = 'storage_invalid_file'; - public const STORAGE_BUCKET_ALREADY_EXISTS = 'storage_bucket_already_exists'; - public const STORAGE_BUCKET_NOT_FOUND = 'storage_bucket_not_found'; - public const STORAGE_INVALID_CONTENT_RANGE = 'storage_invalid_content_range'; - public const STORAGE_INVALID_RANGE = 'storage_invalid_range'; - public const STORAGE_INVALID_APPWRITE_ID = 'storage_invalid_appwrite_id'; + public const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; + + public const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; + + public const STORAGE_FILE_EMPTY = 'storage_file_empty'; + + public const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; + + public const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; + + public const STORAGE_INVALID_FILE = 'storage_invalid_file'; + + public const STORAGE_BUCKET_ALREADY_EXISTS = 'storage_bucket_already_exists'; + + public const STORAGE_BUCKET_NOT_FOUND = 'storage_bucket_not_found'; + + public const STORAGE_INVALID_CONTENT_RANGE = 'storage_invalid_content_range'; + + public const STORAGE_INVALID_RANGE = 'storage_invalid_range'; + + public const STORAGE_INVALID_APPWRITE_ID = 'storage_invalid_appwrite_id'; /** Functions */ - public const FUNCTION_NOT_FOUND = 'function_not_found'; - public const FUNCTION_RUNTIME_UNSUPPORTED = 'function_runtime_unsupported'; + public const FUNCTION_NOT_FOUND = 'function_not_found'; + + public const FUNCTION_RUNTIME_UNSUPPORTED = 'function_runtime_unsupported'; /** Deployments */ - public const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; + public const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; /** Builds */ - public const BUILD_NOT_FOUND = 'build_not_found'; - public const BUILD_NOT_READY = 'build_not_ready'; - public const BUILD_IN_PROGRESS = 'build_in_progress'; + public const BUILD_NOT_FOUND = 'build_not_found'; + + public const BUILD_NOT_READY = 'build_not_ready'; + + public const BUILD_IN_PROGRESS = 'build_in_progress'; /** Execution */ - public const EXECUTION_NOT_FOUND = 'execution_not_found'; + public const EXECUTION_NOT_FOUND = 'execution_not_found'; /** Databases */ - public const DATABASE_NOT_FOUND = 'database_not_found'; - public const DATABASE_ALREADY_EXISTS = 'database_already_exists'; + public const DATABASE_NOT_FOUND = 'database_not_found'; + + public const DATABASE_ALREADY_EXISTS = 'database_already_exists'; /** Collections */ - public const COLLECTION_NOT_FOUND = 'collection_not_found'; - public const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; - public const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; + public const COLLECTION_NOT_FOUND = 'collection_not_found'; + + public const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; + + public const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; /** Documents */ - public const DOCUMENT_NOT_FOUND = 'document_not_found'; - public const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; - public const DOCUMENT_MISSING_DATA = 'document_missing_data'; - public const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; - public const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; - public const DOCUMENT_UPDATE_CONFLICT = 'document_update_conflict'; - public const DOCUMENT_DELETE_RESTRICTED = 'document_delete_restricted'; + public const DOCUMENT_NOT_FOUND = 'document_not_found'; + + public const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; + + public const DOCUMENT_MISSING_DATA = 'document_missing_data'; + + public const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; + + public const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; + + public const DOCUMENT_UPDATE_CONFLICT = 'document_update_conflict'; + + public const DOCUMENT_DELETE_RESTRICTED = 'document_delete_restricted'; /** Attribute */ - public const ATTRIBUTE_NOT_FOUND = 'attribute_not_found'; - public const ATTRIBUTE_UNKNOWN = 'attribute_unknown'; - public const ATTRIBUTE_NOT_AVAILABLE = 'attribute_not_available'; - public const ATTRIBUTE_FORMAT_UNSUPPORTED = 'attribute_format_unsupported'; - public const ATTRIBUTE_DEFAULT_UNSUPPORTED = 'attribute_default_unsupported'; - public const ATTRIBUTE_ALREADY_EXISTS = 'attribute_already_exists'; - public const ATTRIBUTE_LIMIT_EXCEEDED = 'attribute_limit_exceeded'; - public const ATTRIBUTE_VALUE_INVALID = 'attribute_value_invalid'; - public const ATTRIBUTE_TYPE_INVALID = 'attribute_type_invalid'; + public const ATTRIBUTE_NOT_FOUND = 'attribute_not_found'; + + public const ATTRIBUTE_UNKNOWN = 'attribute_unknown'; + + public const ATTRIBUTE_NOT_AVAILABLE = 'attribute_not_available'; + + public const ATTRIBUTE_FORMAT_UNSUPPORTED = 'attribute_format_unsupported'; + + public const ATTRIBUTE_DEFAULT_UNSUPPORTED = 'attribute_default_unsupported'; + + public const ATTRIBUTE_ALREADY_EXISTS = 'attribute_already_exists'; + + public const ATTRIBUTE_LIMIT_EXCEEDED = 'attribute_limit_exceeded'; + + public const ATTRIBUTE_VALUE_INVALID = 'attribute_value_invalid'; + + public const ATTRIBUTE_TYPE_INVALID = 'attribute_type_invalid'; /** Indexes */ - public const INDEX_NOT_FOUND = 'index_not_found'; - public const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; - public const INDEX_ALREADY_EXISTS = 'index_already_exists'; - public const INDEX_INVALID = 'index_invalid'; + public const INDEX_NOT_FOUND = 'index_not_found'; + + public const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; + + public const INDEX_ALREADY_EXISTS = 'index_already_exists'; + + public const INDEX_INVALID = 'index_invalid'; /** Projects */ - public const PROJECT_NOT_FOUND = 'project_not_found'; - public const PROJECT_UNKNOWN = 'project_unknown'; - public const PROJECT_PROVIDER_DISABLED = 'project_provider_disabled'; - public const PROJECT_PROVIDER_UNSUPPORTED = 'project_provider_unsupported'; - public const PROJECT_ALREADY_EXISTS = 'project_already_exists'; - public const PROJECT_INVALID_SUCCESS_URL = 'project_invalid_success_url'; - public const PROJECT_INVALID_FAILURE_URL = 'project_invalid_failure_url'; - public const PROJECT_RESERVED_PROJECT = 'project_reserved_project'; - public const PROJECT_KEY_EXPIRED = 'project_key_expired'; + public const PROJECT_NOT_FOUND = 'project_not_found'; - public const PROJECT_SMTP_CONFIG_INVALID = 'project_smtp_config_invalid'; + public const PROJECT_UNKNOWN = 'project_unknown'; + + public const PROJECT_PROVIDER_DISABLED = 'project_provider_disabled'; + + public const PROJECT_PROVIDER_UNSUPPORTED = 'project_provider_unsupported'; + + public const PROJECT_ALREADY_EXISTS = 'project_already_exists'; + + public const PROJECT_INVALID_SUCCESS_URL = 'project_invalid_success_url'; + + public const PROJECT_INVALID_FAILURE_URL = 'project_invalid_failure_url'; + + public const PROJECT_RESERVED_PROJECT = 'project_reserved_project'; + + public const PROJECT_KEY_EXPIRED = 'project_key_expired'; + + public const PROJECT_SMTP_CONFIG_INVALID = 'project_smtp_config_invalid'; public const PROJECT_TEMPLATE_DEFAULT_DELETION = 'project_template_default_deletion'; /** Webhooks */ - public const WEBHOOK_NOT_FOUND = 'webhook_not_found'; + public const WEBHOOK_NOT_FOUND = 'webhook_not_found'; /** Keys */ - public const KEY_NOT_FOUND = 'key_not_found'; + public const KEY_NOT_FOUND = 'key_not_found'; /** Variables */ - public const VARIABLE_NOT_FOUND = 'variable_not_found'; - public const VARIABLE_ALREADY_EXISTS = 'variable_already_exists'; + public const VARIABLE_NOT_FOUND = 'variable_not_found'; + + public const VARIABLE_ALREADY_EXISTS = 'variable_already_exists'; /** Platform */ - public const PLATFORM_NOT_FOUND = 'platform_not_found'; + public const PLATFORM_NOT_FOUND = 'platform_not_found'; /** Domain */ - public const DOMAIN_NOT_FOUND = 'domain_not_found'; - public const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; - public const DOMAIN_FORBIDDEN = 'domain_forbidden'; - public const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; - public const DOMAIN_TARGET_INVALID = 'domain_target_invalid'; + public const DOMAIN_NOT_FOUND = 'domain_not_found'; + + public const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; + + public const DOMAIN_FORBIDDEN = 'domain_forbidden'; + + public const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; + + public const DOMAIN_TARGET_INVALID = 'domain_target_invalid'; /** GraphqQL */ - public const GRAPHQL_NO_QUERY = 'graphql_no_query'; - public const GRAPHQL_TOO_MANY_QUERIES = 'graphql_too_many_queries'; + public const GRAPHQL_NO_QUERY = 'graphql_no_query'; + + public const GRAPHQL_TOO_MANY_QUERIES = 'graphql_too_many_queries'; /** Migrations */ - public const MIGRATION_NOT_FOUND = 'migration_not_found'; - public const MIGRATION_ALREADY_EXISTS = 'migration_already_exists'; - public const MIGRATION_IN_PROGRESS = 'migration_in_progress'; + public const MIGRATION_NOT_FOUND = 'migration_not_found'; + + public const MIGRATION_ALREADY_EXISTS = 'migration_already_exists'; + + public const MIGRATION_IN_PROGRESS = 'migration_in_progress'; /** Provider */ - public const PROVIDER_NOT_FOUND = 'provider_not_found'; - public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; + public const PROVIDER_NOT_FOUND = 'provider_not_found'; + + public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; protected $type = ''; + protected $errors = []; public function __construct(string $type = Exception::GENERAL_UNKNOWN, string $message = null, int $code = null, \Throwable $previous = null) @@ -248,8 +356,7 @@ class Exception extends \Exception /** * Set the type of the exception. * - * @param string $type - * + * @param string $type * @return void */ public function setType(string $type): void diff --git a/src/Appwrite/GraphQL/Promises/Adapter.php b/src/Appwrite/GraphQL/Promises/Adapter.php index 86270f2a8b..0051dbe612 100644 --- a/src/Appwrite/GraphQL/Promises/Adapter.php +++ b/src/Appwrite/GraphQL/Promises/Adapter.php @@ -22,14 +22,15 @@ abstract class Adapter implements PromiseAdapter /** * Converts a {@see Promise} into a {@see GQLPromise} * - * @param mixed $thenable + * @param mixed $thenable * @return GQLPromise + * * @throws \Exception */ public function convertThenable(mixed $thenable): GQLPromise { - if (!$thenable instanceof Promise) { - throw new \Exception('Expected instance of Promise got: ' . \gettype($thenable)); + if (! $thenable instanceof Promise) { + throw new \Exception('Expected instance of Promise got: '.\gettype($thenable)); } return new GQLPromise($thenable, $this); @@ -38,9 +39,9 @@ abstract class Adapter implements PromiseAdapter /** * Returns a promise that resolves when the passed in promise resolves. * - * @param GQLPromise $promise - * @param callable|null $onFulfilled - * @param callable|null $onRejected + * @param GQLPromise $promise + * @param callable|null $onFulfilled + * @param callable|null $onRejected * @return GQLPromise */ public function then( @@ -57,7 +58,7 @@ abstract class Adapter implements PromiseAdapter /** * Create a new promise with the given resolver function. * - * @param callable $resolver + * @param callable $resolver * @return GQLPromise */ abstract public function create(callable $resolver): GQLPromise; @@ -65,7 +66,7 @@ abstract class Adapter implements PromiseAdapter /** * Create a new promise that is fulfilled with the given value. * - * @param mixed $value + * @param mixed $value * @return GQLPromise */ abstract public function createFulfilled(mixed $value = null): GQLPromise; @@ -73,7 +74,7 @@ abstract class Adapter implements PromiseAdapter /** * Create a new promise that is rejected with the given reason. * - * @param mixed $reason + * @param mixed $reason * @return GQLPromise */ abstract public function createRejected(mixed $reason): GQLPromise; @@ -81,7 +82,7 @@ abstract class Adapter implements PromiseAdapter /** * Create a new promise that resolves when all passed in promises resolve. * - * @param array $promisesOrValues + * @param array $promisesOrValues * @return GQLPromise */ abstract public function all(array $promisesOrValues): GQLPromise; diff --git a/src/Appwrite/GraphQL/Resolvers.php b/src/Appwrite/GraphQL/Resolvers.php index c143a93554..3c5ba4b310 100644 --- a/src/Appwrite/GraphQL/Resolvers.php +++ b/src/Appwrite/GraphQL/Resolvers.php @@ -15,28 +15,28 @@ class Resolvers /** * Create a resolver for a given API {@see Route}. * - * @param App $utopia - * @param ?Route $route + * @param App $utopia + * @param ?Route $route * @return callable */ public static function api( App $utopia, ?Route $route, - ): callable { - return static fn($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $route, $args, $context, $info) { + ): callable + { + return static fn ($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $route, $args) { /** @var App $utopia */ /** @var Response $response */ /** @var Request $request */ - $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); $path = $route->getPath(); foreach ($args as $key => $value) { - if (\str_contains($path, '/:' . $key)) { - $path = \str_replace(':' . $key, $value, $path); + if (\str_contains($path, '/:'.$key)) { + $path = \str_replace(':'.$key, $value, $path); } } @@ -60,10 +60,10 @@ class Resolvers /** * Create a resolver for a document in a specified database and collection with a specific method type. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param string $methodType + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param string $methodType * @return callable */ public static function document( @@ -71,8 +71,9 @@ class Resolvers string $databaseId, string $collectionId, string $methodType, - ): callable { - return [self::class, 'document' . \ucfirst($methodType)]( + ): callable + { + return [self::class, 'document'.\ucfirst($methodType)]( $utopia, $databaseId, $collectionId @@ -82,10 +83,10 @@ class Resolvers /** * Create a resolver for getting a document in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url * @return callable */ public static function documentGet( @@ -93,9 +94,10 @@ class Resolvers string $databaseId, string $collectionId, callable $url, - ): callable { - return static fn($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { + ): callable + { + return static fn ($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -111,11 +113,11 @@ class Resolvers /** * Create a resolver for listing documents in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url - * @param callable $params + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url + * @param callable $params * @return callable */ public static function documentList( @@ -124,9 +126,10 @@ class Resolvers string $collectionId, callable $url, callable $params, - ): callable { - return static fn($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { + ): callable + { + return static fn ($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -147,11 +150,11 @@ class Resolvers /** * Create a resolver for creating a document in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url - * @param callable $params + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url + * @param callable $params * @return callable */ public static function documentCreate( @@ -160,9 +163,10 @@ class Resolvers string $collectionId, callable $url, callable $params, - ): callable { - return static fn($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { + ): callable + { + return static fn ($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -179,11 +183,11 @@ class Resolvers /** * Create a resolver for updating a document in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url - * @param callable $params + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url + * @param callable $params * @return callable */ public static function documentUpdate( @@ -192,9 +196,10 @@ class Resolvers string $collectionId, callable $url, callable $params, - ): callable { - return static fn($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { + ): callable + { + return static fn ($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -211,10 +216,10 @@ class Resolvers /** * Create a resolver for deleting a document in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url * @return callable */ public static function documentDelete( @@ -222,9 +227,10 @@ class Resolvers string $databaseId, string $collectionId, callable $url, - ): callable { - return static fn($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { + ): callable + { + return static fn ($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -238,14 +244,15 @@ class Resolvers } /** - * @param App $utopia - * @param Request $request - * @param Response $response - * @param callable $resolve - * @param callable $reject - * @param callable|null $beforeResolve - * @param callable|null $beforeReject + * @param App $utopia + * @param Request $request + * @param Response $response + * @param callable $resolve + * @param callable $reject + * @param callable|null $beforeResolve + * @param callable|null $beforeReject * @return void + * * @throws Exception */ private static function resolve( @@ -263,7 +270,7 @@ class Resolvers } $request = clone $request; - $utopia->setResource('request', static fn() => $request); + $utopia->setResource('request', static fn () => $request); $response->setContentType(Response::CONTENT_TYPE_NULL); try { @@ -275,6 +282,7 @@ class Resolvers $e = $beforeReject($e); } $reject($e); + return; } @@ -288,6 +296,7 @@ class Resolvers message: $payload['message'], code: $response->getStatusCode() )); + return; } diff --git a/src/Appwrite/GraphQL/Schema.php b/src/Appwrite/GraphQL/Schema.php index 11f728e571..608369ef80 100644 --- a/src/Appwrite/GraphQL/Schema.php +++ b/src/Appwrite/GraphQL/Schema.php @@ -13,16 +13,17 @@ use Utopia\Route; class Schema { protected static ?GQLSchema $schema = null; + protected static array $dirty = []; /** - * - * @param App $utopia - * @param callable $complexity Function to calculate complexity - * @param callable $attributes Function to get attributes - * @param array $urls Array of functions to get urls for specific method types - * @param array $params Array of functions to build parameters for specific method types + * @param App $utopia + * @param callable $complexity Function to calculate complexity + * @param callable $attributes Function to get attributes + * @param array $urls Array of functions to get urls for specific method types + * @param array $params Array of functions to build parameters for specific method types * @return GQLSchema + * * @throws Exception */ public static function build( @@ -36,7 +37,7 @@ class Schema return $utopia; }); - if (!empty(self::$schema)) { + if (! empty(self::$schema)) { return self::$schema; } @@ -67,12 +68,12 @@ class Schema return static::$schema = new GQLSchema([ 'query' => new ObjectType([ 'name' => 'Query', - 'fields' => $queries + 'fields' => $queries, ]), 'mutation' => new ObjectType([ 'name' => 'Mutation', - 'fields' => $mutations - ]) + 'fields' => $mutations, + ]), ]); } @@ -80,9 +81,10 @@ class Schema * This function iterates all API routes and builds a GraphQL * schema defining types and resolvers for all response models. * - * @param App $utopia - * @param callable $complexity + * @param App $utopia + * @param callable $complexity * @return array + * * @throws Exception */ protected static function api(App $utopia, callable $complexity): array @@ -97,10 +99,9 @@ class Schema foreach ($utopia->getRoutes() as $routes) { foreach ($routes as $route) { /** @var Route $route */ - $namespace = $route->getLabel('sdk.namespace', ''); $method = $route->getLabel('sdk.method', ''); - $name = $namespace . \ucfirst($method); + $name = $namespace.\ucfirst($method); if (empty($name)) { continue; @@ -126,7 +127,7 @@ class Schema return [ 'query' => $queries, - 'mutation' => $mutations + 'mutation' => $mutations, ]; } @@ -134,12 +135,13 @@ class Schema * Iterates all of a projects attributes and builds GraphQL * queries and mutations for the collections they make up. * - * @param App $utopia - * @param callable $complexity - * @param callable $attributes - * @param array $urls - * @param array $params + * @param App $utopia + * @param callable $complexity + * @param callable $attributes + * @param array $urls + * @param array $params * @return array + * * @throws \Exception */ protected static function collections( @@ -155,7 +157,7 @@ class Schema $limit = 1000; $offset = 0; - while (!empty($attrs = $attributes($limit, $offset))) { + while (! empty($attrs = $attributes($limit, $offset))) { foreach ($attrs as $attr) { if ($attr['status'] !== 'available') { continue; @@ -182,7 +184,7 @@ class Schema $objectType = new ObjectType([ 'name' => $collectionId, 'fields' => \array_merge( - ["_id" => ['type' => Type::string()]], + ['_id' => ['type' => Type::string()]], $attributes ), ]); @@ -191,7 +193,7 @@ class Schema Mapper::args('mutate') ); - $queryFields[$collectionId . 'Get'] = [ + $queryFields[$collectionId.'Get'] = [ 'type' => $objectType, 'args' => Mapper::args('id'), 'resolve' => Resolvers::documentGet( @@ -199,9 +201,9 @@ class Schema $databaseId, $collectionId, $urls['get'], - ) + ), ]; - $queryFields[$collectionId . 'List'] = [ + $queryFields[$collectionId.'List'] = [ 'type' => Type::listOf($objectType), 'args' => Mapper::args('list'), 'resolve' => Resolvers::documentList( @@ -214,7 +216,7 @@ class Schema 'complexity' => $complexity, ]; - $mutationFields[$collectionId . 'Create'] = [ + $mutationFields[$collectionId.'Create'] = [ 'type' => $objectType, 'args' => $attributes, 'resolve' => Resolvers::documentCreate( @@ -223,14 +225,14 @@ class Schema $collectionId, $urls['create'], $params['create'], - ) + ), ]; - $mutationFields[$collectionId . 'Update'] = [ + $mutationFields[$collectionId.'Update'] = [ 'type' => $objectType, 'args' => \array_merge( Mapper::args('id'), \array_map( - fn($attr) => $attr['type'] = Type::getNullableType($attr['type']), + fn ($attr) => $attr['type'] = Type::getNullableType($attr['type']), $attributes ) ), @@ -240,9 +242,9 @@ class Schema $collectionId, $urls['update'], $params['update'], - ) + ), ]; - $mutationFields[$collectionId . 'Delete'] = [ + $mutationFields[$collectionId.'Delete'] = [ 'type' => Mapper::model('none'), 'args' => Mapper::args('id'), 'resolve' => Resolvers::documentDelete( @@ -250,7 +252,7 @@ class Schema $databaseId, $collectionId, $urls['delete'], - ) + ), ]; } $offset += $limit; @@ -258,7 +260,7 @@ class Schema return [ 'query' => $queryFields, - 'mutation' => $mutationFields + 'mutation' => $mutationFields, ]; } diff --git a/src/Appwrite/GraphQL/Types.php b/src/Appwrite/GraphQL/Types.php index 279cac2068..b20c4cb32e 100644 --- a/src/Appwrite/GraphQL/Types.php +++ b/src/Appwrite/GraphQL/Types.php @@ -22,6 +22,7 @@ class Types } $type = new Json(); Registry::set(Json::class, $type); + return $type; } @@ -37,6 +38,7 @@ class Types } $type = new Assoc(); Registry::set(Assoc::class, $type); + return $type; } @@ -52,6 +54,7 @@ class Types } $type = new InputFile(); Registry::set(InputFile::class, $type); + return $type; } } diff --git a/src/Appwrite/GraphQL/Types/Assoc.php b/src/Appwrite/GraphQL/Types/Assoc.php index a2099f9b22..58584ff60f 100644 --- a/src/Appwrite/GraphQL/Types/Assoc.php +++ b/src/Appwrite/GraphQL/Types/Assoc.php @@ -2,19 +2,13 @@ namespace Appwrite\GraphQL\Types; -use GraphQL\Language\AST\BooleanValueNode; -use GraphQL\Language\AST\FloatValueNode; -use GraphQL\Language\AST\IntValueNode; -use GraphQL\Language\AST\ListValueNode; use GraphQL\Language\AST\Node; -use GraphQL\Language\AST\ObjectValueNode; -use GraphQL\Language\AST\StringValueNode; -use GraphQL\Type\Definition\ScalarType; // https://github.com/webonyx/graphql-php/issues/129#issuecomment-309366803 class Assoc extends Json { public $name = 'Assoc'; + public $description = 'The `Assoc` scalar type represents associative array values.'; public function serialize($value) diff --git a/src/Appwrite/GraphQL/Types/InputFile.php b/src/Appwrite/GraphQL/Types/InputFile.php index 39fd4e23b3..6d55ab5359 100644 --- a/src/Appwrite/GraphQL/Types/InputFile.php +++ b/src/Appwrite/GraphQL/Types/InputFile.php @@ -9,6 +9,7 @@ use GraphQL\Type\Definition\ScalarType; class InputFile extends ScalarType { public $name = 'InputFile'; + public $description = 'The `InputFile` special type represents a file to be uploaded in the same HTTP request as specified by [graphql-multipart-request-spec](https://github.com/jaydenseric/graphql-multipart-request-spec).'; @@ -24,6 +25,6 @@ class InputFile extends ScalarType public function parseLiteral(Node $valueNode, ?array $variables = null) { - throw new Error('`InputFile` cannot be hardcoded in query, be sure to conform to GraphQL multipart request specification. Instead got: ' . $valueNode->kind, $valueNode); + throw new Error('`InputFile` cannot be hardcoded in query, be sure to conform to GraphQL multipart request specification. Instead got: '.$valueNode->kind, $valueNode); } } diff --git a/src/Appwrite/GraphQL/Types/Json.php b/src/Appwrite/GraphQL/Types/Json.php index 18d27322a1..305432cb90 100644 --- a/src/Appwrite/GraphQL/Types/Json.php +++ b/src/Appwrite/GraphQL/Types/Json.php @@ -15,6 +15,7 @@ use GraphQL\Type\Definition\ScalarType; class Json extends ScalarType { public $name = 'Json'; + public $description = 'The `JSON` scalar type represents JSON values as specified by [ECMA-404](https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).'; @@ -43,8 +44,9 @@ class Json extends ScalarType $value[$field->name->value] = $this->parseLiteral($field->value); } + return $value; - case ($valueNode instanceof ListValueNode): + case $valueNode instanceof ListValueNode: return array_map([$this, 'parseLiteral'], $valueNode->values); default: return null; diff --git a/src/Appwrite/GraphQL/Types/Mapper.php b/src/Appwrite/GraphQL/Types/Mapper.php index 0be60d93dc..1c03074f23 100644 --- a/src/Appwrite/GraphQL/Types/Mapper.php +++ b/src/Appwrite/GraphQL/Types/Mapper.php @@ -16,7 +16,9 @@ use Utopia\Validator\Nullable; class Mapper { private static array $models = []; + private static array $args = []; + private static array $blacklist = [ '/v1/mock', '/v1/graphql', @@ -43,7 +45,7 @@ class Mapper 'permissions' => [ 'type' => Type::listOf(Type::nonNull(Type::string())), 'defaultValue' => [], - ] + ], ], ]; @@ -66,7 +68,7 @@ class Mapper /** * Get the registered default arguments for a given key. * - * @param string $key + * @param string $key * @return array */ public static function args(string $key): array @@ -87,7 +89,7 @@ class Mapper $names = $route->getLabel('sdk.response.model', 'none'); $models = \is_array($names) - ? \array_map(static fn($m) => static::$models[$m], $names) + ? \array_map(static fn ($m) => static::$models[$m], $names) : [static::$models[$names]]; foreach ($models as $model) { @@ -103,7 +105,7 @@ class Mapper $parameterType = Mapper::param( $utopia, $parameter['validator'], - !$parameter['optional'], + ! $parameter['optional'], $parameter['injections'] ); $params[$name] = [ @@ -116,7 +118,7 @@ class Mapper 'type' => $type, 'description' => $description, 'args' => $params, - 'resolve' => Resolvers::api($utopia, $route) + 'resolve' => Resolvers::api($utopia, $route), ]; if ($list) { @@ -130,7 +132,7 @@ class Mapper /** * Get a type from the registry, creating it if it does not already exist. * - * @param string $name + * @param string $name * @return Type */ public static function model(string $name): Type @@ -149,23 +151,23 @@ class Mapper 'description' => 'Additional data', 'resolve' => static function ($object, $args, $context, $info) { $data = \array_filter( - (array)$object, - fn($key) => !\str_starts_with($key, '_'), + (array) $object, + fn ($key) => ! \str_starts_with($key, '_'), ARRAY_FILTER_USE_KEY ); return \json_encode($data, JSON_FORCE_OBJECT); - } + }, ]; } // If model has no properties, explicitly add a 'status' field // because GraphQL requires at least 1 field per type. - if (!$model->isAny() && empty($model->getRules())) { + if (! $model->isAny() && empty($model->getRules())) { $fields['status'] = [ 'type' => Type::string(), 'description' => 'Status', - 'resolve' => static fn($object, $args, $context, $info) => 'OK', + 'resolve' => static fn ($object, $args, $context, $info) => 'OK', ]; } @@ -187,7 +189,7 @@ class Mapper 'description' => $rule['description'], ]; - if (!$rule['required']) { + if (! $rule['required']) { $fields[$escapedKey]['defaultValue'] = $rule['default']; } } @@ -205,11 +207,12 @@ class Mapper /** * Map a {@see Route} parameter to a GraphQL Type * - * @param App $utopia - * @param Validator|callable $validator - * @param bool $required - * @param array $injections + * @param App $utopia + * @param Validator|callable $validator + * @param bool $required + * @param array $injections * @return Type + * * @throws Exception */ public static function param( @@ -228,7 +231,7 @@ class Mapper $validator = $validator->getValidator(); } - switch ((!empty($validator)) ? $validator::class : '') { + switch ((! empty($validator)) ? $validator::class : '') { case 'Appwrite\Network\Validator\CNAME': case 'Appwrite\Task\Validator\Cron': case 'Appwrite\Utopia\Database\Validator\CustomId': @@ -300,7 +303,7 @@ class Mapper break; } - if ($required && !$isNullable) { + if ($required && ! $isNullable) { $type = Type::nonNull($type); } @@ -310,10 +313,11 @@ class Mapper /** * Map an {@see Attribute} to a GraphQL Type * - * @param string $type - * @param bool $array - * @param bool $required + * @param string $type + * @param bool $array + * @param bool $required * @return Type + * * @throws Exception */ public static function attribute(string $type, bool $array, bool $required): Type @@ -349,6 +353,7 @@ class Mapper } $complexModel = self::$models[$type]; + return self::model(\ucfirst($complexModel->getType())); } @@ -389,7 +394,7 @@ class Mapper return static::getHashOptionsImplementation($object); } - throw new Exception('Unknown union type: ' . $name); + throw new Exception('Unknown union type: '.$name); } private static function getAttributeImplementation(array $object): Type diff --git a/src/Appwrite/GraphQL/Types/Registry.php b/src/Appwrite/GraphQL/Types/Registry.php index cd40d5c3e4..325766bb67 100644 --- a/src/Appwrite/GraphQL/Types/Registry.php +++ b/src/Appwrite/GraphQL/Types/Registry.php @@ -11,7 +11,7 @@ class Registry /** * Check if a type exists in the registry. * - * @param string $type + * @param string $type * @return bool */ public static function has(string $type): bool @@ -22,7 +22,7 @@ class Registry /** * Get a type from the registry. * - * @param string $type + * @param string $type * @return Type */ public static function get(string $type): Type @@ -33,8 +33,8 @@ class Registry /** * Set a type in the registry. * - * @param string $type - * @param Type $typeObject + * @param string $type + * @param Type $typeObject */ public static function set(string $type, Type $typeObject): void { diff --git a/src/Appwrite/Messaging/Adapter.php b/src/Appwrite/Messaging/Adapter.php index 27dd7f68eb..794fd9b3ed 100644 --- a/src/Appwrite/Messaging/Adapter.php +++ b/src/Appwrite/Messaging/Adapter.php @@ -5,6 +5,8 @@ namespace Appwrite\Messaging; abstract class Adapter { abstract public function subscribe(string $projectId, mixed $identifier, array $roles, array $channels): void; + abstract public function unsubscribe(mixed $identifier): void; + abstract public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options): void; } diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php index 33fe484c13..2824f948d7 100644 --- a/src/Appwrite/Messaging/Adapter/Realtime.php +++ b/src/Appwrite/Messaging/Adapter/Realtime.php @@ -2,10 +2,10 @@ namespace Appwrite\Messaging\Adapter; -use Utopia\Database\DateTime; -use Utopia\Database\Document; use Appwrite\Messaging\Adapter; use Utopia\App; +use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; @@ -39,20 +39,20 @@ class Realtime extends Adapter /** * Adds a subscription. * - * @param string $projectId - * @param mixed $identifier - * @param array $roles - * @param array $channels + * @param string $projectId + * @param mixed $identifier + * @param array $roles + * @param array $channels * @return void */ public function subscribe(string $projectId, mixed $identifier, array $roles, array $channels): void { - if (!isset($this->subscriptions[$projectId])) { // Init Project + if (! isset($this->subscriptions[$projectId])) { // Init Project $this->subscriptions[$projectId] = []; } foreach ($roles as $role) { - if (!isset($this->subscriptions[$projectId][$role])) { // Add user first connection + if (! isset($this->subscriptions[$projectId][$role])) { // Add user first connection $this->subscriptions[$projectId][$role] = []; } @@ -64,14 +64,14 @@ class Realtime extends Adapter $this->connections[$identifier] = [ 'projectId' => $projectId, 'roles' => $roles, - 'channels' => $channels + 'channels' => $channels, ]; } /** * Removes Subscription. * - * @param mixed $connection + * @param mixed $connection * @return void */ public function unsubscribe(mixed $connection): void @@ -102,9 +102,10 @@ class Realtime extends Adapter /** * Checks if Channel has a subscriber. - * @param string $projectId - * @param string $role - * @param string $channel + * + * @param string $projectId + * @param string $role + * @param string $channel * @return bool */ public function hasSubscriber(string $projectId, string $role, string $channel = ''): bool @@ -122,12 +123,13 @@ class Realtime extends Adapter /** * Sends an event to the Realtime Server - * @param string $projectId - * @param array $payload - * @param string $event - * @param array $channels - * @param array $roles - * @param array $options + * + * @param string $projectId + * @param array $payload + * @param string $event + * @param array $channels + * @param array $roles + * @param array $options * @return void */ public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options = []): void @@ -150,8 +152,8 @@ class Realtime extends Adapter 'events' => $events, 'channels' => $channels, 'timestamp' => DateTime::formatTz(DateTime::now()), - 'payload' => $payload - ] + 'payload' => $payload, + ], ])); } @@ -166,11 +168,10 @@ class Realtime extends Adapter * - 110.201 ms (±2.32%) | 100,000 Connections / 1,000,000 Subscriptions * - 1,121.328 ms (±0.84%) | 1,000,000 Connections / 10,000,000 Subscriptions * - * @param array $event + * @param array $event */ public function getSubscribers(array $event) { - $receivers = []; /** * Check if project has subscriber. @@ -212,8 +213,9 @@ class Realtime extends Adapter /** * Converts the channels from the Query Params into an array. * Also renames the account channel to account.USER_ID and removes all illegal account channel variations. - * @param array $channels - * @param string $userId + * + * @param array $channels + * @param string $userId * @return array */ public static function convertChannels(array $channels, string $userId): array @@ -227,8 +229,8 @@ class Realtime extends Adapter break; case $key === 'account': - if (!empty($userId)) { - $channels['account.' . $userId] = $value; + if (! empty($userId)) { + $channels['account.'.$userId] = $value; } break; } @@ -240,9 +242,9 @@ class Realtime extends Adapter /** * Create channels array based on the event name and payload. * - * @param string $event - * @param Document $payload - * @param Document|null $project + * @param string $event + * @param Document $payload + * @param Document|null $project * @return array */ public static function fromPayload(string $event, Document $payload, Document $project = null, Document $database = null, Document $collection = null, Document $bucket = null): array @@ -257,18 +259,18 @@ class Realtime extends Adapter switch ($parts[0]) { case 'users': $channels[] = 'account'; - $channels[] = 'account.' . $parts[1]; + $channels[] = 'account.'.$parts[1]; $roles = [Role::user(ID::custom($parts[1]))->toString()]; break; case 'teams': if ($parts[2] === 'memberships') { $permissionsChanged = $parts[4] ?? false; $channels[] = 'memberships'; - $channels[] = 'memberships.' . $parts[3]; + $channels[] = 'memberships.'.$parts[3]; } else { $permissionsChanged = $parts[2] === 'create'; $channels[] = 'teams'; - $channels[] = 'teams.' . $parts[1]; + $channels[] = 'teams.'.$parts[1]; } $roles = [Role::team(ID::custom($parts[1]))->toString()]; break; @@ -286,8 +288,8 @@ class Realtime extends Adapter } $channels[] = 'documents'; - $channels[] = 'databases.' . $database->getId() . '.collections.' . $payload->getAttribute('$collectionId') . '.documents'; - $channels[] = 'databases.' . $database->getId() . '.collections.' . $payload->getAttribute('$collectionId') . '.documents.' . $payload->getId(); + $channels[] = 'databases.'.$database->getId().'.collections.'.$payload->getAttribute('$collectionId').'.documents'; + $channels[] = 'databases.'.$database->getId().'.collections.'.$payload->getAttribute('$collectionId').'.documents.'.$payload->getId(); $roles = $collection->getAttribute('documentSecurity', false) ? \array_merge($collection->getRead(), $payload->getRead()) @@ -300,8 +302,8 @@ class Realtime extends Adapter throw new \Exception('Bucket needs to be passed to Realtime for File events in the Storage.'); } $channels[] = 'files'; - $channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files'; - $channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files.' . $payload->getId(); + $channels[] = 'buckets.'.$payload->getAttribute('bucketId').'.files'; + $channels[] = 'buckets.'.$payload->getAttribute('bucketId').'.files.'.$payload->getId(); $roles = $bucket->getAttribute('fileSecurity', false) ? \array_merge($bucket->getRead(), $payload->getRead()) @@ -312,11 +314,11 @@ class Realtime extends Adapter case 'functions': if ($parts[2] === 'executions') { - if (!empty($payload->getRead())) { + if (! empty($payload->getRead())) { $channels[] = 'console'; $channels[] = 'executions'; - $channels[] = 'executions.' . $payload->getId(); - $channels[] = 'functions.' . $payload->getAttribute('functionId'); + $channels[] = 'executions.'.$payload->getId(); + $channels[] = 'functions.'.$payload->getAttribute('functionId'); $roles = $payload->getRead(); } } elseif ($parts[2] === 'deployments') { @@ -332,7 +334,7 @@ class Realtime extends Adapter 'channels' => $channels, 'roles' => $roles, 'permissionsChanged' => $permissionsChanged, - 'projectId' => $projectId + 'projectId' => $projectId, ]; } } diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 9ea3443091..2685d81829 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -2,15 +2,15 @@ namespace Appwrite\Migration; +use Exception; use Swoole\Runtime; -use Utopia\Database\Document; -use Utopia\Database\Database; -use Utopia\Database\Query; +use Utopia\App; use Utopia\CLI\Console; use Utopia\Config\Config; -use Exception; -use Utopia\App; +use Utopia\Database\Database; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; Runtime::enableCoroutine(SWOOLE_HOOK_ALL); @@ -80,26 +80,25 @@ abstract class Migration $this->collections = array_merge([ '_metadata' => [ '$id' => ID::custom('_metadata'), - '$collection' => Database::METADATA + '$collection' => Database::METADATA, ], 'audit' => [ '$id' => ID::custom('audit'), - '$collection' => Database::METADATA + '$collection' => Database::METADATA, ], 'abuse' => [ '$id' => ID::custom('abuse'), - '$collection' => Database::METADATA - ] + '$collection' => Database::METADATA, + ], ], Config::getParam('collections', [])); } /** * Set project for migration. * - * @param Document $project - * @param Database $projectDB - * @param Database $oldConsoleDB - * + * @param Document $project + * @param Database $projectDB + * @param Database $oldConsoleDB * @return self */ public function setProject(Document $project, Database $projectDB, Database $consoleDB): self @@ -114,7 +113,7 @@ abstract class Migration /** * Set PDO for Migration. * - * @param \PDO $pdo + * @param \PDO $pdo * @return \Appwrite\Migration\Migration */ public function setPDO(\PDO $pdo): self @@ -127,7 +126,7 @@ abstract class Migration /** * Iterates through every document. * - * @param callable $callback + * @param callable $callback */ public function forEachDocument(callable $callback): void { @@ -136,7 +135,7 @@ abstract class Migration continue; } - Console::log('Migrating Collection ' . $collection['$id'] . ':'); + Console::log('Migrating Collection '.$collection['$id'].':'); \Co\run(function (array $collection, callable $callback) { foreach ($this->documentsIterator($collection['$id']) as $document) { @@ -148,14 +147,15 @@ abstract class Migration $old = $document->getArrayCopy(); $new = call_user_func($callback, $document); - if (is_null($new) || !self::hasDifference($new->getArrayCopy(), $old)) { + if (is_null($new) || ! self::hasDifference($new->getArrayCopy(), $old)) { return; } try { $new = $this->projectDB->updateDocument($document->getCollection(), $document->getId(), $document); } catch (\Throwable $th) { - Console::error('Failed to update document: ' . $th->getMessage()); + Console::error('Failed to update document: '.$th->getMessage()); + return; } }, $document, $callback); @@ -167,8 +167,9 @@ abstract class Migration /** * Provides an iterator for all documents on a collection. * - * @param string $collectionId + * @param string $collectionId * @return iterable + * * @throws \Exception */ public function documentsIterator(string $collectionId): iterable @@ -186,7 +187,7 @@ abstract class Migration $count = count($documents); $sum += $count; - Console::log($sum . ' / ' . $collectionCount); + Console::log($sum.' / '.$collectionCount); foreach ($documents as $document) { yield $document; } @@ -196,28 +197,28 @@ abstract class Migration } else { $nextDocument = end($documents); } - } while (!is_null($nextDocument)); + } while (! is_null($nextDocument)); } /** * Checks 2 arrays for differences. * - * @param array $array1 - * @param array $array2 + * @param array $array1 + * @param array $array2 * @return bool */ public static function hasDifference(array $array1, array $array2): bool { foreach ($array1 as $key => $value) { if (is_array($value)) { - if (!isset($array2[$key]) || !is_array($array2[$key])) { + if (! isset($array2[$key]) || ! is_array($array2[$key])) { return true; } else { if (self::hasDifference($value, $array2[$key])) { return true; } } - } elseif (!array_key_exists($key, $array2) || $array2[$key] !== $value) { + } elseif (! array_key_exists($key, $array2) || $array2[$key] !== $value) { return true; } } @@ -228,16 +229,17 @@ abstract class Migration /** * Creates colletion from the config collection. * - * @param string $id - * @param string|null $name + * @param string $id + * @param string|null $name * @return void + * * @throws \Throwable */ protected function createCollection(string $id, string $name = null): void { $name ??= $id; - if (!$this->projectDB->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), $name)) { + if (! $this->projectDB->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), $name)) { $attributes = []; $indexes = []; $collection = $this->collections[$id]; @@ -275,10 +277,11 @@ abstract class Migration /** * Creates attribute from collections.php * - * @param \Utopia\Database\Database $database - * @param string $collectionId - * @param string $attributeId + * @param \Utopia\Database\Database $database + * @param string $collectionId + * @param string $attributeId * @return void + * * @throws \Exception * @throws \Utopia\Database\Exception\Duplicate * @throws \Utopia\Database\Exception\Limit @@ -320,11 +323,12 @@ abstract class Migration /** * Creates index from collections.php * - * @param \Utopia\Database\Database $database - * @param string $collectionId - * @param string $indexId - * @param string|null $from + * @param \Utopia\Database\Database $database + * @param string $collectionId + * @param string $indexId + * @param string|null $from * @return void + * * @throws \Exception * @throws \Utopia\Database\Exception\Duplicate * @throws \Utopia\Database\Exception\Limit @@ -360,9 +364,9 @@ abstract class Migration /** * Change a collection attribute's internal type * - * @param string $collection - * @param string $attribute - * @param string $type + * @param string $collection + * @param string $attribute + * @param string $type * @return void */ protected function changeAttributeInternalType(string $collection, string $attribute, string $type): void diff --git a/src/Appwrite/Migration/Version/V15.php b/src/Appwrite/Migration/Version/V15.php index b6deb780da..dadf971675 100644 --- a/src/Appwrite/Migration/Version/V15.php +++ b/src/Appwrite/Migration/Version/V15.php @@ -4,8 +4,6 @@ namespace Appwrite\Migration\Version; use Appwrite\Migration\Migration; use Appwrite\OpenSSL\OpenSSL; -use Exception; -use PDO; use Utopia\App; use Utopia\CLI\Console; use Utopia\Config\Config; @@ -33,7 +31,7 @@ class V15 extends Migration $this->providers = \array_merge( ['email', 'anonymous'], \array_map( - fn ($value) => "oauth-" . $value, + fn ($value) => 'oauth-'.$value, \array_keys(Config::getParam('authProviders', [])) ) ); @@ -49,7 +47,7 @@ class V15 extends Migration ); } - Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); + Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); Console::info('Migrating Stats'); $this->migrateStatsMetric('requests', 'project.$all.network.requests'); $this->migrateStatsMetric('network', 'project.$all.network.bandwidth'); @@ -76,6 +74,7 @@ class V15 extends Migration * Migrating all Bucket tables. * * @return void + * * @throws \Exception * @throws \PDOException */ @@ -108,7 +107,7 @@ class V15 extends Migration addCreatePermission: true ); - if (!is_null($bucket->getAttribute('permission'))) { + if (! is_null($bucket->getAttribute('permission'))) { $bucket->setAttribute('fileSecurity', $bucket->getAttribute('permissions') === 'document'); } @@ -152,6 +151,7 @@ class V15 extends Migration * Migrating all Database and Collection tables. * * @return void + * * @throws \Exception * @throws \PDOException */ @@ -229,7 +229,7 @@ class V15 extends Migration addCreatePermission: true ); - if (!is_null($collection->getAttribute('permission'))) { + if (! is_null($collection->getAttribute('permission'))) { $collection->setAttribute('documentSecurity', $collection->getAttribute('permissions') === 'document'); } @@ -249,9 +249,10 @@ class V15 extends Migration $requiredAttributes = array_reduce($collection->getAttribute('attributes', []), function (array $carry, Document $item) { if ($item->getAttribute('required', false)) { $carry = array_merge($carry, [ - $item->getAttribute('key') => $item->getAttribute('default') + $item->getAttribute('key') => $item->getAttribute('default'), ]); } + return $carry; }, []); @@ -289,7 +290,7 @@ class V15 extends Migration /** * Removes all 'write' permissions from a table. * - * @param string $table + * @param string $table * @return void */ protected function removeWritePermissions(string $table): void @@ -304,8 +305,9 @@ class V15 extends Migration /** * Returns all columns from the Table. * - * @param string $table + * @param string $table * @return array + * * @throws \Exception * @throws \PDOException */ @@ -325,6 +327,7 @@ class V15 extends Migration * Migrates all Integer colums for timestamps to DateTime. * * @return void + * * @throws \Exception */ protected function migrateDateTimeAttribute(string $table, string $attribute): void @@ -352,7 +355,7 @@ class V15 extends Migration /** * Skip adding filter on internal attributes. */ - if (!str_starts_with($attribute, '_')) { + if (! str_starts_with($attribute, '_')) { try { /** * Add datetime filter. @@ -378,8 +381,9 @@ class V15 extends Migration /** * Create the '_permissions' column to a table. * - * @param string $table + * @param string $table * @return void + * * @throws \Exception * @throws \PDOException */ @@ -387,7 +391,7 @@ class V15 extends Migration { $columns = $this->getSQLColumnTypes($table); - if (!array_key_exists('_permissions', $columns)) { + if (! array_key_exists('_permissions', $columns)) { try { $this->pdo->prepare("ALTER TABLE IF EXISTS `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_{$table}` ADD `_permissions` MEDIUMTEXT DEFAULT NULL")->execute(); } catch (\Throwable $th) { @@ -399,10 +403,11 @@ class V15 extends Migration /** * Populate '$permissions' from '$read' and '$write'. * - * @param \Utopia\Database\Document $document - * @param null|string $table - * @param bool $addCreatePermission + * @param \Utopia\Database\Document $document + * @param null|string $table + * @param bool $addCreatePermission * @return void + * * @throws \Exception * @throws \PDOException */ @@ -443,7 +448,7 @@ class V15 extends Migration /** * Migrates a permission string * - * @param string $permission + * @param string $permission * @return string */ protected function migratePermission(string $permission): string @@ -730,7 +735,7 @@ class V15 extends Migration foreach ($this->documentsIterator($id) as $function) { $vars = $function->getAttribute('vars', []); - if (!is_array($vars)) { + if (! is_array($vars)) { continue; } @@ -751,7 +756,7 @@ class V15 extends Migration 'functionInternalId' => $function->getInternalId(), 'key' => (string) $key, 'value' => (string) $value, - 'search' => implode(' ', [$variableId, $key, $function->getId()]) + 'search' => implode(' ', [$variableId, $key, $function->getId()]), ]); $this->projectDB->createDocument('variables', $variable); } @@ -1223,7 +1228,7 @@ class V15 extends Migration /** * Fix run on each document * - * @param \Utopia\Database\Document $document + * @param \Utopia\Database\Document $document * @return \Utopia\Database\Document */ protected function fixDocument(Document $document) @@ -1474,14 +1479,14 @@ class V15 extends Migration $this->pdo->prepare("UPDATE `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_stats` SET metric = {$to} WHERE metric = {$from}")->execute(); } catch (\Throwable $th) { - Console::warning("Migrating steps from {$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_stats:" . $th->getMessage()); + Console::warning("Migrating steps from {$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_stats:".$th->getMessage()); } } /** * Filter from the 'encrypt' filter. * - * @param string $value + * @param string $value * @return string|false */ protected function encryptFilter(string $value): string diff --git a/src/Appwrite/Migration/Version/V16.php b/src/Appwrite/Migration/Version/V16.php index bee2236dfb..761a274e0f 100644 --- a/src/Appwrite/Migration/Version/V16.php +++ b/src/Appwrite/Migration/Version/V16.php @@ -24,7 +24,7 @@ class V16 extends Migration ); } - Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); + Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); Console::info('Migrating Collections'); $this->migrateCollections(); @@ -102,7 +102,7 @@ class V16 extends Migration /** * Fix run on each document * - * @param \Utopia\Database\Document $document + * @param \Utopia\Database\Document $document * @return \Utopia\Database\Document */ protected function fixDocument(Document $document) @@ -118,7 +118,7 @@ class V16 extends Migration * Set default authDuration */ $document->setAttribute('auths', array_merge($document->getAttribute('auths', []), [ - 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG + 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, ])); /** @@ -127,16 +127,16 @@ class V16 extends Migration $authProviders = $document->getAttribute('authProviders', []); foreach (Config::getParam('authProviders') as $provider => $value) { - if (!$value['enabled']) { + if (! $value['enabled']) { continue; } - if (($authProviders[$provider . 'Appid'] ?? false) && ($authProviders[$provider . 'Secret'] ?? false)) { - if (array_key_exists($provider . 'Enabled', $authProviders)) { + if (($authProviders[$provider.'Appid'] ?? false) && ($authProviders[$provider.'Secret'] ?? false)) { + if (array_key_exists($provider.'Enabled', $authProviders)) { continue; } - $authProviders[$provider . 'Enabled'] = true; + $authProviders[$provider.'Enabled'] = true; } } diff --git a/src/Appwrite/Migration/Version/V17.php b/src/Appwrite/Migration/Version/V17.php index 3f744d8069..421c86bcc8 100644 --- a/src/Appwrite/Migration/Version/V17.php +++ b/src/Appwrite/Migration/Version/V17.php @@ -23,7 +23,7 @@ class V17 extends Migration ); } - Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); + Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); Console::info('Migrating Collections'); $this->migrateCollections(); @@ -33,11 +33,11 @@ class V17 extends Migration $this->forEachDocument([$this, 'fixDocument']); } - /** * Migrating all Bucket tables. * * @return void + * * @throws \Exception * @throws \PDOException */ @@ -234,7 +234,7 @@ class V17 extends Migration /** * Fix run on each document * - * @param \Utopia\Database\Document $document + * @param \Utopia\Database\Document $document * @return \Utopia\Database\Document */ protected function fixDocument(Document $document) @@ -250,15 +250,15 @@ class V17 extends Migration * Set default maxSessions */ $document->setAttribute('auths', array_merge($document->getAttribute('auths', []), [ - 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT + 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, ])); break; case 'users': - /** + /** * Set hashOptions type */ $document->setAttribute('hashOptions', array_merge($document->getAttribute('hashOptions', []), [ - 'type' => $document->getAttribute('hash', Auth::DEFAULT_ALGO) + 'type' => $document->getAttribute('hash', Auth::DEFAULT_ALGO), ])); break; } diff --git a/src/Appwrite/Migration/Version/V18.php b/src/Appwrite/Migration/Version/V18.php index 839269f940..2b3b98088d 100644 --- a/src/Appwrite/Migration/Version/V18.php +++ b/src/Appwrite/Migration/Version/V18.php @@ -13,7 +13,6 @@ class V18 extends Migration { public function execute(): void { - /** * Disable SubQueries for Performance. */ @@ -25,7 +24,7 @@ class V18 extends Migration ); } - Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); + Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); $this->addDocumentSecurityToProject(); @@ -43,6 +42,7 @@ class V18 extends Migration * Migrate all Databases. * * @return void + * * @throws \Exception */ private function migrateDatabases(): void @@ -154,7 +154,7 @@ class V18 extends Migration /** * Fix run on each document * - * @param Document $document + * @param Document $document * @return Document */ protected function fixDocument(Document $document): Document diff --git a/src/Appwrite/Migration/Version/V19.php b/src/Appwrite/Migration/Version/V19.php index 39522aff0b..fe9bde6d29 100644 --- a/src/Appwrite/Migration/Version/V19.php +++ b/src/Appwrite/Migration/Version/V19.php @@ -2,8 +2,6 @@ namespace Appwrite\Migration\Version; -use Appwrite\Auth\Auth; -use Utopia\Config\Config; use Appwrite\Migration\Migration; use Utopia\CLI\Console; use Utopia\Database\Database; @@ -13,7 +11,6 @@ class V19 extends Migration { public function execute(): void { - /** * Disable SubQueries for Performance. */ @@ -25,7 +22,7 @@ class V19 extends Migration ); } - Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); + Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); $this->alterPermissionIndex('_metadata'); @@ -48,6 +45,7 @@ class V19 extends Migration * Migrate all Databases. * * @return void + * * @throws \Exception */ private function migrateDatabases(): void @@ -99,7 +97,7 @@ class V19 extends Migration default: break; } - if (!in_array($id, ['files', 'collections'])) { + if (! in_array($id, ['files', 'collections'])) { $this->alterPermissionIndex($id); $this->alterUidType($id); } @@ -111,7 +109,7 @@ class V19 extends Migration /** * Fix run on each document * - * @param Document $document + * @param Document $document * @return Document */ protected function fixDocument(Document $document): Document @@ -163,6 +161,7 @@ class V19 extends Migration * Migrating all Bucket tables. * * @return void + * * @throws \Exception * @throws \PDOException */ diff --git a/src/Appwrite/Network/Validator/CNAME.php b/src/Appwrite/Network/Validator/CNAME.php index 678a57cecd..3840322137 100644 --- a/src/Appwrite/Network/Validator/CNAME.php +++ b/src/Appwrite/Network/Validator/CNAME.php @@ -12,7 +12,7 @@ class CNAME extends Validator protected $target; /** - * @param string $target + * @param string $target */ public function __construct($target) { @@ -30,13 +30,12 @@ class CNAME extends Validator /** * Check if CNAME record target value matches selected target * - * @param mixed $domain - * + * @param mixed $domain * @return bool */ public function isValid($domain): bool { - if (!is_string($domain)) { + if (! is_string($domain)) { return false; } @@ -46,7 +45,7 @@ class CNAME extends Validator return false; } - if (!$records) { + if (! $records) { return false; } diff --git a/src/Appwrite/Network/Validator/Email.php b/src/Appwrite/Network/Validator/Email.php index efc1a5d5b3..232437aab7 100644 --- a/src/Appwrite/Network/Validator/Email.php +++ b/src/Appwrite/Network/Validator/Email.php @@ -8,8 +8,6 @@ use Utopia\Validator; * Email * * Validate that an variable is a valid email address - * - * @package Utopia\Validator */ class Email extends Validator { @@ -30,12 +28,12 @@ class Email extends Validator * * Validation will pass when $value is valid email address. * - * @param mixed $value + * @param mixed $value * @return bool */ public function isValid($value): bool { - if (!\filter_var($value, FILTER_VALIDATE_EMAIL)) { + if (! \filter_var($value, FILTER_VALIDATE_EMAIL)) { return false; } diff --git a/src/Appwrite/Network/Validator/Origin.php b/src/Appwrite/Network/Validator/Origin.php index 508961ab9e..78065c0e48 100644 --- a/src/Appwrite/Network/Validator/Origin.php +++ b/src/Appwrite/Network/Validator/Origin.php @@ -2,35 +2,55 @@ namespace Appwrite\Network\Validator; -use Utopia\Validator\Hostname; use Utopia\Validator; +use Utopia\Validator\Hostname; class Origin extends Validator { public const CLIENT_TYPE_UNKNOWN = 'unknown'; + public const CLIENT_TYPE_WEB = 'web'; + public const CLIENT_TYPE_FLUTTER_IOS = 'flutter-ios'; + public const CLIENT_TYPE_FLUTTER_ANDROID = 'flutter-android'; + public const CLIENT_TYPE_FLUTTER_MACOS = 'flutter-macos'; + public const CLIENT_TYPE_FLUTTER_WINDOWS = 'flutter-windows'; + public const CLIENT_TYPE_FLUTTER_LINUX = 'flutter-linux'; + public const CLIENT_TYPE_FLUTTER_WEB = 'flutter-web'; + public const CLIENT_TYPE_APPLE_IOS = 'apple-ios'; + public const CLIENT_TYPE_APPLE_MACOS = 'apple-macos'; + public const CLIENT_TYPE_APPLE_WATCHOS = 'apple-watchos'; + public const CLIENT_TYPE_APPLE_TVOS = 'apple-tvos'; + public const CLIENT_TYPE_ANDROID = 'android'; + public const CLIENT_TYPE_UNITY = 'unity'; - public const SCHEME_TYPE_HTTP = 'http'; + public const SCHEME_TYPE_HTTPS = 'https'; + public const SCHEME_TYPE_IOS = 'appwrite-ios'; + public const SCHEME_TYPE_MACOS = 'appwrite-macos'; + public const SCHEME_TYPE_WATCHOS = 'appwrite-watchos'; + public const SCHEME_TYPE_TVOS = 'appwrite-tvos'; + public const SCHEME_TYPE_ANDROID = 'appwrite-android'; + public const SCHEME_TYPE_WINDOWS = 'appwrite-windows'; + public const SCHEME_TYPE_LINUX = 'appwrite-linux'; /** @@ -65,7 +85,7 @@ class Origin extends Validator protected $host = ''; /** - * @param string $target + * @param string $target */ public function __construct($platforms) { @@ -92,7 +112,7 @@ class Origin extends Validator break; default: - # code... + // code... break; } } @@ -100,25 +120,24 @@ class Origin extends Validator public function getDescription(): string { - if (!\array_key_exists($this->client, $this->platforms)) { + if (! \array_key_exists($this->client, $this->platforms)) { return 'Unsupported platform'; } - return 'Invalid Origin. Register your new client (' . $this->host . ') as a new ' - . $this->platforms[$this->client] . ' platform on your project console dashboard'; + return 'Invalid Origin. Register your new client ('.$this->host.') as a new ' + .$this->platforms[$this->client].' platform on your project console dashboard'; } /** * Check if Origin has been allowed * for access to the API * - * @param mixed $origin - * + * @param mixed $origin * @return bool */ public function isValid($origin): bool { - if (!is_string($origin)) { + if (! is_string($origin)) { return false; } diff --git a/src/Appwrite/OpenSSL/OpenSSL.php b/src/Appwrite/OpenSSL/OpenSSL.php index 1965a3c858..2eed67dd3e 100644 --- a/src/Appwrite/OpenSSL/OpenSSL.php +++ b/src/Appwrite/OpenSSL/OpenSSL.php @@ -10,12 +10,11 @@ class OpenSSL * @param $data * @param $method * @param $key - * @param int $options - * @param string $iv - * @param null $tag - * @param string $aad - * @param int $tag_length - * + * @param int $options + * @param string $iv + * @param null $tag + * @param string $aad + * @param int $tag_length * @return string */ public static function encrypt($data, $method, $key, $options = 0, $iv = '', &$tag = null, $aad = '', $tag_length = 16) @@ -27,11 +26,10 @@ class OpenSSL * @param $data * @param $method * @param $password - * @param int $options - * @param string $iv - * @param string $tag - * @param string $aad - * + * @param int $options + * @param string $iv + * @param string $tag + * @param string $aad * @return string */ public static function decrypt($data, $method, $password, $options = 1, $iv = '', $tag = '', $aad = '') @@ -40,8 +38,7 @@ class OpenSSL } /** - * @param string $method - * + * @param string $method * @return int */ public static function cipherIVLength($method) @@ -51,8 +48,7 @@ class OpenSSL /** * @param $length - * @param null $crypto_strong - * + * @param null $crypto_strong * @return false|string */ public static function randomPseudoBytes($length, &$crypto_strong = null) diff --git a/src/Appwrite/Platform/Services/Tasks.php b/src/Appwrite/Platform/Services/Tasks.php index 9e919127bf..a24d72be2f 100644 --- a/src/Appwrite/Platform/Services/Tasks.php +++ b/src/Appwrite/Platform/Services/Tasks.php @@ -2,26 +2,25 @@ namespace Appwrite\Platform\Services; -use Utopia\Platform\Service; +use Appwrite\Platform\Tasks\CalcTierStats; +use Appwrite\Platform\Tasks\CalcUsersStats; +use Appwrite\Platform\Tasks\ClearCardCache; use Appwrite\Platform\Tasks\Doctor; +use Appwrite\Platform\Tasks\Hamster; use Appwrite\Platform\Tasks\Install; use Appwrite\Platform\Tasks\Maintenance; use Appwrite\Platform\Tasks\Migrate; -use Appwrite\Platform\Tasks\Schedule; use Appwrite\Platform\Tasks\PatchCreateMissingSchedules; +use Appwrite\Platform\Tasks\PatchDeleteProjectCollections; +use Appwrite\Platform\Tasks\PatchDeleteScheduleUpdatedAtAttribute; +use Appwrite\Platform\Tasks\Schedule; use Appwrite\Platform\Tasks\SDKs; use Appwrite\Platform\Tasks\Specs; use Appwrite\Platform\Tasks\SSL; -use Appwrite\Platform\Tasks\Hamster; -use Appwrite\Platform\Tasks\PatchDeleteScheduleUpdatedAtAttribute; -use Appwrite\Platform\Tasks\ClearCardCache; -use Appwrite\Platform\Tasks\Usage; use Appwrite\Platform\Tasks\Vars; use Appwrite\Platform\Tasks\Version; use Appwrite\Platform\Tasks\VolumeSync; -use Appwrite\Platform\Tasks\CalcUsersStats; -use Appwrite\Platform\Tasks\CalcTierStats; -use Appwrite\Platform\Tasks\PatchDeleteProjectCollections; +use Utopia\Platform\Service; class Tasks extends Service { @@ -46,7 +45,6 @@ class Tasks extends Service ->addAction(Specs::getName(), new Specs()) ->addAction(CalcUsersStats::getName(), new CalcUsersStats()) ->addAction(CalcTierStats::getName(), new CalcTierStats()) - ->addAction(PatchDeleteProjectCollections::getName(), new PatchDeleteProjectCollections()) - ; + ->addAction(PatchDeleteProjectCollections::getName(), new PatchDeleteProjectCollections()); } } diff --git a/src/Appwrite/Platform/Tasks/CalcTierStats.php b/src/Appwrite/Platform/Tasks/CalcTierStats.php index d660709940..0dc795cbcd 100644 --- a/src/Appwrite/Platform/Tasks/CalcTierStats.php +++ b/src/Appwrite/Platform/Tasks/CalcTierStats.php @@ -4,15 +4,15 @@ namespace Appwrite\Platform\Tasks; use Exception; use League\Csv\CannotInsertRecord; +use League\Csv\Writer; +use PHPMailer\PHPMailer\PHPMailer; use Utopia\App; -use Utopia\Database\Validator\Authorization; -use Utopia\Platform\Action; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Query; -use League\Csv\Writer; -use PHPMailer\PHPMailer\PHPMailer; +use Utopia\Database\Validator\Authorization; +use Utopia\Platform\Action; use Utopia\Pools\Group; use Utopia\Registry\Registry; @@ -44,11 +44,13 @@ class CalcTierStats extends Action ]; protected string $directory = '/usr/local'; + protected string $path; + protected string $date; private array $usageStats = [ - 'project.$all.network.requests' => 'Requests', + 'project.$all.network.requests' => 'Requests', 'project.$all.network.bandwidth' => 'Bandwidth', ]; @@ -60,7 +62,6 @@ class CalcTierStats extends Action public function __construct() { - $this ->desc('Get stats for projects') ->inject('pools') @@ -81,7 +82,7 @@ class CalcTierStats extends Action //docker compose exec -t appwrite calc-tier-stats Console::title('Cloud free tier stats calculation V1'); - Console::success(APP_NAME . ' cloud free tier stats calculation has started'); + Console::success(APP_NAME.' cloud free tier stats calculation has started'); /* Initialise new Utopia app */ $app = new App('UTC'); @@ -102,9 +103,8 @@ class CalcTierStats extends Action $limit = 30; $sum = 30; $offset = 0; - while (!empty($projects)) { + while (! empty($projects)) { foreach ($projects as $project) { - /** * Skip user projects with id 'console' */ @@ -123,18 +123,18 @@ class CalcTierStats extends Action $dbForProject = new Database($adapter, $cache); $dbForProject->setDefaultDatabase('appwrite'); - $dbForProject->setNamespace('_' . $project->getInternalId()); + $dbForProject->setNamespace('_'.$project->getInternalId()); /** Get Project ID */ $stats['Project ID'] = $project->getId(); - $stats['Organization ID'] = $project->getAttribute('teamId', null); + $stats['Organization ID'] = $project->getAttribute('teamId', null); /** Get Total Members */ $teamInternalId = $project->getAttribute('teamInternalId', null); if ($teamInternalId) { $stats['Organization Members'] = $dbForConsole->count('memberships', [ - Query::equal('teamInternalId', [$teamInternalId]) + Query::equal('teamInternalId', [$teamInternalId]), ]); } else { $stats['Organization Members'] = 0; @@ -195,7 +195,7 @@ class CalcTierStats extends Action }); foreach ($tmp as $key => $value) { - $stats[$metrics[$key]] = $value; + $stats[$metrics[$key]] = $value; } try { @@ -208,27 +208,27 @@ class CalcTierStats extends Action } try { - /** Get Api keys */ + /** Get Api keys */ $stats['Api keys'] = $dbForConsole->count('keys', [ - Query::equal('projectInternalId', [$project->getInternalId()]), + Query::equal('projectInternalId', [$project->getInternalId()]), ]); } catch (\Throwable) { $stats['Api keys'] = 0; } try { - /** Get Webhooks */ + /** Get Webhooks */ $stats['Webhooks'] = $dbForConsole->count('webhooks', [ - Query::equal('projectInternalId', [$project->getInternalId()]), + Query::equal('projectInternalId', [$project->getInternalId()]), ]); } catch (\Throwable) { $stats['Webhooks'] = 0; } try { - /** Get Platforms */ + /** Get Platforms */ $stats['Platforms'] = $dbForConsole->count('platforms', [ - Query::equal('projectInternalId', [$project->getInternalId()]), + Query::equal('projectInternalId', [$project->getInternalId()]), ]); } catch (\Throwable) { $stats['Platforms'] = 0; @@ -242,28 +242,26 @@ class CalcTierStats extends Action try { $buckets = $dbForProject->find('buckets', []); foreach ($buckets as $bucket) { - $file = $dbForProject->findOne('bucket_' . $bucket->getInternalId(), [Query::orderDesc('sizeOriginal'),]); + $file = $dbForProject->findOne('bucket_'.$bucket->getInternalId(), [Query::orderDesc('sizeOriginal')]); if (empty($file)) { continue; } - $filesSum += $dbForProject->sum('bucket_' . $bucket->getInternalId(), 'sizeOriginal', [], 0); - $filesCount += $dbForProject->count('bucket_' . $bucket->getInternalId(), []); + $filesSum += $dbForProject->sum('bucket_'.$bucket->getInternalId(), 'sizeOriginal', [], 0); + $filesCount += $dbForProject->count('bucket_'.$bucket->getInternalId(), []); if ($file->getAttribute('sizeOriginal') > $maxFileSize) { $maxFileSize = $file->getAttribute('sizeOriginal'); } $counter++; } } catch (\Throwable) { - ; } $stats['Buckets'] = $counter; $stats['Files'] = $filesCount; $stats['Storage (bytes)'] = $filesSum; $stats['Max File Size (bytes)'] = $maxFileSize; - try { - /** Get Total Functions */ + /** Get Total Functions */ $stats['Databases'] = $dbForProject->count('databases', []); } catch (\Throwable) { $stats['Databases'] = 0; @@ -292,7 +290,7 @@ class CalcTierStats extends Action $csv->insertOne(array_values($stats)); } catch (\Throwable $th) { - Console::error('Failed on project ("' . $project->getId() . '") version with error on File: ' . $th->getFile() . ' line no: ' . $th->getline() . ' with message: ' . $th->getMessage()); + Console::error('Failed on project ("'.$project->getId().'") version with error on File: '.$th->getFile().' line no: '.$th->getline().' with message: '.$th->getMessage()); } finally { $pools ->get($db) @@ -311,7 +309,7 @@ class CalcTierStats extends Action $count = $count + $sum; } - Console::log('Iterated through ' . $count - 1 . '/' . $totalProjects . ' projects...'); + Console::log('Iterated through '.$count - 1 .'/'.$totalProjects.' projects...'); $pools ->get('console') @@ -341,7 +339,7 @@ class CalcTierStats extends Action /** Content */ $mail->Subject = "Cloud Report for {$this->date}"; - $mail->Body = "Please find the daily cloud report atttached"; + $mail->Body = 'Please find the daily cloud report atttached'; $mail->send(); Console::success('Email has been sent!'); } catch (Exception $e) { diff --git a/src/Appwrite/Platform/Tasks/CalcUsersStats.php b/src/Appwrite/Platform/Tasks/CalcUsersStats.php index 6310fe17b4..67fcc1a5c5 100644 --- a/src/Appwrite/Platform/Tasks/CalcUsersStats.php +++ b/src/Appwrite/Platform/Tasks/CalcUsersStats.php @@ -3,14 +3,14 @@ namespace Appwrite\Platform\Tasks; use Exception; +use League\Csv\Writer; +use PHPMailer\PHPMailer\PHPMailer; use Utopia\App; -use Utopia\Platform\Action; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Query; -use League\Csv\Writer; -use PHPMailer\PHPMailer\PHPMailer; +use Utopia\Platform\Action; use Utopia\Pools\Group; use Utopia\Registry\Registry; @@ -21,11 +21,13 @@ class CalcUsersStats extends Action 'Project Name', 'Team ID', 'Team name', - 'Users' + 'Users', ]; protected string $directory = '/usr/local'; + protected string $path; + protected string $date; public static function getName(): string @@ -35,7 +37,6 @@ class CalcUsersStats extends Action public function __construct() { - $this ->desc('Get stats for projects') ->inject('pools') @@ -52,7 +53,7 @@ class CalcUsersStats extends Action //docker compose exec -t appwrite calc-users-stats Console::title('Cloud Users calculation V1'); - Console::success(APP_NAME . ' cloud Users calculation has started'); + Console::success(APP_NAME.' cloud Users calculation has started'); /* Initialise new Utopia app */ $app = new App('UTC'); @@ -73,9 +74,8 @@ class CalcUsersStats extends Action $limit = 30; $sum = 30; $offset = 0; - while (!empty($projects)) { + while (! empty($projects)) { foreach ($projects as $project) { - /** * Skip user projects with id 'console' */ @@ -94,7 +94,7 @@ class CalcUsersStats extends Action $dbForProject = new Database($adapter, $cache); $dbForProject->setDefaultDatabase('appwrite'); - $dbForProject->setNamespace('_' . $project->getInternalId()); + $dbForProject->setNamespace('_'.$project->getInternalId()); /** Get Project ID */ $stats['Project ID'] = $project->getId(); @@ -102,7 +102,6 @@ class CalcUsersStats extends Action /** Get Project Name */ $stats['Project Name'] = $project->getAttribute('name'); - /** Get Team Name and Id */ $teamId = $project->getAttribute('teamId', null); $teamName = null; @@ -111,7 +110,7 @@ class CalcUsersStats extends Action $teamName = $team->getAttribute('name'); } - $stats['Team ID'] = $teamId; + $stats['Team ID'] = $teamId; $stats['Team name'] = $teamName; /** Get Total Users */ @@ -119,7 +118,7 @@ class CalcUsersStats extends Action $csv->insertOne(array_values($stats)); } catch (\Throwable $th) { - Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage()); + Console::error('Failed to update project ("'.$project->getId().'") version with error: '.$th->getMessage()); } finally { $pools ->get($db) @@ -137,7 +136,7 @@ class CalcUsersStats extends Action $offset = $offset + $limit; $count = $count + $sum; } - Console::log('Iterated through ' . $count - 1 . '/' . $totalProjects . ' projects...'); + Console::log('Iterated through '.$count - 1 .'/'.$totalProjects.' projects...'); $pools ->get('console') ->reclaim(); @@ -166,7 +165,7 @@ class CalcUsersStats extends Action /** Content */ $mail->Subject = "Cloud Report for {$this->date}"; - $mail->Body = "Please find the daily cloud report atttached"; + $mail->Body = 'Please find the daily cloud report atttached'; $mail->send(); Console::success('Email has been sent!'); } catch (Exception $e) { diff --git a/src/Appwrite/Platform/Tasks/ClearCardCache.php b/src/Appwrite/Platform/Tasks/ClearCardCache.php index d3153b995c..59499b6888 100644 --- a/src/Appwrite/Platform/Tasks/ClearCardCache.php +++ b/src/Appwrite/Platform/Tasks/ClearCardCache.php @@ -4,12 +4,12 @@ namespace Appwrite\Platform\Tasks; use Utopia\Cache\Adapter\Filesystem; use Utopia\Cache\Cache; -use Utopia\Platform\Action; use Utopia\CLI\Console; -use Utopia\Database\Query; use Utopia\Database\Database; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; +use Utopia\Platform\Action; class ClearCardCache extends Action { @@ -33,12 +33,12 @@ class ClearCardCache extends Action Authorization::setDefaultStatus(false); Console::title('ClearCardCache V1'); - Console::success(APP_NAME . ' ClearCardCache v1 has started'); - $resources = ['card/' . $userId, 'card-back/' . $userId, 'card-og/' . $userId]; + Console::success(APP_NAME.' ClearCardCache v1 has started'); + $resources = ['card/'.$userId, 'card-back/'.$userId, 'card-og/'.$userId]; $caches = Authorization::skip(fn () => $dbForConsole->find('cache', [ Query::equal('resource', $resources), - Query::limit(100) + Query::limit(100), ])); $count = \count($caches); @@ -49,7 +49,7 @@ class ClearCardCache extends Action $key = $cache->getId(); $cacheFolder = new Cache( - new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-console') + new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-console') ); $cacheFolder->purge($key); @@ -57,6 +57,6 @@ class ClearCardCache extends Action Authorization::skip(fn () => $dbForConsole->deleteDocument('cache', $cache->getId())); } - Console::success(APP_NAME . ' ClearCardCache v1 has finished'); + Console::success(APP_NAME.' ClearCardCache v1 has finished'); } } diff --git a/src/Appwrite/Platform/Tasks/Doctor.php b/src/Appwrite/Platform/Tasks/Doctor.php index 9a6d6a2847..8b37e578f4 100644 --- a/src/Appwrite/Platform/Tasks/Doctor.php +++ b/src/Appwrite/Platform/Tasks/Doctor.php @@ -2,16 +2,16 @@ namespace Appwrite\Platform\Tasks; +use Appwrite\ClamAV\Network; use Utopia\App; use Utopia\CLI\Console; -use Appwrite\ClamAV\Network; -use Utopia\Logger\Logger; -use Utopia\Storage\Device\Local; -use Utopia\Storage\Storage; use Utopia\Config\Config; use Utopia\Domains\Domain; +use Utopia\Logger\Logger; use Utopia\Platform\Action; use Utopia\Registry\Registry; +use Utopia\Storage\Device\Local; +use Utopia\Storage\Storage; class Doctor extends Action { @@ -35,24 +35,24 @@ class Doctor extends Action / \ ) __/ ) __/\ /\ / ) / )( )( ) _) _ )(( O ) \_/\_/(__) (__) (_/\_)(__\_)(__) (__) (____)(_)(__)\__/ "); - Console::log("\n" . '👩‍⚕️ Running ' . APP_NAME . ' Doctor for version ' . App::getEnv('_APP_VERSION', 'UNKNOWN') . ' ...' . "\n"); + Console::log("\n".'👩‍⚕️ Running '.APP_NAME.' Doctor for version '.App::getEnv('_APP_VERSION', 'UNKNOWN').' ...'."\n"); Console::log('[Settings]'); $domain = new Domain(App::getEnv('_APP_DOMAIN')); - if (!$domain->isKnown() || $domain->isTest()) { - Console::log('🔴 Hostname has no public suffix (' . $domain->get() . ')'); + if (! $domain->isKnown() || $domain->isTest()) { + Console::log('🔴 Hostname has no public suffix ('.$domain->get().')'); } else { - Console::log('🟢 Hostname has a public suffix (' . $domain->get() . ')'); + Console::log('🟢 Hostname has a public suffix ('.$domain->get().')'); } $domain = new Domain(App::getEnv('_APP_DOMAIN_TARGET')); - if (!$domain->isKnown() || $domain->isTest()) { - Console::log('🔴 CNAME target has no public suffix (' . $domain->get() . ')'); + if (! $domain->isKnown() || $domain->isTest()) { + Console::log('🔴 CNAME target has no public suffix ('.$domain->get().')'); } else { - Console::log('🟢 CNAME target has a public suffix (' . $domain->get() . ')'); + Console::log('🟢 CNAME target has a public suffix ('.$domain->get().')'); } if (App::getEnv('_APP_OPENSSL_KEY_V1') === 'your-secret-key' || empty(App::getEnv('_APP_OPENSSL_KEY_V1'))) { @@ -96,22 +96,21 @@ class Doctor extends Action $providerName = App::getEnv('_APP_LOGGING_PROVIDER', ''); $providerConfig = App::getEnv('_APP_LOGGING_CONFIG', ''); - if (empty($providerName) || empty($providerConfig) || !Logger::hasProvider($providerName)) { + if (empty($providerName) || empty($providerConfig) || ! Logger::hasProvider($providerName)) { Console::log('🔴 Logging adapter is disabled'); } else { - Console::log('🟢 Logging adapter is enabled (' . $providerName . ')'); + Console::log('🟢 Logging adapter is enabled ('.$providerName.')'); } \sleep(0.2); try { - Console::log("\n" . '[Connectivity]'); + Console::log("\n".'[Connectivity]'); } catch (\Throwable $th) { //throw $th; } $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - $configs = [ 'Console.DB' => Config::getParam('pools-console'), 'Projects.DB' => Config::getParam('pools-database'), @@ -123,12 +122,12 @@ class Doctor extends Action $adapter = $pools->get($database)->pop()->getResource(); if ($adapter->ping()) { - Console::success('🟢 ' . str_pad("{$key}({$database})", 50, '.') . 'connected'); + Console::success('🟢 '.str_pad("{$key}({$database})", 50, '.').'connected'); } else { - Console::error('🔴 ' . str_pad("{$key}({$database})", 47, '.') . 'disconnected'); + Console::error('🔴 '.str_pad("{$key}({$database})", 47, '.').'disconnected'); } } catch (\Throwable $th) { - Console::error('🔴 ' . str_pad("{$key}.({$database})", 47, '.') . 'disconnected'); + Console::error('🔴 '.str_pad("{$key}.({$database})", 47, '.').'disconnected'); } } } @@ -146,12 +145,12 @@ class Doctor extends Action $adapter = $pools->get($pool)->pop()->getResource(); if ($adapter->ping()) { - Console::success('🟢 ' . str_pad("{$key}({$pool})", 50, '.') . 'connected'); + Console::success('🟢 '.str_pad("{$key}({$pool})", 50, '.').'connected'); } else { - Console::error('🔴 ' . str_pad("{$key}({$pool})", 47, '.') . 'disconnected'); + Console::error('🔴 '.str_pad("{$key}({$pool})", 47, '.').'disconnected'); } } catch (\Throwable $th) { - Console::error('🔴 ' . str_pad("{$key}({$pool})", 47, '.') . 'disconnected'); + Console::error('🔴 '.str_pad("{$key}({$pool})", 47, '.').'disconnected'); } } } @@ -164,12 +163,12 @@ class Doctor extends Action ); if ((@$antivirus->ping())) { - Console::success('🟢 ' . str_pad("Antivirus", 50, '.') . 'connected'); + Console::success('🟢 '.str_pad('Antivirus', 50, '.').'connected'); } else { - Console::error('🔴 ' . str_pad("Antivirus", 47, '.') . 'disconnected'); + Console::error('🔴 '.str_pad('Antivirus', 47, '.').'disconnected'); } } catch (\Throwable $th) { - Console::error('🔴 ' . str_pad("Antivirus", 47, '.') . 'disconnected'); + Console::error('🔴 '.str_pad('Antivirus', 47, '.').'disconnected'); } } @@ -182,9 +181,9 @@ class Doctor extends Action $mail->AltBody = 'Hello World'; $mail->send(); - Console::success('🟢 ' . str_pad("SMTP", 50, '.') . 'connected'); + Console::success('🟢 '.str_pad('SMTP', 50, '.').'connected'); } catch (\Throwable $th) { - Console::error('🔴 ' . str_pad("SMTP", 47, '.') . 'disconnected'); + Console::error('🔴 '.str_pad('SMTP', 47, '.').'disconnected'); } \sleep(0.2); @@ -194,24 +193,24 @@ class Doctor extends Action foreach ( [ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES + 'Uploads' => APP_STORAGE_UPLOADS, + 'Cache' => APP_STORAGE_CACHE, + 'Config' => APP_STORAGE_CONFIG, + 'Certs' => APP_STORAGE_CERTIFICATES, ] as $key => $volume ) { $device = new Local($volume); if (\is_readable($device->getRoot())) { - Console::success('🟢 ' . $key . ' Volume is readable'); + Console::success('🟢 '.$key.' Volume is readable'); } else { - Console::error('🔴 ' . $key . ' Volume is unreadable'); + Console::error('🔴 '.$key.' Volume is unreadable'); } if (\is_writable($device->getRoot())) { - Console::success('🟢 ' . $key . ' Volume is writeable'); + Console::success('🟢 '.$key.' Volume is writeable'); } else { - Console::error('🔴 ' . $key . ' Volume is unwriteable'); + Console::error('🔴 '.$key.' Volume is unwriteable'); } } @@ -222,10 +221,10 @@ class Doctor extends Action foreach ( [ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES + 'Uploads' => APP_STORAGE_UPLOADS, + 'Cache' => APP_STORAGE_CACHE, + 'Config' => APP_STORAGE_CONFIG, + 'Certs' => APP_STORAGE_CERTIFICATES, ] as $key => $volume ) { $device = new Local($volume); @@ -233,32 +232,32 @@ class Doctor extends Action $percentage = (($device->getPartitionTotalSpace() - $device->getPartitionFreeSpace()) / $device->getPartitionTotalSpace()) * 100; - $message = $key . ' Volume has ' . Storage::human($device->getPartitionFreeSpace()) . ' free space (' . \round($percentage, 2) . '% used)'; + $message = $key.' Volume has '.Storage::human($device->getPartitionFreeSpace()).' free space ('.\round($percentage, 2).'% used)'; if ($percentage < 80) { - Console::success('🟢 ' . $message); + Console::success('🟢 '.$message); } else { - Console::error('🔴 ' . $message); + Console::error('🔴 '.$message); } } try { if (App::isProduction()) { Console::log(''); - $version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost') . '/v1/health/version'), true); + $version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost').'/v1/health/version'), true); if ($version && isset($version['version'])) { if (\version_compare($version['version'], App::getEnv('_APP_VERSION', 'UNKNOWN')) === 0) { - Console::info('You are running the latest version of ' . APP_NAME . '! 🥳'); + Console::info('You are running the latest version of '.APP_NAME.'! 🥳'); } else { - Console::info('A new version (' . $version['version'] . ') is available! 🥳' . "\n"); + Console::info('A new version ('.$version['version'].') is available! 🥳'."\n"); } } else { - Console::error('Failed to check for a newer version' . "\n"); + Console::error('Failed to check for a newer version'."\n"); } } } catch (\Throwable $th) { - Console::error('Failed to check for a newer version' . "\n"); + Console::error('Failed to check for a newer version'."\n"); } } } diff --git a/src/Appwrite/Platform/Tasks/Hamster.php b/src/Appwrite/Platform/Tasks/Hamster.php index 5b04c338eb..85545f1a19 100644 --- a/src/Appwrite/Platform/Tasks/Hamster.php +++ b/src/Appwrite/Platform/Tasks/Hamster.php @@ -4,17 +4,17 @@ namespace Appwrite\Platform\Tasks; use Appwrite\Network\Validator\Origin; use Exception; -use Utopia\App; -use Utopia\Platform\Action; -use Utopia\Cache\Cache; -use Utopia\CLI\Console; -use Utopia\Database\Database; -use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Analytics\Adapter\Mixpanel; use Utopia\Analytics\Event; +use Utopia\App; +use Utopia\Cache\Cache; +use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; +use Utopia\Platform\Action; use Utopia\Pools\Group; class Hamster extends Action @@ -67,7 +67,8 @@ class Hamster extends Action * Skip user projects with id 'console' */ if ($project->getId() === 'console') { - Console::info("Skipping project console"); + Console::info('Skipping project console'); + return; } @@ -82,7 +83,7 @@ class Hamster extends Action $dbForProject = new Database($adapter, $cache); $dbForProject->setDefaultDatabase('appwrite'); - $dbForProject->setNamespace('_' . $project->getInternalId()); + $dbForProject->setNamespace('_'.$project->getInternalId()); $statsPerProject = []; @@ -101,7 +102,7 @@ class Hamster extends Action $statsPerProject['custom_functions'] = $dbForProject->count('functions', [], APP_LIMIT_COUNT); foreach (\array_keys(Config::getParam('runtimes')) as $runtime) { - $statsPerProject['custom_functions_' . $runtime] = $dbForProject->count('functions', [ + $statsPerProject['custom_functions_'.$runtime] = $dbForProject->count('functions', [ Query::equal('runtime', [$runtime]), ], APP_LIMIT_COUNT); } @@ -116,7 +117,7 @@ class Hamster extends Action $teamInternalId = $project->getAttribute('teamInternalId', null); if ($teamInternalId) { $statsPerProject['custom_organization_members'] = $dbForConsole->count('memberships', [ - Query::equal('teamInternalId', [$teamInternalId]) + Query::equal('teamInternalId', [$teamInternalId]), ], APP_LIMIT_COUNT); } else { $statsPerProject['custom_organization_members'] = 0; @@ -128,8 +129,8 @@ class Hamster extends Action Query::equal('teamInternalId', [$teamInternalId]), ]); - if (!$membership || $membership->isEmpty()) { - throw new Exception('Membership not found. Skipping project : ' . $project->getId()); + if (! $membership || $membership->isEmpty()) { + throw new Exception('Membership not found. Skipping project : '.$project->getId()); } $userInternalId = $membership->getAttribute('userInternalId', null); @@ -146,42 +147,42 @@ class Hamster extends Action /** Get Domains */ $statsPerProject['custom_domains'] = $dbForConsole->count('domains', [ Query::equal('projectInternalId', [$project->getInternalId()]), - Query::limit(APP_LIMIT_COUNT) + Query::limit(APP_LIMIT_COUNT), ]); /** Get Platforms */ $platforms = $dbForConsole->find('platforms', [ Query::equal('projectInternalId', [$project->getInternalId()]), - Query::limit(APP_LIMIT_COUNT) + Query::limit(APP_LIMIT_COUNT), ]); - $statsPerProject['custom_platforms_web'] = sizeof(array_filter($platforms, function ($platform) { + $statsPerProject['custom_platforms_web'] = count(array_filter($platforms, function ($platform) { return $platform['type'] === 'web'; })); - $statsPerProject['custom_platforms_android'] = sizeof(array_filter($platforms, function ($platform) { + $statsPerProject['custom_platforms_android'] = count(array_filter($platforms, function ($platform) { return $platform['type'] === 'android'; })); - $statsPerProject['custom_platforms_apple'] = sizeof(array_filter($platforms, function ($platform) { + $statsPerProject['custom_platforms_apple'] = count(array_filter($platforms, function ($platform) { return str_contains($platform['type'], 'apple'); })); - $statsPerProject['custom_platforms_flutter'] = sizeof(array_filter($platforms, function ($platform) { + $statsPerProject['custom_platforms_flutter'] = count(array_filter($platforms, function ($platform) { return str_contains($platform['type'], 'flutter'); })); $flutterPlatforms = [Origin::CLIENT_TYPE_FLUTTER_ANDROID, Origin::CLIENT_TYPE_FLUTTER_IOS, Origin::CLIENT_TYPE_FLUTTER_MACOS, Origin::CLIENT_TYPE_FLUTTER_WINDOWS, Origin::CLIENT_TYPE_FLUTTER_LINUX]; foreach ($flutterPlatforms as $flutterPlatform) { - $statsPerProject['custom_platforms_' . $flutterPlatform] = sizeof(array_filter($platforms, function ($platform) use ($flutterPlatform) { + $statsPerProject['custom_platforms_'.$flutterPlatform] = count(array_filter($platforms, function ($platform) use ($flutterPlatform) { return $platform['type'] === $flutterPlatform; })); } $statsPerProject['custom_platforms_api_keys'] = $dbForConsole->count('keys', [ Query::equal('projectInternalId', [$project->getInternalId()]), - Query::limit(APP_LIMIT_COUNT) + Query::limit(APP_LIMIT_COUNT), ]); /** Get Usage $statsPerProject */ @@ -209,17 +210,17 @@ class Hamster extends Action Query::orderDesc('time'), ]); - $statsPerProject[$key . '_' . $periodKey] = []; + $statsPerProject[$key.'_'.$periodKey] = []; foreach ($requestDocs as $requestDoc) { - $statsPerProject[$key . '_' . $periodKey][] = [ + $statsPerProject[$key.'_'.$periodKey][] = [ 'value' => $requestDoc->getAttribute('value'), 'date' => $requestDoc->getAttribute('time'), ]; } - $statsPerProject[$key . '_' . $periodKey] = array_reverse($statsPerProject[$key . '_' . $periodKey]); + $statsPerProject[$key.'_'.$periodKey] = array_reverse($statsPerProject[$key.'_'.$periodKey]); // Calculate aggregate of each metric - $statsPerProject[$key . '_' . $periodKey] = array_sum(array_column($statsPerProject[$key . '_' . $periodKey], 'value')); + $statsPerProject[$key.'_'.$periodKey] = array_sum(array_column($statsPerProject[$key.'_'.$periodKey], 'value')); } } }); @@ -228,11 +229,11 @@ class Hamster extends Action /** Send data to mixpanel */ $res = $this->mixpanel->createProfile($statsPerProject['email'], '', [ 'name' => $statsPerProject['name'], - 'email' => $statsPerProject['email'] + 'email' => $statsPerProject['email'], ]); - if (!$res) { - Console::error('Failed to create user profile for project: ' . $project->getId()); + if (! $res) { + Console::error('Failed to create user profile for project: '.$project->getId()); } $event = new Event(); @@ -240,12 +241,12 @@ class Hamster extends Action ->setName('Project Daily Usage') ->setProps($statsPerProject); $res = $this->mixpanel->createEvent($event); - if (!$res) { - Console::error('Failed to create event for project: ' . $project->getId()); + if (! $res) { + Console::error('Failed to create event for project: '.$project->getId()); } } } catch (Exception $e) { - Console::error('Failed to send stats for project: ' . $project->getId()); + Console::error('Failed to send stats for project: '.$project->getId()); Console::error($e->getMessage()); } finally { $pools @@ -257,9 +258,8 @@ class Hamster extends Action public function action(Group $pools, Cache $cache, Database $dbForConsole): void { - Console::title('Cloud Hamster V1'); - Console::success(APP_NAME . ' cloud hamster process has started'); + Console::success(APP_NAME.' cloud hamster process has started'); $sleep = (int) App::getEnv('_APP_HAMSTER_INTERVAL', '30'); // 30 seconds (by default) @@ -278,7 +278,7 @@ class Hamster extends Action $delay = $next->getTimestamp() - $now->getTimestamp(); } - Console::log('[' . $now->format("Y-m-d H:i:s.v") . '] Delaying for ' . $delay . ' setting loop to [' . $next->format("Y-m-d H:i:s.v") . ']'); + Console::log('['.$now->format('Y-m-d H:i:s.v').'] Delaying for '.$delay.' setting loop to ['.$next->format('Y-m-d H:i:s.v').']'); Console::loop(function () use ($pools, $cache, $dbForConsole, $sleep) { $now = date('d-m-Y H:i:s', time()); @@ -325,12 +325,12 @@ class Hamster extends Action $results = $dbForConsole->find($collection, \array_merge([ Query::limit($limit), - Query::offset($count) + Query::offset($count), ])); $sum = count($results); - Console::log('Processing chunk #' . $chunk . '. Found ' . $sum . ' documents'); + Console::log('Processing chunk #'.$chunk.'. Found '.$sum.' documents'); foreach ($results as $document) { call_user_func($callback, $dbForConsole, $document); @@ -340,12 +340,11 @@ class Hamster extends Action $executionEnd = \microtime(true); - Console::log("Processed {$count} document by group in " . ($executionEnd - $executionStart) . " seconds"); + Console::log("Processed {$count} document by group in ".($executionEnd - $executionStart).' seconds'); } protected function getStatsPerOrganization(Database $dbForConsole) { - $this->calculateByGroup('teams', $dbForConsole, function (Database $dbForConsole, Document $document) { try { $statsPerOrganization = []; @@ -358,8 +357,8 @@ class Hamster extends Action Query::equal('teamInternalId', [$document->getInternalId()]), ]); - if (!$membership || $membership->isEmpty()) { - throw new Exception('Membership not found. Skipping organization : ' . $document->getId()); + if (! $membership || $membership->isEmpty()) { + throw new Exception('Membership not found. Skipping organization : '.$document->getId()); } $userInternalId = $membership->getAttribute('userInternalId', null); @@ -380,11 +379,11 @@ class Hamster extends Action /** Number of projects in this organization */ $statsPerOrganization['projects'] = $dbForConsole->count('projects', [ Query::equal('teamId', [$document->getId()]), - Query::limit(APP_LIMIT_COUNT) + Query::limit(APP_LIMIT_COUNT), ]); - if (!isset($statsPerOrganization['email'])) { - throw new Exception('Email not found. Skipping organization : ' . $document->getId()); + if (! isset($statsPerOrganization['email'])) { + throw new Exception('Email not found. Skipping organization : '.$document->getId()); } $event = new Event(); @@ -392,8 +391,8 @@ class Hamster extends Action ->setName('Organization Daily Usage') ->setProps($statsPerOrganization); $res = $this->mixpanel->createEvent($event); - if (!$res) { - throw new Exception('Failed to create event for organization : ' . $document->getId()); + if (! $res) { + throw new Exception('Failed to create event for organization : '.$document->getId()); } } catch (Exception $e) { Console::error($e->getMessage()); @@ -419,11 +418,11 @@ class Hamster extends Action /** Number of teams this user is a part of */ $statsPerUser['memberships'] = $dbForConsole->count('memberships', [ Query::equal('userInternalId', [$document->getInternalId()]), - Query::limit(APP_LIMIT_COUNT) + Query::limit(APP_LIMIT_COUNT), ]); - if (!isset($statsPerUser['email'])) { - throw new Exception('User has no email: ' . $document->getId()); + if (! isset($statsPerUser['email'])) { + throw new Exception('User has no email: '.$document->getId()); } /** Send data to mixpanel */ @@ -433,8 +432,8 @@ class Hamster extends Action ->setProps($statsPerUser); $res = $this->mixpanel->createEvent($event); - if (!$res) { - throw new Exception('Failed to create user profile for user: ' . $document->getId()); + if (! $res) { + throw new Exception('Failed to create user profile for user: '.$document->getId()); } } catch (Exception $e) { Console::error($e->getMessage()); diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index be12eadf62..9c25320b6d 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -9,8 +9,8 @@ use Appwrite\Utopia\View; use Utopia\Analytics\GoogleAnalytics; use Utopia\CLI\Console; use Utopia\Config\Config; -use Utopia\Validator\Text; use Utopia\Platform\Action; +use Utopia\Validator\Text; class Install extends Action { @@ -70,19 +70,19 @@ class Install extends Action Console::success('Starting Appwrite installation...'); // Create directory with write permissions - if (null !== $path && !\file_exists(\dirname($path))) { - if (!@\mkdir(\dirname($path), 0755, true)) { - Console::error('Can\'t create directory ' . \dirname($path)); + if (null !== $path && ! \file_exists(\dirname($path))) { + if (! @\mkdir(\dirname($path), 0755, true)) { + Console::error('Can\'t create directory '.\dirname($path)); Console::exit(1); } } - $data = @file_get_contents($path . '/docker-compose.yml'); + $data = @file_get_contents($path.'/docker-compose.yml'); if ($data !== false) { $time = \time(); - Console::info('Compose file found, creating backup: docker-compose.yml.' . $time . '.backup'); - file_put_contents($path . '/docker-compose.yml.' . $time . '.backup', $data); + Console::info('Compose file found, creating backup: docker-compose.yml.'.$time.'.backup'); + file_put_contents($path.'/docker-compose.yml.'.$time.'.backup', $data); $compose = new Compose($data); $appwrite = $compose->getService('appwrite'); $oldVersion = ($appwrite) ? $appwrite->getImageVersion() : null; @@ -91,14 +91,14 @@ class Install extends Action } catch (\Throwable $th) { $ports = [ $defaultHTTPPort => $defaultHTTPPort, - $defaultHTTPSPort => $defaultHTTPSPort + $defaultHTTPSPort => $defaultHTTPSPort, ]; Console::warning('Traefik not found. Falling back to default ports.'); } if ($oldVersion) { foreach ($compose->getServices() as $service) { // Fetch all env vars from previous compose file - if (!$service) { + if (! $service) { continue; } @@ -116,11 +116,11 @@ class Install extends Action } } - $data = @file_get_contents($path . '/.env'); + $data = @file_get_contents($path.'/.env'); if ($data !== false) { // Fetch all env vars from previous .env file - Console::info('Env file found, creating backup: .env.' . $time . '.backup'); - file_put_contents($path . '/.env.' . $time . '.backup', $data); + Console::info('Env file found, creating backup: .env.'.$time.'.backup'); + file_put_contents($path.'/.env.'.$time.'.backup', $data); $env = new Env($data); foreach ($env->list() as $key => $value) { @@ -148,40 +148,44 @@ class Install extends Action } if (empty($httpPort)) { - $httpPort = Console::confirm('Choose your server HTTP port: (default: ' . $defaultHTTPPort . ')'); + $httpPort = Console::confirm('Choose your server HTTP port: (default: '.$defaultHTTPPort.')'); $httpPort = ($httpPort) ? $httpPort : $defaultHTTPPort; } if (empty($httpsPort)) { - $httpsPort = Console::confirm('Choose your server HTTPS port: (default: ' . $defaultHTTPSPort . ')'); + $httpsPort = Console::confirm('Choose your server HTTPS port: (default: '.$defaultHTTPSPort.')'); $httpsPort = ($httpsPort) ? $httpsPort : $defaultHTTPSPort; } $input = []; foreach ($vars as $var) { - if (!empty($var['filter']) && ($interactive !== 'Y' || !Console::isInteractive())) { + if (! empty($var['filter']) && ($interactive !== 'Y' || ! Console::isInteractive())) { if ($data && $var['default'] !== null) { $input[$var['name']] = $var['default']; + continue; } if ($var['filter'] === 'token') { $input[$var['name']] = Auth::tokenGenerator(); + continue; } if ($var['filter'] === 'password') { $input[$var['name']] = Auth::passwordGenerator(); + continue; } } - if (!$var['required'] || !Console::isInteractive() || $interactive !== 'Y') { + if (! $var['required'] || ! Console::isInteractive() || $interactive !== 'Y') { $input[$var['name']] = $var['default']; + continue; } - $input[$var['name']] = Console::confirm($var['question'] . ' (default: \'' . $var['default'] . '\')'); + $input[$var['name']] = Console::confirm($var['question'].' (default: \''.$var['default'].'\')'); if (empty($input[$var['name']])) { $input[$var['name']] = $var['default']; @@ -191,38 +195,36 @@ class Install extends Action if ($input[$var['name']] !== 'localhost') { Console::warning("\nIf you haven't already done so, set the following record for {$input[$var['name']]} on your DNS provider:\n"); $mask = "%-15.15s %-10.10s %-30.30s\n"; - printf($mask, "Type", "Name", "Value"); - printf($mask, "A or AAAA", "@", ""); + printf($mask, 'Type', 'Name', 'Value'); + printf($mask, 'A or AAAA', '@', ''); Console::warning("\nUse 'AAAA' if you're using an IPv6 address and 'A' if you're using an IPv4 address.\n"); } } } - $templateForCompose = new View(__DIR__ . '/../views/install/compose.phtml'); - $templateForEnv = new View(__DIR__ . '/../views/install/env.phtml'); + $templateForCompose = new View(__DIR__.'/../views/install/compose.phtml'); + $templateForEnv = new View(__DIR__.'/../views/install/env.phtml'); $templateForCompose ->setParam('httpPort', $httpPort) ->setParam('httpsPort', $httpsPort) ->setParam('version', APP_VERSION_STABLE) ->setParam('organization', $organization) - ->setParam('image', $image) - ; + ->setParam('image', $image); $templateForEnv - ->setParam('vars', $input) - ; + ->setParam('vars', $input); - if (!file_put_contents($path . '/docker-compose.yml', $templateForCompose->render(false))) { + if (! file_put_contents($path.'/docker-compose.yml', $templateForCompose->render(false))) { $message = 'Failed to save Docker Compose file'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); + $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message); Console::error($message); Console::exit(1); } - if (!file_put_contents($path . '/.env', $templateForEnv->render(false))) { + if (! file_put_contents($path.'/.env', $templateForEnv->render(false))) { $message = 'Failed to save environment variables file'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); + $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message); Console::error($message); Console::exit(1); } @@ -233,23 +235,23 @@ class Install extends Action foreach ($input as $key => $value) { if ($value) { - $env .= $key . '=' . \escapeshellarg($value) . ' '; + $env .= $key.'='.\escapeshellarg($value).' '; } } - Console::log("Running \"docker compose up -d --remove-orphans --renew-anon-volumes\""); + Console::log('Running "docker compose up -d --remove-orphans --renew-anon-volumes"'); $exit = Console::execute("${env} docker compose --project-directory {$path} up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr); if ($exit !== 0) { $message = 'Failed to install Appwrite dockers'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); + $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message); Console::error($message); Console::error($stderr); Console::exit($exit); } else { $message = 'Appwrite installed successfully'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); + $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message); Console::success($message); } } diff --git a/src/Appwrite/Platform/Tasks/Maintenance.php b/src/Appwrite/Platform/Tasks/Maintenance.php index 0739923e34..df93feb4af 100644 --- a/src/Appwrite/Platform/Tasks/Maintenance.php +++ b/src/Appwrite/Platform/Tasks/Maintenance.php @@ -2,14 +2,13 @@ namespace Appwrite\Platform\Tasks; -use Appwrite\Auth\Auth; use Appwrite\Event\Certificate; use Appwrite\Event\Delete; use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Database; -use Utopia\Database\Document; use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Platform\Action; @@ -31,7 +30,7 @@ class Maintenance extends Action public function action(Database $dbForConsole): void { Console::title('Maintenance V1'); - Console::success(APP_NAME . ' maintenance process v1 has started'); + Console::success(APP_NAME.' maintenance process v1 has started'); function notifyDeleteExecutionLogs(int $interval) { @@ -85,20 +84,19 @@ class Maintenance extends Action $time = DateTime::now(); $certificates = $dbForConsole->find('certificates', [ - Query::lessThan('attempts', 5), // Maximum 5 attempts - Query::lessThanEqual('renewDate', $time), // includes 60 days cooldown (we have 30 days to renew) - Query::limit(200), // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains) + Query::lessThan('attempts', 5), // Maximum 5 attempts + Query::lessThanEqual('renewDate', $time), // includes 60 days cooldown (we have 30 days to renew) + Query::limit(200), // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains) ]); - if (\count($certificates) > 0) { - Console::info("[{$time}] Found " . \count($certificates) . " certificates for renewal, scheduling jobs."); + Console::info("[{$time}] Found ".\count($certificates).' certificates for renewal, scheduling jobs.'); $event = new Certificate(); foreach ($certificates as $certificate) { $event ->setDomain(new Document([ - 'domain' => $certificate->getAttribute('domain') + 'domain' => $certificate->getAttribute('domain'), ])) ->trigger(); } @@ -109,7 +107,6 @@ class Maintenance extends Action function notifyDeleteCache($interval) { - (new Delete()) ->setType(DELETE_TYPE_CACHE_BY_TIMESTAMP) ->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * $interval)) @@ -118,7 +115,6 @@ class Maintenance extends Action function notifyDeleteSchedules($interval) { - (new Delete()) ->setType(DELETE_TYPE_SCHEDULES) ->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * $interval)) diff --git a/src/Appwrite/Platform/Tasks/Migrate.php b/src/Appwrite/Platform/Tasks/Migrate.php index 90b4234109..b4112f8d3f 100644 --- a/src/Appwrite/Platform/Tasks/Migrate.php +++ b/src/Appwrite/Platform/Tasks/Migrate.php @@ -2,14 +2,14 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; -use Utopia\CLI\Console; use Appwrite\Migration\Migration; use Utopia\App; -use Utopia\Cache\Cache; use Utopia\Cache\Adapter\Redis as RedisCache; +use Utopia\Cache\Cache; +use Utopia\CLI\Console; use Utopia\Database\Document; use Utopia\Database\Validator\Authorization; +use Utopia\Platform\Action; use Utopia\Registry\Registry; use Utopia\Validator\Text; @@ -35,22 +35,23 @@ class Migrate extends Action try { $redis->del($redis->keys("cache-_{$project->getInternalId()}:*")); } catch (\Throwable $th) { - Console::error('Failed to clear project ("' . $project->getId() . '") cache with error: ' . $th->getMessage()); + Console::error('Failed to clear project ("'.$project->getId().'") cache with error: '.$th->getMessage()); } } public function action(string $version, Registry $register) { Authorization::disable(); - if (!array_key_exists($version, Migration::$versions)) { + if (! array_key_exists($version, Migration::$versions)) { Console::error("Version {$version} not found."); Console::exit(1); + return; } $app = new App('UTC'); - Console::success('Starting Data Migration to version ' . $version); + Console::success('Starting Data Migration to version '.$version); $dbPool = $register->get('dbPool', true); $redis = $register->get('cache', true); @@ -78,10 +79,10 @@ class Migrate extends Action $totalProjects = $dbForConsole->count('projects') + 1; } - $class = 'Appwrite\\Migration\\Version\\' . Migration::$versions[$version]; + $class = 'Appwrite\\Migration\\Version\\'.Migration::$versions[$version]; $migration = new $class(); - while (!empty($projects)) { + while (! empty($projects)) { foreach ($projects as $project) { /** * Skip user projects with id 'console' @@ -99,7 +100,7 @@ class Migrate extends Action ->setProject($project, $projectDB, $dbForConsole) ->execute(); } catch (\Throwable $th) { - Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage()); + Console::error('Failed to update project ("'.$project->getId().'") version with error: '.$th->getMessage()); throw $th; } @@ -112,7 +113,7 @@ class Migrate extends Action $offset = $offset + $limit; $count = $count + $sum; - Console::log('Migrated ' . $count . '/' . $totalProjects . ' projects...'); + Console::log('Migrated '.$count.'/'.$totalProjects.' projects...'); } Swoole\Event::wait(); // Wait for Coroutines to finish diff --git a/src/Appwrite/Platform/Tasks/PatchCreateMissingSchedules.php b/src/Appwrite/Platform/Tasks/PatchCreateMissingSchedules.php index 74ef644498..9724818f70 100644 --- a/src/Appwrite/Platform/Tasks/PatchCreateMissingSchedules.php +++ b/src/Appwrite/Platform/Tasks/PatchCreateMissingSchedules.php @@ -2,14 +2,14 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; use Utopia\CLI\Console; +use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; -use Utopia\Database\Query; -use Utopia\Database\Database; use Utopia\Database\Helpers\ID; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; +use Utopia\Platform\Action; class PatchCreateMissingSchedules extends Action { @@ -36,7 +36,7 @@ class PatchCreateMissingSchedules extends Action Authorization::setDefaultStatus(false); Console::title('PatchCreateMissingSchedules V1'); - Console::success(APP_NAME . ' PatchCreateMissingSchedules v1 has started'); + Console::success(APP_NAME.' PatchCreateMissingSchedules v1 has started'); $limit = 100; $projectCursor = null; @@ -52,7 +52,7 @@ class PatchCreateMissingSchedules extends Action } foreach ($projects as $project) { - Console::log("Checking Project " . $project->getAttribute('name') . " (" . $project->getId() . ")"); + Console::log('Checking Project '.$project->getAttribute('name').' ('.$project->getId().')'); $dbForProject = $getProjectDB($project); $functionCursor = null; @@ -79,11 +79,11 @@ class PatchCreateMissingSchedules extends Action 'resourceId' => $functionId, 'resourceUpdatedAt' => DateTime::now(), 'projectId' => $project->getId(), - 'schedule' => $function->getAttribute('schedule'), - 'active' => !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')), + 'schedule' => $function->getAttribute('schedule'), + 'active' => ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')), ])); - Console::success('Recreated schedule for function ' . $functionId); + Console::success('Recreated schedule for function '.$functionId); } } diff --git a/src/Appwrite/Platform/Tasks/PatchDeleteProjectCollections.php b/src/Appwrite/Platform/Tasks/PatchDeleteProjectCollections.php index a909e68595..3a70e239cb 100644 --- a/src/Appwrite/Platform/Tasks/PatchDeleteProjectCollections.php +++ b/src/Appwrite/Platform/Tasks/PatchDeleteProjectCollections.php @@ -3,11 +3,11 @@ namespace Appwrite\Platform\Tasks; use Utopia\App; -use Utopia\Platform\Action; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Query; +use Utopia\Platform\Action; use Utopia\Pools\Group; use Utopia\Validator\Numeric; @@ -31,7 +31,6 @@ class PatchDeleteProjectCollections extends Action public function __construct() { - $this ->desc('Delete unnecessary project collections') ->param('offset', 0, new Numeric(), 'Resume deletion from param pos', true) @@ -48,7 +47,7 @@ class PatchDeleteProjectCollections extends Action //docker compose exec -t appwrite patch-delete-project-collections Console::title('Delete project collections V1'); - Console::success(APP_NAME . ' delete project collections has started'); + Console::success(APP_NAME.' delete project collections has started'); /* Initialise new Utopia app */ $app = new App('UTC'); @@ -63,9 +62,8 @@ class PatchDeleteProjectCollections extends Action $limit = 50; $sum = 50; $offset = $offset; - while (!empty($projects)) { + while (! empty($projects)) { foreach ($projects as $project) { - /** * Skip user projects with id 'console' */ @@ -84,7 +82,7 @@ class PatchDeleteProjectCollections extends Action $dbForProject = new Database($adapter, $cache); $dbForProject->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - $dbForProject->setNamespace('_' . $project->getInternalId()); + $dbForProject->setNamespace('_'.$project->getInternalId()); foreach ($this->names as $name) { if (empty($name)) { @@ -92,14 +90,14 @@ class PatchDeleteProjectCollections extends Action } if ($dbForProject->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), $name)) { if ($dbForProject->deleteCollection($name)) { - Console::log('Deleted ' . $name); + Console::log('Deleted '.$name); } else { - Console::error('Failed to delete ' . $name); + Console::error('Failed to delete '.$name); } } } } catch (\Throwable $th) { - Console::error('Failed on project ("' . $project->getId() . '") version with error: ' . $th->getMessage()); + Console::error('Failed on project ("'.$project->getId().'") version with error: '.$th->getMessage()); } finally { $pools ->get($db) @@ -114,14 +112,14 @@ class PatchDeleteProjectCollections extends Action Query::offset($offset), ]); - if (!empty($projects)) { - Console::log('Querying..... offset=' . $offset . ' , limit=' . $limit . ', count=' . $count); + if (! empty($projects)) { + Console::log('Querying..... offset='.$offset.' , limit='.$limit.', count='.$count); } $offset = $offset + $limit; $count = $count + $sum; } - Console::log('Iterated through ' . $count - 1 . '/' . $totalProjects . ' projects...'); + Console::log('Iterated through '.$count - 1 .'/'.$totalProjects.' projects...'); $pools ->get('console') ->reclaim(); diff --git a/src/Appwrite/Platform/Tasks/PatchDeleteScheduleUpdatedAtAttribute.php b/src/Appwrite/Platform/Tasks/PatchDeleteScheduleUpdatedAtAttribute.php index 95a7c4ffe1..b8fd8baaa2 100644 --- a/src/Appwrite/Platform/Tasks/PatchDeleteScheduleUpdatedAtAttribute.php +++ b/src/Appwrite/Platform/Tasks/PatchDeleteScheduleUpdatedAtAttribute.php @@ -2,11 +2,11 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; use Utopia\CLI\Console; -use Utopia\Database\Query; use Utopia\Database\Database; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; +use Utopia\Platform\Action; use Utopia\Pools\Group; class PatchDeleteScheduleUpdatedAtAttribute extends Action @@ -35,7 +35,7 @@ class PatchDeleteScheduleUpdatedAtAttribute extends Action Authorization::setDefaultStatus(false); Console::title('PatchDeleteScheduleUpdatedAtAttribute V1'); - Console::success(APP_NAME . ' PatchDeleteScheduleUpdatedAtAttribute v1 has started'); + Console::success(APP_NAME.' PatchDeleteScheduleUpdatedAtAttribute v1 has started'); $limit = 100; $projectCursor = null; @@ -51,7 +51,7 @@ class PatchDeleteScheduleUpdatedAtAttribute extends Action } foreach ($projects as $project) { - Console::log("Checking Project " . $project->getAttribute('name') . " (" . $project->getId() . ")"); + Console::log('Checking Project '.$project->getAttribute('name').' ('.$project->getId().')'); $dbForProject = $getProjectDB($project); try { diff --git a/src/Appwrite/Platform/Tasks/SDKs.php b/src/Appwrite/Platform/Tasks/SDKs.php index f70ae8bd60..4b2c07e17c 100644 --- a/src/Appwrite/Platform/Tasks/SDKs.php +++ b/src/Appwrite/Platform/Tasks/SDKs.php @@ -2,8 +2,8 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; use Appwrite\SDK\Language\Android; +use Appwrite\SDK\Language\Apple; use Appwrite\SDK\Language\CLI; use Appwrite\SDK\Language\Dart; use Appwrite\SDK\Language\Deno; @@ -18,14 +18,14 @@ use Appwrite\SDK\Language\Python; use Appwrite\SDK\Language\REST; use Appwrite\SDK\Language\Ruby; use Appwrite\SDK\Language\Swift; -use Exception; -use Throwable; -use Appwrite\SDK\Language\Apple; use Appwrite\SDK\Language\Web; use Appwrite\SDK\SDK; use Appwrite\Spec\Swagger2; +use Exception; +use Throwable; use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Platform\Action; class SDKs extends Action { @@ -44,14 +44,14 @@ class SDKs extends Action public function action(): void { $platforms = Config::getParam('platforms'); - $selectedPlatform = Console::confirm('Choose Platform ("' . APP_PLATFORM_CLIENT . '", "' . APP_PLATFORM_SERVER . '", "' . APP_PLATFORM_CONSOLE . '" or "*" for all):'); + $selectedPlatform = Console::confirm('Choose Platform ("'.APP_PLATFORM_CLIENT.'", "'.APP_PLATFORM_SERVER.'", "'.APP_PLATFORM_CONSOLE.'" or "*" for all):'); $selectedSDK = \strtolower(Console::confirm('Choose SDK ("*" for all):')); $version = Console::confirm('Choose an Appwrite version'); $git = (Console::confirm('Should we use git push? (yes/no)') == 'yes'); $production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false; $message = ($git) ? Console::confirm('Please enter your commit message:') : ''; - if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', '1.3.x', 'latest'])) { + if (! in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', '1.3.x', 'latest'])) { throw new Exception('Unknown version given'); } @@ -65,30 +65,31 @@ class SDKs extends Action continue; } - if (!$language['enabled']) { - Console::warning($language['name'] . ' for ' . $platform['name'] . ' is disabled'); + if (! $language['enabled']) { + Console::warning($language['name'].' for '.$platform['name'].' is disabled'); + continue; } - Console::info('Fetching API Spec for ' . $language['name'] . ' for ' . $platform['name'] . ' (version: ' . $version . ')'); + Console::info('Fetching API Spec for '.$language['name'].' for '.$platform['name'].' (version: '.$version.')'); - $spec = file_get_contents(__DIR__ . '/../../../../app/config/specs/swagger2-' . $version . '-' . $language['family'] . '.json'); + $spec = file_get_contents(__DIR__.'/../../../../app/config/specs/swagger2-'.$version.'-'.$language['family'].'.json'); $cover = 'https://appwrite.io/images/github.png'; - $result = \realpath(__DIR__ . '/../../../../app') . '/sdks/' . $key . '-' . $language['key']; - $resultExamples = \realpath(__DIR__ . '/../../../..') . '/docs/examples/' . $version . '/' . $key . '-' . $language['key']; - $target = \realpath(__DIR__ . '/../../../../app') . '/sdks/git/' . $language['key'] . '/'; - $readme = \realpath(__DIR__ . '/../../../../docs/sdks/' . $language['key'] . '/README.md'); + $result = \realpath(__DIR__.'/../../../../app').'/sdks/'.$key.'-'.$language['key']; + $resultExamples = \realpath(__DIR__.'/../../../..').'/docs/examples/'.$version.'/'.$key.'-'.$language['key']; + $target = \realpath(__DIR__.'/../../../../app').'/sdks/git/'.$language['key'].'/'; + $readme = \realpath(__DIR__.'/../../../../docs/sdks/'.$language['key'].'/README.md'); $readme = ($readme) ? \file_get_contents($readme) : ''; - $gettingStarted = \realpath(__DIR__ . '/../../../../docs/sdks/' . $language['key'] . '/GETTING_STARTED.md'); + $gettingStarted = \realpath(__DIR__.'/../../../../docs/sdks/'.$language['key'].'/GETTING_STARTED.md'); $gettingStarted = ($gettingStarted) ? \file_get_contents($gettingStarted) : ''; - $examples = \realpath(__DIR__ . '/../../../../docs/sdks/' . $language['key'] . '/EXAMPLES.md'); + $examples = \realpath(__DIR__.'/../../../../docs/sdks/'.$language['key'].'/EXAMPLES.md'); $examples = ($examples) ? \file_get_contents($examples) : ''; - $changelog = \realpath(__DIR__ . '/../../../../docs/sdks/' . $language['key'] . '/CHANGELOG.md'); + $changelog = \realpath(__DIR__.'/../../../../docs/sdks/'.$language['key'].'/CHANGELOG.md'); $changelog = ($changelog) ? \file_get_contents($changelog) : '# Change Log'; - $warning = '**This SDK is compatible with Appwrite server version ' . $version . '. For older versions, please check [previous releases](' . $language['url'] . '/releases).**'; + $warning = '**This SDK is compatible with Appwrite server version '.$version.'. For older versions, please check [previous releases]('.$language['url'].'/releases).**'; $license = 'BSD-3-Clause'; - $licenseContent = 'Copyright (c) ' . date('Y') . ' Appwrite (https://appwrite.io) and individual contributors. + $licenseContent = 'Copyright (c) '.date('Y').' Appwrite (https://appwrite.io) and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -142,7 +143,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $config = new Node(); $config->setNPMPackage('node-appwrite'); $config->setBowerPackage('appwrite'); - $warning = $warning . "\n\n > This is the Node.js SDK for integrating with Appwrite from your Node.js server-side code. + $warning = $warning."\n\n > This is the Node.js SDK for integrating with Appwrite from your Node.js server-side code. If you're looking to integrate from the browser, you should check [appwrite/sdk-for-web](https://github.com/appwrite/sdk-for-web)"; break; case 'deno': @@ -168,14 +169,14 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND case 'dart': $config = new Dart(); $config->setPackageName('dart_appwrite'); - $warning = $warning . "\n\n > This is the Dart SDK for integrating with Appwrite from your Dart server-side code. If you're looking for the Flutter SDK you should check [appwrite/sdk-for-flutter](https://github.com/appwrite/sdk-for-flutter)"; + $warning = $warning."\n\n > This is the Dart SDK for integrating with Appwrite from your Dart server-side code. If you're looking for the Flutter SDK you should check [appwrite/sdk-for-flutter](https://github.com/appwrite/sdk-for-flutter)"; break; case 'go': $config = new Go(); break; case 'swift': $config = new Swift(); - $warning = $warning . "\n\n > This is the Swift SDK for integrating with Appwrite from your Swift server-side code. If you're looking for the Apple SDK you should check [appwrite/sdk-for-apple](https://github.com/appwrite/sdk-for-apple)"; + $warning = $warning."\n\n > This is the Swift SDK for integrating with Appwrite from your Swift server-side code. If you're looking for the Apple SDK you should check [appwrite/sdk-for-apple](https://github.com/appwrite/sdk-for-apple)"; break; case 'apple': $config = new Apple(); @@ -189,7 +190,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND break; case 'kotlin': $config = new Kotlin(); - $warning = $warning . "\n\n > This is the Kotlin SDK for integrating with Appwrite from your Kotlin server-side code. If you're looking for the Android SDK you should check [appwrite/sdk-for-android](https://github.com/appwrite/sdk-for-android)"; + $warning = $warning."\n\n > This is the Kotlin SDK for integrating with Appwrite from your Kotlin server-side code. If you're looking for the Android SDK you should check [appwrite/sdk-for-android](https://github.com/appwrite/sdk-for-android)"; break; case 'graphql': $config = new GraphQL(); @@ -198,7 +199,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $config = new REST(); break; default: - throw new Exception('Language "' . $language['key'] . '" not supported'); + throw new Exception('Language "'.$language['key'].'" not supported'); } Console::info("Generating {$language['name']} SDK..."); @@ -246,29 +247,28 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $gitUrl = $language['gitUrl']; $gitBranch = $language['gitBranch']; - - if (!$production) { - $gitUrl = 'git@github.com:aw-tests/' . $language['gitRepoName'] . '.git'; + if (! $production) { + $gitUrl = 'git@github.com:aw-tests/'.$language['gitRepoName'].'.git'; } - if ($git && !empty($gitUrl)) { - \exec('rm -rf ' . $target . ' && \ - mkdir -p ' . $target . ' && \ - cd ' . $target . ' && \ - git init --initial-branch=' . $gitBranch . ' && \ - git remote add origin ' . $gitUrl . ' && \ - git fetch origin ' . $gitBranch . ' && \ - git pull origin ' . $gitBranch . ' && \ - rm -rf ' . $target . '/* && \ - cp -r ' . $result . '/* ' . $target . '/ && \ + if ($git && ! empty($gitUrl)) { + \exec('rm -rf '.$target.' && \ + mkdir -p '.$target.' && \ + cd '.$target.' && \ + git init --initial-branch='.$gitBranch.' && \ + git remote add origin '.$gitUrl.' && \ + git fetch origin '.$gitBranch.' && \ + git pull origin '.$gitBranch.' && \ + rm -rf '.$target.'/* && \ + cp -r '.$result.'/* '.$target.'/ && \ git add . && \ - git commit -m "' . $message . '" && \ - git push -u origin ' . $gitBranch . ' + git commit -m "'.$message.'" && \ + git push -u origin '.$gitBranch.' '); Console::success("Pushed {$language['name']} SDK to {$gitUrl}"); - \exec('rm -rf ' . $target); + \exec('rm -rf '.$target); Console::success("Remove temp directory '{$target}' for {$language['name']} SDK"); } @@ -279,10 +279,10 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND } foreach ($docDirectories as $languageTitle => $path) { - $languagePath = strtolower($languageTitle !== 0 ? '/' . $languageTitle : ''); + $languagePath = strtolower($languageTitle !== 0 ? '/'.$languageTitle : ''); \exec( - 'mkdir -p ' . $resultExamples . $languagePath . ' && \ - cp -r ' . $result . '/docs/examples' . $languagePath . ' ' . $resultExamples + 'mkdir -p '.$resultExamples.$languagePath.' && \ + cp -r '.$result.'/docs/examples'.$languagePath.' '.$resultExamples ); Console::success("Copied code examples for {$language['name']} SDK to: {$resultExamples}"); } diff --git a/src/Appwrite/Platform/Tasks/SSL.php b/src/Appwrite/Platform/Tasks/SSL.php index 43026b0753..9697ff91ae 100644 --- a/src/Appwrite/Platform/Tasks/SSL.php +++ b/src/Appwrite/Platform/Tasks/SSL.php @@ -2,11 +2,11 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; use Appwrite\Event\Certificate; use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Document; +use Utopia\Platform\Action; use Utopia\Validator\Hostname; class SSL extends Action @@ -26,11 +26,11 @@ class SSL extends Action public function action(string $domain): void { - Console::success('Scheduling a job to issue a TLS certificate for domain: ' . $domain); + Console::success('Scheduling a job to issue a TLS certificate for domain: '.$domain); (new Certificate()) ->setDomain(new Document([ - 'domain' => $domain + 'domain' => $domain, ])) ->setSkipRenewCheck(true) ->trigger(); diff --git a/src/Appwrite/Platform/Tasks/Schedule.php b/src/Appwrite/Platform/Tasks/Schedule.php index 219d1c9886..42e8327e9a 100644 --- a/src/Appwrite/Platform/Tasks/Schedule.php +++ b/src/Appwrite/Platform/Tasks/Schedule.php @@ -2,23 +2,23 @@ namespace Appwrite\Platform\Tasks; +use Appwrite\Event\Func; use Cron\CronExpression; +use function Swoole\Coroutine\run; use Swoole\Timer; use Utopia\App; -use Utopia\Platform\Action; use Utopia\CLI\Console; +use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Database; +use Utopia\Platform\Action; use Utopia\Pools\Group; -use Appwrite\Event\Func; - -use function Swoole\Coroutine\run; class Schedule extends Action { public const FUNCTION_UPDATE_TIMER = 10; //seconds + public const FUNCTION_ENQUEUE_TIMER = 60; //seconds public static function getName(): string @@ -40,16 +40,17 @@ class Schedule extends Action * 1. Load all documents from 'schedules' collection to create local copy * 2. Create timer that sync all changes from 'schedules' collection to local copy. Only reading changes thanks to 'resourceUpdatedAt' attribute * 3. Create timer that prepares coroutines for soon-to-execute schedules. When it's ready, coroutime sleeps until exact time before sending request to worker. - */ + */ public function action(Group $pools, Database $dbForConsole, callable $getProjectDB): void { Console::title('Scheduler V1'); - Console::success(APP_NAME . ' Scheduler v1 has started'); + Console::success(APP_NAME.' Scheduler v1 has started'); /** * Extract only nessessary attributes to lower memory used. * * @var Document $schedule + * * @return array */ $getSchedule = function (Document $schedule) use ($dbForConsole, $getProjectDB): array { @@ -92,14 +93,14 @@ class Schedule extends Action $schedules[$document['resourceId']] = $getSchedule($document); } - $latestDocument = !empty(array_key_last($results)) ? $results[array_key_last($results)] : null; + $latestDocument = ! empty(array_key_last($results)) ? $results[array_key_last($results)] : null; } $pools->reclaim(); - Console::success("{$total} functions were loaded in " . (microtime(true) - $loadStart) . " seconds"); + Console::success("{$total} functions were loaded in ".(microtime(true) - $loadStart).' seconds'); - Console::success("Starting timers at " . DateTime::now()); + Console::success('Starting timers at '.DateTime::now()); run( function () use ($dbForConsole, &$schedules, &$lastSyncUpdate, $getSchedule, $pools) { @@ -120,7 +121,7 @@ class Schedule extends Action while ($sum === $limit) { $paginationQueries = [Query::limit($limit)]; if ($latestDocument !== null) { - $paginationQueries[] = Query::cursorAfter($latestDocument); + $paginationQueries[] = Query::cursorAfter($latestDocument); } $results = $dbForConsole->find('schedules', \array_merge($paginationQueries, [ Query::equal('region', [App::getEnv('_APP_REGION', 'default')]), @@ -144,7 +145,7 @@ class Schedule extends Action $schedules[$document['resourceId']] = $getSchedule($document); } } - $latestDocument = !empty(array_key_last($results)) ? $results[array_key_last($results)] : null; + $latestDocument = ! empty(array_key_last($results)) ? $results[array_key_last($results)] : null; } $lastSyncUpdate = $time; @@ -152,7 +153,7 @@ class Schedule extends Action $pools->reclaim(); - Console::log("Sync tick: {$total} schedules were updated in " . ($timerEnd - $timerStart) . " seconds"); + Console::log("Sync tick: {$total} schedules were updated in ".($timerEnd - $timerStart).' seconds'); }); /** @@ -179,7 +180,7 @@ class Schedule extends Action $currentTick = $next < $timeFrame; - if (!$currentTick) { + if (! $currentTick) { continue; } @@ -189,7 +190,7 @@ class Schedule extends Action $executionStart = $nextDate->getTimestamp(); // in seconds $delay = $executionStart - $promiseStart; // Time to wait from now until execution needs to be queued - if (!isset($delayedExecutions[$delay])) { + if (! isset($delayedExecutions[$delay])) { $delayedExecutions[$delay] = []; } @@ -205,7 +206,7 @@ class Schedule extends Action foreach ($scheduleKeys as $scheduleKey) { // Ensure schedule was not deleted - if (!isset($schedules[$scheduleKey])) { + if (! isset($schedules[$scheduleKey])) { return; } @@ -226,10 +227,10 @@ class Schedule extends Action $timerEnd = \microtime(true); $lastEnqueueUpdate = $timerStart; - Console::log("Enqueue tick: {$total} executions were enqueued in " . ($timerEnd - $timerStart) . " seconds"); + Console::log("Enqueue tick: {$total} executions were enqueued in ".($timerEnd - $timerStart).' seconds'); }; - Timer::tick(self::FUNCTION_ENQUEUE_TIMER * 1000, fn() => $enqueueFunctions()); + Timer::tick(self::FUNCTION_ENQUEUE_TIMER * 1000, fn () => $enqueueFunctions()); $enqueueFunctions(); } ); diff --git a/src/Appwrite/Platform/Tasks/Specs.php b/src/Appwrite/Platform/Tasks/Specs.php index 82caf8ef72..d596a36925 100644 --- a/src/Appwrite/Platform/Tasks/Specs.php +++ b/src/Appwrite/Platform/Tasks/Specs.php @@ -2,8 +2,6 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; -use Utopia\Validator\Text; use Appwrite\Specification\Format\OpenAPI3; use Appwrite\Specification\Format\Swagger2; use Appwrite\Specification\Specification; @@ -17,8 +15,10 @@ use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Adapter\MySQL; use Utopia\Database\Database; +use Utopia\Platform\Action; use Utopia\Registry\Registry; use Utopia\Request; +use Utopia\Validator\Text; use Utopia\Validator\WhiteList; class Specs extends Action @@ -177,15 +177,15 @@ class Specs extends Action $sdkPlaforms[] = APP_PLATFORM_CLIENT; } - if (!$route->getLabel('docs', true)) { + if (! $route->getLabel('docs', true)) { continue; } - if ($route->getLabel('sdk.mock', false) && !$mocks) { + if ($route->getLabel('sdk.mock', false) && ! $mocks) { continue; } - if (!$route->getLabel('sdk.mock', false) && $mocks) { + if (! $route->getLabel('sdk.mock', false) && $mocks) { continue; } @@ -193,7 +193,7 @@ class Specs extends Action continue; } - if ($platform !== APP_PLATFORM_CONSOLE && !\in_array($platforms[$platform], $sdkPlaforms)) { + if ($platform !== APP_PLATFORM_CONSOLE && ! \in_array($platforms[$platform], $sdkPlaforms)) { continue; } @@ -203,10 +203,10 @@ class Specs extends Action foreach (Config::getParam('services', []) as $service) { if ( - !isset($service['docs']) // Skip service if not part of the public API - || !isset($service['sdk']) - || !$service['docs'] - || !$service['sdk'] + ! isset($service['docs']) // Skip service if not part of the public API + || ! isset($service['sdk']) + || ! $service['docs'] + || ! $service['sdk'] ) { continue; } @@ -221,7 +221,7 @@ class Specs extends Action $models = $response->getModels(); foreach ($models as $key => $value) { - if ($platform !== APP_PLATFORM_CONSOLE && !$value->isPublic()) { + if ($platform !== APP_PLATFORM_CONSOLE && ! $value->isPublic()) { unset($models[$key]); } } @@ -231,7 +231,7 @@ class Specs extends Action $formatInstance = match ($format) { 'swagger2' => new Swagger2(...$arguments), 'open-api3' => new OpenAPI3(...$arguments), - default => throw new Exception('Format not found: ' . $format) + default => throw new Exception('Format not found: '.$format) }; $specs = new Specification($formatInstance); @@ -243,36 +243,36 @@ class Specs extends Action ->setParam('description', 'Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)') ->setParam('endpoint', 'https://HOSTNAME/v1') ->setParam('version', APP_VERSION_STABLE) - ->setParam('terms', $endpoint . '/policy/terms') + ->setParam('terms', $endpoint.'/policy/terms') ->setParam('support.email', $email) - ->setParam('support.url', $endpoint . '/support') - ->setParam('contact.name', APP_NAME . ' Team') + ->setParam('support.url', $endpoint.'/support') + ->setParam('contact.name', APP_NAME.' Team') ->setParam('contact.email', $email) - ->setParam('contact.url', $endpoint . '/support') + ->setParam('contact.url', $endpoint.'/support') ->setParam('license.name', 'BSD-3-Clause') ->setParam('license.url', 'https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE') ->setParam('docs.description', 'Full API docs, specs and tutorials') - ->setParam('docs.url', $endpoint . '/docs'); + ->setParam('docs.url', $endpoint.'/docs'); if ($mocks) { - $path = __DIR__ . '/../config/specs/' . $format . '-mocks-' . $platform . '.json'; + $path = __DIR__.'/../config/specs/'.$format.'-mocks-'.$platform.'.json'; - if (!file_put_contents($path, json_encode($specs->parse()))) { - throw new Exception('Failed to save mocks spec file: ' . $path); + if (! file_put_contents($path, json_encode($specs->parse()))) { + throw new Exception('Failed to save mocks spec file: '.$path); } - Console::success('Saved mocks spec file: ' . realpath($path)); + Console::success('Saved mocks spec file: '.realpath($path)); continue; } - $path = __DIR__ . '/../../../../app/config/specs/' . $format . '-' . $version . '-' . $platform . '.json'; + $path = __DIR__.'/../../../../app/config/specs/'.$format.'-'.$version.'-'.$platform.'.json'; - if (!file_put_contents($path, json_encode($specs->parse()))) { - throw new Exception('Failed to save spec file: ' . $path); + if (! file_put_contents($path, json_encode($specs->parse()))) { + throw new Exception('Failed to save spec file: '.$path); } - Console::success('Saved spec file: ' . realpath($path)); + Console::success('Saved spec file: '.realpath($path)); } } } diff --git a/src/Appwrite/Platform/Tasks/Vars.php b/src/Appwrite/Platform/Tasks/Vars.php index c97f77a9da..714bb40ab1 100644 --- a/src/Appwrite/Platform/Tasks/Vars.php +++ b/src/Appwrite/Platform/Tasks/Vars.php @@ -3,8 +3,8 @@ namespace Appwrite\Platform\Tasks; use Utopia\App; -use Utopia\Config\Config; use Utopia\CLI\Console; +use Utopia\Config\Config; use Utopia\Platform\Action; class Vars extends Action @@ -33,7 +33,7 @@ class Vars extends Action } foreach ($vars as $key => $value) { - Console::log('- ' . $value['name'] . '=' . App::getEnv($value['name'], '')); + Console::log('- '.$value['name'].'='.App::getEnv($value['name'], '')); } } } diff --git a/src/Appwrite/Platform/Tasks/VolumeSync.php b/src/Appwrite/Platform/Tasks/VolumeSync.php index 6197b20fbd..193d07fd17 100644 --- a/src/Appwrite/Platform/Tasks/VolumeSync.php +++ b/src/Appwrite/Platform/Tasks/VolumeSync.php @@ -27,11 +27,10 @@ class VolumeSync extends Action public function action(string $source, string $destination, int $interval) { - Console::title('RSync V1'); - Console::success(APP_NAME . ' rsync process v1 has started'); + Console::success(APP_NAME.' rsync process v1 has started'); - if (!file_exists($source)) { + if (! file_exists($source)) { Console::error('Source directory does not exist. Exiting ... '); Console::exit(0); } @@ -42,14 +41,15 @@ class VolumeSync extends Action Console::info("[{$time}] Executing rsync every {$interval} seconds"); Console::info("Syncing between $source and $destination"); - if (!file_exists($source)) { + if (! file_exists($source)) { Console::error('Source directory does not exist. Skipping ... '); + return; } - $stdin = ""; - $stdout = ""; - $stderr = ""; + $stdin = ''; + $stdout = ''; + $stderr = ''; Console::execute("rsync -av $source $destination", $stdin, $stdout, $stderr); Console::success($stdout); diff --git a/src/Appwrite/Promises/Promise.php b/src/Appwrite/Promises/Promise.php index a6b1aa79d5..95e4c7bc69 100644 --- a/src/Appwrite/Promises/Promise.php +++ b/src/Appwrite/Promises/Promise.php @@ -5,7 +5,9 @@ namespace Appwrite\Promises; abstract class Promise { protected const STATE_PENDING = 1; + protected const STATE_FULFILLED = 0; + protected const STATE_REJECTED = -1; protected int $state = self::STATE_PENDING; @@ -37,7 +39,7 @@ abstract class Promise /** * Create a new promise from the given callable. * - * @param callable $promise + * @param callable $promise * @return self */ public static function create(callable $promise): self @@ -48,7 +50,7 @@ abstract class Promise /** * Resolve promise with given value. * - * @param mixed $value + * @param mixed $value * @return self */ public static function resolve(mixed $value): self @@ -61,7 +63,7 @@ abstract class Promise /** * Rejects the promise with the given reason. * - * @param mixed $value + * @param mixed $value * @return self */ public static function reject(mixed $value): self @@ -74,7 +76,7 @@ abstract class Promise /** * Catch any exception thrown by the executor. * - * @param callable $onRejected + * @param callable $onRejected * @return self */ public function catch(callable $onRejected): self @@ -85,8 +87,8 @@ abstract class Promise /** * Execute the promise. * - * @param callable|null $onFulfilled - * @param callable|null $onRejected + * @param callable|null $onFulfilled + * @param callable|null $onRejected * @return self */ public function then( @@ -99,13 +101,15 @@ abstract class Promise if ($this->isFulfilled() && $onFulfilled === null) { return $this; } + return self::create(function (callable $resolve, callable $reject) use ($onFulfilled, $onRejected) { while ($this->isPending()) { usleep(25000); } $callable = $this->isFulfilled() ? $onFulfilled : $onRejected; - if (!\is_callable($callable)) { + if (! \is_callable($callable)) { $resolve($this->result); + return; } try { @@ -119,7 +123,7 @@ abstract class Promise /** * Returns a promise that completes when all passed in promises complete. * - * @param iterable|self[] $promises + * @param iterable|self[] $promises * @return self */ abstract public static function all(iterable $promises): self; @@ -127,13 +131,14 @@ abstract class Promise /** * Set resolved result * - * @param mixed $value + * @param mixed $value * @return void */ protected function setResult(mixed $value): void { - if (!\is_callable([$value, 'then'])) { + if (! \is_callable([$value, 'then'])) { $this->result = $value; + return; } @@ -146,7 +151,7 @@ abstract class Promise $value->then($callable, $callable); - while (!$resolved) { + while (! $resolved) { usleep(25000); } } @@ -154,7 +159,7 @@ abstract class Promise /** * Change promise state * - * @param integer $state + * @param int $state * @return void */ protected function setState(int $state): void @@ -165,7 +170,7 @@ abstract class Promise /** * Promise is pending * - * @return boolean + * @return bool */ protected function isPending(): bool { @@ -175,7 +180,7 @@ abstract class Promise /** * Promise is fulfilled * - * @return boolean + * @return bool */ protected function isFulfilled(): bool { @@ -185,7 +190,7 @@ abstract class Promise /** * Promise is rejected * - * @return boolean + * @return bool */ protected function isRejected(): bool { diff --git a/src/Appwrite/Promises/Swoole.php b/src/Appwrite/Promises/Swoole.php index c258ef6a5e..4867ed6c96 100644 --- a/src/Appwrite/Promises/Swoole.php +++ b/src/Appwrite/Promises/Swoole.php @@ -28,7 +28,7 @@ class Swoole extends Promise /** * Returns a promise that completes when all passed in promises complete. * - * @param iterable|Swoole[] $promises + * @param iterable|Swoole[] $promises * @return Promise */ public static function all(iterable $promises): Promise @@ -45,6 +45,7 @@ class Swoole extends Promise $promise->then(function ($value) use ($key, &$result, $channel) { $result[$key] = $value; $channel->push(true); + return $value; }, function ($err) use ($channel, &$error) { $channel->push(true); @@ -61,6 +62,7 @@ class Swoole extends Promise if ($error !== null) { $reject($error); + return; } diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index 146500e743..f6ff7c2fb8 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -5,12 +5,14 @@ namespace Appwrite\Resque; use Appwrite\Event\Usage; use Exception; use Utopia\App; -use Utopia\Cache\Cache; -use Utopia\Config\Config; use Utopia\Cache\Adapter\Sharding; +use Utopia\Cache\Cache; use Utopia\CLI\Console; +use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; +use Utopia\DSN\DSN; use Utopia\Pools\Group; use Utopia\Storage\Device; use Utopia\Storage\Device\Backblaze; @@ -18,8 +20,6 @@ use Utopia\Storage\Device\DOSpaces; use Utopia\Storage\Device\Linode; use Utopia\Storage\Device\Local; use Utopia\Storage\Device\S3; -use Utopia\Database\Validator\Authorization; -use Utopia\DSN\DSN; use Utopia\Storage\Device\Wasabi; use Utopia\Storage\Storage; @@ -43,11 +43,12 @@ abstract class Worker * Function for identifying the worker needs to be set to unique name * * @return string + * * @throws Exception */ public function getName(): string { - throw new Exception("Please implement getName method in worker"); + throw new Exception('Please implement getName method in worker'); } /** @@ -55,11 +56,12 @@ abstract class Worker * Can include any preparations, such as connecting to external services or loading files * * @return void + * * @throws \Exception|\Throwable */ public function init(): void { - throw new Exception("Please implement init method in worker"); + throw new Exception('Please implement init method in worker'); } /** @@ -67,11 +69,12 @@ abstract class Worker * You can access $args here, it will contain event information * * @return void + * * @throws \Exception|\Throwable */ public function run(): void { - throw new Exception("Please implement run method in worker"); + throw new Exception('Please implement run method in worker'); } /** @@ -79,20 +82,23 @@ abstract class Worker * You can do cleanup here, such as disconnecting from services or removing temp files * * @return void + * * @throws \Exception|\Throwable */ public function shutdown(): void { - throw new Exception("Please implement shutdown method in worker"); + throw new Exception('Please implement shutdown method in worker'); } public const DATABASE_PROJECT = 'project'; + public const DATABASE_CONSOLE = 'console'; /** * A wrapper around 'init' function with non-worker-specific code * * @return void + * * @throws \Exception|\Throwable */ public function setUp(): void @@ -101,7 +107,7 @@ abstract class Worker $this->init(); } catch (\Throwable $error) { foreach (self::$errorCallbacks as $errorCallback) { - $errorCallback($error, "init", $this->getName()); + $errorCallback($error, 'init', $this->getName()); } throw $error; @@ -112,6 +118,7 @@ abstract class Worker * A wrapper around 'run' function with non-worker-specific code * * @return void + * * @throws \Exception|\Throwable */ public function perform(): void @@ -125,7 +132,7 @@ abstract class Worker $this->run(); } catch (\Throwable $error) { foreach (self::$errorCallbacks as $errorCallback) { - $errorCallback($error, "run", $this->getName(), $this->args); + $errorCallback($error, 'run', $this->getName(), $this->args); } throw $error; @@ -136,6 +143,7 @@ abstract class Worker * A wrapper around 'shutdown' function with non-worker-specific code * * @return void + * * @throws \Exception|\Throwable */ public function tearDown(): void @@ -149,17 +157,17 @@ abstract class Worker $this->shutdown(); } catch (\Throwable $error) { foreach (self::$errorCallbacks as $errorCallback) { - $errorCallback($error, "shutdown", $this->getName()); + $errorCallback($error, 'shutdown', $this->getName()); } throw $error; } } - /** * Register callback. Will be executed when error occurs. - * @param callable $callback + * + * @param callable $callback * @return void */ public static function error(callable $callback): void @@ -169,8 +177,10 @@ abstract class Worker /** * Get internal project database - * @param Document $project + * + * @param Document $project * @return Database + * * @throws Exception */ protected static $databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools @@ -180,7 +190,6 @@ abstract class Worker global $register; $pools = $register->get('pools'); /** @var Group $pools */ - if ($project->isEmpty() || $project->getId() === 'console') { return $this->getConsoleDB(); } @@ -189,28 +198,30 @@ abstract class Worker if (isset(self::$databases[$databaseName])) { $database = self::$databases[$databaseName]; - $database->setNamespace('_' . $project->getInternalId()); + $database->setNamespace('_'.$project->getInternalId()); + return $database; } $dbAdapter = $pools ->get($project->getAttribute('database')) ->pop() - ->getResource() - ; + ->getResource(); $database = new Database($dbAdapter, $this->getCache()); self::$databases[$databaseName] = $database; - $database->setNamespace('_' . $project->getInternalId()); + $database->setNamespace('_'.$project->getInternalId()); return $database; } /** * Get console database + * * @return Database + * * @throws Exception */ protected function getConsoleDB(): Database @@ -218,20 +229,19 @@ abstract class Worker global $register; $pools = $register->get('pools'); /** @var Group $pools */ - $databaseName = 'console'; if (isset(self::$databases[$databaseName])) { $database = self::$databases[$databaseName]; $database->setNamespace('console'); + return $database; } $dbAdapter = $pools ->get('console') ->pop() - ->getResource() - ; + ->getResource(); $database = new Database($dbAdapter, $this->getCache()); @@ -242,9 +252,9 @@ abstract class Worker return $database; } - /** * Get Cache + * * @return Cache */ protected function getCache(): Cache @@ -252,7 +262,6 @@ abstract class Worker global $register; $pools = $register->get('pools'); /** @var Group $pools */ - $list = Config::getParam('pools-cache', []); $adapters = []; @@ -260,8 +269,7 @@ abstract class Worker $adapters[] = $pools ->get($value) ->pop() - ->getResource() - ; + ->getResource(); } return new Cache(new Sharding($adapters)); @@ -269,7 +277,9 @@ abstract class Worker /** * Get usage queue + * * @return Usage + * * @throws Exception */ protected function getUsageQueue(): Usage @@ -287,42 +297,46 @@ abstract class Worker /** * Get Functions Storage Device - * @param string $projectId of the project + * + * @param string $projectId of the project * @return Device */ protected function getFunctionsDevice(string $projectId): Device { - return $this->getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $projectId); + return $this->getDevice(APP_STORAGE_FUNCTIONS.'/app-'.$projectId); } /** * Get Files Storage Device - * @param string $projectId of the project + * + * @param string $projectId of the project * @return Device */ protected function getFilesDevice(string $projectId): Device { - return $this->getDevice(APP_STORAGE_UPLOADS . '/app-' . $projectId); + return $this->getDevice(APP_STORAGE_UPLOADS.'/app-'.$projectId); } /** * Get Builds Storage Device - * @param string $projectId of the project + * + * @param string $projectId of the project * @return Device */ protected function getBuildsDevice(string $projectId): Device { - return $this->getDevice(APP_STORAGE_BUILDS . '/app-' . $projectId); + return $this->getDevice(APP_STORAGE_BUILDS.'/app-'.$projectId); } protected function getCacheDevice(string $projectId): Device { - return $this->getDevice(APP_STORAGE_CACHE . '/app-' . $projectId); + return $this->getDevice(APP_STORAGE_CACHE.'/app-'.$projectId); } /** * Get Device based on selected storage environment - * @param string $root path of the device + * + * @param string $root path of the device * @return Device */ public function getDevice(string $root): Device @@ -343,7 +357,7 @@ abstract class Worker $bucket = $dsn->getPath(); $region = $dsn->getParam('region'); } catch (\Exception $e) { - Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); + Console::error($e->getMessage().'Invalid DSN. Defaulting to Local device.'); } switch ($device) { diff --git a/src/Appwrite/Specification/Format.php b/src/Appwrite/Specification/Format.php index c2317c1153..670fbceecb 100644 --- a/src/Appwrite/Specification/Format.php +++ b/src/Appwrite/Specification/Format.php @@ -2,10 +2,10 @@ namespace Appwrite\Specification; +use Appwrite\Utopia\Response\Model; use Utopia\App; use Utopia\Config\Config; use Utopia\Route; -use Appwrite\Utopia\Response\Model; abstract class Format { @@ -22,8 +22,11 @@ abstract class Format protected array $models; protected array $services; + protected array $keys; + protected int $authCount; + protected array $params = [ 'name' => '', 'description' => '', @@ -46,8 +49,8 @@ abstract class Format [ 'namespace' => 'users', 'method' => 'getUsage', - 'parameter' => 'provider' - ] + 'parameter' => 'provider', + ], ]; public function __construct(App $app, array $services, array $routes, array $models, array $keys, int $authCount) @@ -83,9 +86,8 @@ abstract class Format * * Set param value * - * @param string $key - * @param string $value - * + * @param string $key + * @param string $value * @return self */ public function setParam(string $key, string $value): self @@ -100,9 +102,8 @@ abstract class Format * * Get param value * - * @param string $key - * @param string $default - * + * @param string $key + * @param string $default * @return string */ public function getParam(string $key, string $default = ''): string @@ -177,8 +178,10 @@ abstract class Format } break; } + return null; } + public function getEnumKeys(string $service, string $method, string $param): array { $values = []; @@ -190,18 +193,21 @@ abstract class Format foreach ($codes as $code => $value) { $values[] = $value['name']; } + return $values; case 'getCreditCard': $codes = Config::getParam('avatar-credit-cards'); foreach ($codes as $code => $value) { $values[] = $value['name']; } + return $values; case 'getFlag': $codes = Config::getParam('avatar-flags'); foreach ($codes as $code => $value) { $values[] = $value['name']; } + return $values; } break; @@ -211,7 +217,8 @@ abstract class Format case 'getCollectionUsage': case 'getDatabaseUsage': // Range Enum Keys - $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; + $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; + return $values; } break; @@ -221,6 +228,7 @@ abstract class Format case 'getFunctionUsage': // Range Enum Keys $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; + return $values; } break; @@ -231,6 +239,7 @@ abstract class Format // Range Enum Keys if ($param == 'range') { $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; + return $values; } } @@ -241,9 +250,11 @@ abstract class Format case 'getBucketUsage': // Range Enum Keys $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; + return $values; } } + return $values; } } diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 94cb0bb90d..f979ca1b4d 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -20,30 +20,32 @@ class OpenAPI3 extends Format protected function getNestedModels(Model $model, array &$usedModels): void { foreach ($model->getRules() as $rule) { - if (!in_array($model->getType(), $usedModels)) { + if (! in_array($model->getType(), $usedModels)) { continue; } if (\is_array($rule['type'])) { foreach ($rule['type'] as $ruleType) { - if (!in_array($ruleType, ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { + if (! in_array($ruleType, ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { $usedModels[] = $ruleType; foreach ($this->models as $m) { if ($m->getType() === $ruleType) { $this->getNestedModels($m, $usedModels); + continue; } } } } } else { - if (!in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { + if (! in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { $usedModels[] = $rule['type']; foreach ($this->models as $m) { if ($m->getType() === $rule['type']) { $this->getNestedModels($m, $usedModels); + continue; } } @@ -125,7 +127,7 @@ class OpenAPI3 extends Format } $id = $route->getLabel('sdk.method', \uniqid()); - $desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__ . '/../../../../' . $route->getLabel('sdk.description', '')) : null; + $desc = (! empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__.'/../../../../'.$route->getLabel('sdk.description', '')) : null; $produces = $route->getLabel('sdk.response.type', null); $model = $route->getLabel('sdk.response.model', 'none'); $routeSecurity = $route->getLabel('sdk.auth', []); @@ -154,7 +156,7 @@ class OpenAPI3 extends Format $temp = [ 'summary' => $route->getDesc(), - 'operationId' => $route->getLabel('sdk.namespace', 'default') . ucfirst($id), + 'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id), 'tags' => [$route->getLabel('sdk.namespace', 'default')], 'description' => ($desc) ? \file_get_contents($desc) : '', 'responses' => [], @@ -163,8 +165,8 @@ class OpenAPI3 extends Format 'weight' => $route->getOrder(), 'cookies' => $route->getLabel('sdk.cookies', false), 'type' => $route->getLabel('sdk.methodType', ''), - 'demo' => Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')) . '/' . Template::fromCamelCaseToDash($id) . '.md', - 'edit' => 'https://github.com/appwrite/appwrite/edit/master' . $route->getLabel('sdk.description', ''), + 'demo' => Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')).'/'.Template::fromCamelCaseToDash($id).'.md', + 'edit' => 'https://github.com/appwrite/appwrite/edit/master'.$route->getLabel('sdk.description', ''), 'rate-limit' => $route->getLabel('abuse-limit', 0), 'rate-time' => $route->getLabel('abuse-time', 3600), 'rate-key' => $route->getLabel('abuse-key', 'url:{url},ip:{ip}'), @@ -188,8 +190,8 @@ class OpenAPI3 extends Format } } - if (!(\is_array($model)) && $model->isNone()) { - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + if (! (\is_array($model)) && $model->isNone()) { + $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ 'description' => in_array($produces, [ 'image/*', 'image/jpeg', @@ -203,19 +205,19 @@ class OpenAPI3 extends Format ]; } else { if (\is_array($model)) { - $modelDescription = \join(', or ', \array_map(fn ($m) => $m->getName(), $model)); + $modelDescription = \implode(', or ', \array_map(fn ($m) => $m->getName(), $model)); // model has multiple possible responses, we will use oneOf foreach ($model as $m) { $usedModels[] = $m->getType(); } - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ 'description' => $modelDescription, 'content' => [ $produces => [ 'schema' => [ - 'oneOf' => \array_map(fn ($m) => ['$ref' => '#/components/schemas/' . $m->getType()], $model) + 'oneOf' => \array_map(fn ($m) => ['$ref' => '#/components/schemas/'.$m->getType()], $model), ], ], ], @@ -223,12 +225,12 @@ class OpenAPI3 extends Format } else { // Response definition using one type $usedModels[] = $model->getType(); - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ 'description' => $model->getName(), 'content' => [ $produces => [ 'schema' => [ - '$ref' => '#/components/schemas/' . $model->getType(), + '$ref' => '#/components/schemas/'.$model->getType(), ], ], ], @@ -237,11 +239,11 @@ class OpenAPI3 extends Format } if ($route->getLabel('sdk.response.code', 500) === 204) { - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['description'] = 'No content'; - unset($temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['schema']); + $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')]['description'] = 'No content'; + unset($temp['responses'][(string) $route->getLabel('sdk.response.code', '500')]['schema']); } - if ((!empty($scope))) { // && 'public' != $scope + if ((! empty($scope))) { // && 'public' != $scope $securities = ['Project' => []]; foreach ($route->getLabel('sdk.auth', []) as $security) { @@ -256,8 +258,8 @@ class OpenAPI3 extends Format $body = [ 'content' => [ - $consumes[0] => [ - 'schema' => [ + $consumes[0] => [ + 'schema' => [ 'type' => 'object', 'properties' => [], ], @@ -276,7 +278,7 @@ class OpenAPI3 extends Format $node = [ 'name' => $name, 'description' => $param['description'], - 'required' => !$param['optional'], + 'required' => ! $param['optional'], ]; foreach ($this->services as $service) { @@ -292,10 +294,10 @@ class OpenAPI3 extends Format $validator = $validator->getValidator(); } - switch ((!empty($validator)) ? \get_class($validator) : '') { + switch ((! empty($validator)) ? \get_class($validator) : '') { case 'Utopia\Validator\Text': $node['schema']['type'] = $validator->getType(); - $node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; break; case 'Utopia\Validator\Boolean': $node['schema']['type'] = $validator->getType(); @@ -303,14 +305,14 @@ class OpenAPI3 extends Format break; case 'Utopia\Database\Validator\UID': $node['schema']['type'] = $validator->getType(); - $node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; break; case 'Appwrite\Utopia\Database\Validator\CustomId': if ($route->getLabel('sdk.methodType', '') === 'upload') { $node['schema']['x-upload-id'] = true; } $node['schema']['type'] = $validator->getType(); - $node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; break; case 'Utopia\Database\Validator\DatetimeValidator': $node['schema']['type'] = $validator->getType(); @@ -367,14 +369,14 @@ class OpenAPI3 extends Format $node['schema']['items'] = [ 'type' => 'string', ]; - $node['schema']['x-example'] = '["' . Permission::read(Role::any()) . '"]'; + $node['schema']['x-example'] = '["'.Permission::read(Role::any()).'"]'; break; case 'Utopia\Database\Validator\Roles': $node['schema']['type'] = $validator->getType(); $node['schema']['items'] = [ 'type' => 'string', ]; - $node['schema']['x-example'] = '["' . Role::any()->toString() . '"]'; + $node['schema']['x-example'] = '["'.Role::any()->toString().'"]'; break; case 'Appwrite\Auth\Validator\Password': $node['schema']['type'] = $validator->getType(); @@ -429,9 +431,9 @@ class OpenAPI3 extends Format } if ($allowed) { - $node['schema']['enum'] = $validator->getList(); - $node['schema']['x-enum-name'] = $this->getEnumName($route->getLabel('sdk.namespace', ''), $route->getLabel('sdk.method', ''), $name); - $node['schema']['x-enum-keys'] = $this->getEnumKeys($route->getLabel('sdk.namespace', ''), $route->getLabel('sdk.method', ''), $name); + $node['schema']['enum'] = $validator->getList(); + $node['schema']['x-enum-name'] = $this->getEnumName($route->getLabel('sdk.namespace', ''), $route->getLabel('sdk.method', ''), $name); + $node['schema']['x-enum-keys'] = $this->getEnumKeys($route->getLabel('sdk.namespace', ''), $route->getLabel('sdk.method', ''), $name); } if ($validator->getType() === 'integer') { $node['format'] = 'int32'; @@ -442,25 +444,25 @@ class OpenAPI3 extends Format break; } - if ($param['optional'] && !\is_null($param['default'])) { // Param has default value + if ($param['optional'] && ! \is_null($param['default'])) { // Param has default value $node['schema']['default'] = $param['default']; } - if (false !== \strpos($url, ':' . $name)) { // Param is in URL path + if (false !== \strpos($url, ':'.$name)) { // Param is in URL path $node['in'] = 'path'; $temp['parameters'][] = $node; } elseif ($route->getMethod() == 'GET') { // Param is in query $node['in'] = 'query'; $temp['parameters'][] = $node; } else { // Param is in payload - if (!$param['optional']) { + if (! $param['optional']) { $bodyRequired[] = $name; } $body['content'][$consumes[0]]['schema']['properties'][$name] = [ 'type' => $node['schema']['type'], 'description' => $node['description'], - 'x-example' => $node['schema']['x-example'] ?? null + 'x-example' => $node['schema']['x-example'] ?? null, ]; if (isset($node['schema']['enum'])) { @@ -491,14 +493,14 @@ class OpenAPI3 extends Format } } - $url = \str_replace(':' . $name, '{' . $name . '}', $url); + $url = \str_replace(':'.$name, '{'.$name.'}', $url); } - if (!empty($bodyRequired)) { + if (! empty($bodyRequired)) { $body['content'][$consumes[0]]['schema']['required'] = $bodyRequired; } - if (!empty($body['content'][$consumes[0]]['schema']['properties'])) { + if (! empty($body['content'][$consumes[0]]['schema']['properties'])) { $temp['requestBody'] = $body; } @@ -510,7 +512,7 @@ class OpenAPI3 extends Format } foreach ($this->models as $model) { - if (!in_array($model->getType(), $usedModels) && $model->getType() !== 'error') { + if (! in_array($model->getType(), $usedModels) && $model->getType() !== 'error') { continue; } @@ -522,7 +524,7 @@ class OpenAPI3 extends Format 'type' => 'object', ]; - if (!empty($rules)) { + if (! empty($rules)) { $output['components']['schemas'][$model->getType()]['properties'] = []; } @@ -530,7 +532,7 @@ class OpenAPI3 extends Format $output['components']['schemas'][$model->getType()]['additionalProperties'] = true; } - if (!empty($required)) { + if (! empty($required)) { $output['components']['schemas'][$model->getType()]['required'] = $required; } @@ -577,19 +579,19 @@ class OpenAPI3 extends Format if ($rule['array']) { $items = [ 'anyOf' => \array_map(function ($type) { - return ['$ref' => '#/components/schemas/' . $type]; - }, $rule['type']) + return ['$ref' => '#/components/schemas/'.$type]; + }, $rule['type']), ]; } else { $items = [ 'oneOf' => \array_map(function ($type) { - return ['$ref' => '#/components/schemas/' . $type]; - }, $rule['type']) + return ['$ref' => '#/components/schemas/'.$type]; + }, $rule['type']), ]; } } else { $items = [ - '$ref' => '#/components/schemas/' . $rule['type'], + '$ref' => '#/components/schemas/'.$rule['type'], ]; } break; @@ -622,7 +624,7 @@ class OpenAPI3 extends Format if ($items) { $output['components']['schemas'][$model->getType()]['properties'][$name]['items'] = $items; } - if (!in_array($name, $required)) { + if (! in_array($name, $required)) { $output['components']['schemas'][$model->getType()]['properties'][$name]['nullable'] = true; } } diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 6b3d394aad..15aad0238f 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -20,30 +20,32 @@ class Swagger2 extends Format protected function getNestedModels(Model $model, array &$usedModels): void { foreach ($model->getRules() as $rule) { - if (!in_array($model->getType(), $usedModels)) { + if (! in_array($model->getType(), $usedModels)) { continue; } if (\is_array($rule['type'])) { foreach ($rule['type'] as $ruleType) { - if (!in_array($ruleType, ['string', 'integer', 'boolean', 'json', 'float'])) { + if (! in_array($ruleType, ['string', 'integer', 'boolean', 'json', 'float'])) { $usedModels[] = $ruleType; foreach ($this->models as $m) { if ($m->getType() === $ruleType) { $this->getNestedModels($m, $usedModels); + continue; } } } } } else { - if (!in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float'])) { + if (! in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float'])) { $usedModels[] = $rule['type']; foreach ($this->models as $m) { if ($m->getType() === $rule['type']) { $this->getNestedModels($m, $usedModels); + continue; } } @@ -124,7 +126,7 @@ class Swagger2 extends Format } $id = $route->getLabel('sdk.method', \uniqid()); - $desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__ . '/../../../../' . $route->getLabel('sdk.description', '')) : null; + $desc = (! empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__.'/../../../../'.$route->getLabel('sdk.description', '')) : null; $produces = $route->getLabel('sdk.response.type', null); $model = $route->getLabel('sdk.response.model', 'none'); $routeSecurity = $route->getLabel('sdk.auth', []); @@ -153,7 +155,7 @@ class Swagger2 extends Format $temp = [ 'summary' => $route->getDesc(), - 'operationId' => $route->getLabel('sdk.namespace', 'default') . ucfirst($id), + 'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id), 'consumes' => [], 'produces' => [], 'tags' => [$route->getLabel('sdk.namespace', 'default')], @@ -164,8 +166,8 @@ class Swagger2 extends Format 'weight' => $route->getOrder(), 'cookies' => $route->getLabel('sdk.cookies', false), 'type' => $route->getLabel('sdk.methodType', ''), - 'demo' => Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')) . '/' . Template::fromCamelCaseToDash($id) . '.md', - 'edit' => 'https://github.com/appwrite/appwrite/edit/master' . $route->getLabel('sdk.description', ''), + 'demo' => Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')).'/'.Template::fromCamelCaseToDash($id).'.md', + 'edit' => 'https://github.com/appwrite/appwrite/edit/master'.$route->getLabel('sdk.description', ''), 'rate-limit' => $route->getLabel('abuse-limit', 0), 'rate-time' => $route->getLabel('abuse-time', 3600), 'rate-key' => $route->getLabel('abuse-key', 'url:{url},ip:{ip}'), @@ -193,8 +195,8 @@ class Swagger2 extends Format } } - if (!(\is_array($model)) && $model->isNone()) { - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + if (! (\is_array($model)) && $model->isNone()) { + $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ 'description' => in_array($produces, [ 'image/*', 'image/jpeg', @@ -206,42 +208,42 @@ class Swagger2 extends Format 'image/bmp', ]) ? 'Image' : 'File', 'schema' => [ - 'type' => 'file' + 'type' => 'file', ], ]; } else { if (\is_array($model)) { - $modelDescription = \join(', or ', \array_map(fn ($m) => $m->getName(), $model)); + $modelDescription = \implode(', or ', \array_map(fn ($m) => $m->getName(), $model)); // model has multiple possible responses, we will use oneOf foreach ($model as $m) { $usedModels[] = $m->getType(); } - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ 'description' => $modelDescription, 'schema' => [ 'x-oneOf' => \array_map(function ($m) { - return ['$ref' => '#/definitions/' . $m->getType()]; - }, $model) + return ['$ref' => '#/definitions/'.$m->getType()]; + }, $model), ], ]; } else { // Response definition using one type $usedModels[] = $model->getType(); - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ 'description' => $model->getName(), 'schema' => [ - '$ref' => '#/definitions/' . $model->getType(), + '$ref' => '#/definitions/'.$model->getType(), ], ]; } } if (in_array($route->getLabel('sdk.response.code', 500), [204, 301, 302, 308], true)) { - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['description'] = 'No content'; - unset($temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['schema']); + $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')]['description'] = 'No content'; + unset($temp['responses'][(string) $route->getLabel('sdk.response.code', '500')]['schema']); } - if ((!empty($scope))) { // && 'public' != $scope + if ((! empty($scope))) { // && 'public' != $scope $securities = ['Project' => []]; foreach ($route->getLabel('sdk.auth', []) as $security) { @@ -277,7 +279,7 @@ class Swagger2 extends Format $node = [ 'name' => $name, 'description' => $param['description'], - 'required' => !$param['optional'], + 'required' => ! $param['optional'], ]; foreach ($this->services as $service) { @@ -293,11 +295,10 @@ class Swagger2 extends Format $validator = $validator->getValidator(); } - - switch ((!empty($validator)) ? \get_class($validator) : '') { + switch ((! empty($validator)) ? \get_class($validator) : '') { case 'Utopia\Validator\Text': $node['type'] = $validator->getType(); - $node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; break; case 'Utopia\Validator\Boolean': $node['type'] = $validator->getType(); @@ -308,11 +309,11 @@ class Swagger2 extends Format $node['x-upload-id'] = true; } $node['type'] = $validator->getType(); - $node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; break; case 'Utopia\Database\Validator\UID': $node['type'] = $validator->getType(); - $node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; break; case 'Utopia\Database\Validator\DatetimeValidator': $node['type'] = $validator->getType(); @@ -369,7 +370,7 @@ class Swagger2 extends Format $node['items'] = [ 'type' => 'string', ]; - $node['x-example'] = '["' . Permission::read(Role::any()) . '"]'; + $node['x-example'] = '["'.Permission::read(Role::any()).'"]'; break; case 'Utopia\Database\Validator\Roles': $node['type'] = $validator->getType(); @@ -377,7 +378,7 @@ class Swagger2 extends Format $node['items'] = [ 'type' => 'string', ]; - $node['x-example'] = '["' . Role::any()->toString() . '"]'; + $node['x-example'] = '["'.Role::any()->toString().'"]'; break; case 'Appwrite\Auth\Validator\Password': $node['type'] = $validator->getType(); @@ -442,11 +443,11 @@ class Swagger2 extends Format break; } - if ($param['optional'] && !\is_null($param['default'])) { // Param has default value + if ($param['optional'] && ! \is_null($param['default'])) { // Param has default value $node['default'] = $param['default']; } - if (false !== \strpos($url, ':' . $name)) { // Param is in URL path + if (false !== \strpos($url, ':'.$name)) { // Param is in URL path $node['in'] = 'path'; $temp['parameters'][] = $node; } elseif ($route->getMethod() == 'GET') { // Param is in query @@ -460,7 +461,7 @@ class Swagger2 extends Format continue; } - if (!$param['optional']) { + if (! $param['optional']) { $bodyRequired[] = $name; } @@ -491,14 +492,14 @@ class Swagger2 extends Format } } - $url = \str_replace(':' . $name, '{' . $name . '}', $url); + $url = \str_replace(':'.$name, '{'.$name.'}', $url); } - if (!empty($bodyRequired)) { + if (! empty($bodyRequired)) { $body['schema']['required'] = $bodyRequired; } - if (!empty($body['schema']['properties'])) { + if (! empty($body['schema']['properties'])) { $temp['parameters'][] = $body; } @@ -512,7 +513,7 @@ class Swagger2 extends Format } foreach ($this->models as $model) { - if (!in_array($model->getType(), $usedModels)) { + if (! in_array($model->getType(), $usedModels)) { continue; } @@ -524,7 +525,7 @@ class Swagger2 extends Format 'type' => 'object', ]; - if (!empty($rules)) { + if (! empty($rules)) { $output['definitions'][$model->getType()]['properties'] = []; } @@ -532,7 +533,7 @@ class Swagger2 extends Format $output['definitions'][$model->getType()]['additionalProperties'] = true; } - if (!empty($required)) { + if (! empty($required)) { $output['definitions'][$model->getType()]['required'] = $required; } @@ -577,17 +578,17 @@ class Swagger2 extends Format if (\is_array($rule['type'])) { if ($rule['array']) { $items = [ - 'x-anyOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/' . $type], $rule['type']) + 'x-anyOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/'.$type], $rule['type']), ]; } else { $items = [ - 'x-oneOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/' . $type], $rule['type']) + 'x-oneOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/'.$type], $rule['type']), ]; } } else { $items = [ 'type' => $type, - '$ref' => '#/definitions/' . $rule['type'], + '$ref' => '#/definitions/'.$rule['type'], ]; } break; @@ -600,6 +601,7 @@ class Swagger2 extends Format 'description' => $rule['description'] ?? '', 'x-example' => $rule['example'] ?? null, ]; + continue; } @@ -630,7 +632,7 @@ class Swagger2 extends Format if ($items) { $output['definitions'][$model->getType()]['properties'][$name]['items'] = $items; } - if (!in_array($name, $required)) { + if (! in_array($name, $required)) { $output['definitions'][$model->getType()]['properties'][$name]['x-nullable'] = true; } } diff --git a/src/Appwrite/Task/Validator/Cron.php b/src/Appwrite/Task/Validator/Cron.php index 03bd1c5220..a2709bc1c0 100644 --- a/src/Appwrite/Task/Validator/Cron.php +++ b/src/Appwrite/Task/Validator/Cron.php @@ -24,8 +24,7 @@ class Cron extends Validator * * Returns true if valid or false if not. * - * @param mixed $value - * + * @param mixed $value * @return bool */ public function isValid($value): bool @@ -34,7 +33,7 @@ class Cron extends Validator return true; } - if (!CronExpression::isValidExpression($value)) { + if (! CronExpression::isValidExpression($value)) { return false; } diff --git a/src/Appwrite/Template/Template.php b/src/Appwrite/Template/Template.php index c01d54389b..6b2bec0aef 100644 --- a/src/Appwrite/Template/Template.php +++ b/src/Appwrite/Template/Template.php @@ -17,18 +17,17 @@ class Template extends View * * Creates a new Template() from the file at $path * - * @param string $path - * + * @param string $path * @return self - * */ public static function fromFile(string $path): self { - if (!\is_readable($path)) { + if (! \is_readable($path)) { throw new Exception("$path view template is not readable."); } $template = new Template(); + return $template->setPath($path); } @@ -37,10 +36,8 @@ class Template extends View * * Creates a new Template() using a raw string * - * @param string $content - * + * @param string $content * @return self - * */ public static function fromString(string $content): self { @@ -50,6 +47,7 @@ class Template extends View $template = new Template(); $template->content = $content; + return $template; } @@ -71,10 +69,10 @@ class Template extends View if (\is_readable($this->path)) { $template = \file_get_contents($this->path); // Include template file - } elseif (!empty($this->content)) { + } elseif (! empty($this->content)) { $template = $this->print($this->content, self::FILTER_NL2P); } else { - throw new Exception('"' . $this->path . '" template is not readable or not found'); + throw new Exception('"'.$this->path.'" template is not readable or not found'); } // First replace the variables inside the params. Then replace the variables in the template @@ -90,7 +88,6 @@ class Template extends View * Parse URL string to array * * @param $url - * * @return mixed On seriously malformed URLs, parse_url() may return FALSE. */ public static function parseURL($url) @@ -104,25 +101,24 @@ class Template extends View * Convert PHP array to query string * * @param $url - * * @return string */ public static function unParseURL(array $url) { - $scheme = isset($url['scheme']) ? $url['scheme'] . '://' : ''; + $scheme = isset($url['scheme']) ? $url['scheme'].'://' : ''; $host = isset($url['host']) ? $url['host'] : ''; - $port = isset($url['port']) ? ':' . $url['port'] : ''; + $port = isset($url['port']) ? ':'.$url['port'] : ''; $user = isset($url['user']) ? $url['user'] : ''; - $pass = isset($url['pass']) ? ':' . $url['pass'] : ''; + $pass = isset($url['pass']) ? ':'.$url['pass'] : ''; $pass = ($user || $pass) ? "$pass@" : ''; $path = isset($url['path']) ? $url['path'] : ''; - $query = isset($url['query']) && !empty($url['query']) ? '?' . $url['query'] : ''; + $query = isset($url['query']) && ! empty($url['query']) ? '?'.$url['query'] : ''; - $fragment = isset($url['fragment']) ? '#' . $url['fragment'] : ''; + $fragment = isset($url['fragment']) ? '#'.$url['fragment'] : ''; - return $scheme . $user . $pass . $host . $port . $path . $query . $fragment; + return $scheme.$user.$pass.$host.$port.$path.$query.$fragment; } /** @@ -131,8 +127,7 @@ class Template extends View * Merge array of params to query string * * @param $query1 - * @param array $query2 - * + * @param array $query2 * @return string */ public static function mergeQuery($query1, array $query2) @@ -149,7 +144,7 @@ class Template extends View /** * From Camel Case * - * @var string $input + * @var string * * @return string */ @@ -167,7 +162,7 @@ class Template extends View /** * From Camel Case to Dash Case * - * @var string $input + * @var string * * @return string */ diff --git a/src/Appwrite/URL/URL.php b/src/Appwrite/URL/URL.php index 98250ab429..bfc6b8ee7d 100644 --- a/src/Appwrite/URL/URL.php +++ b/src/Appwrite/URL/URL.php @@ -9,8 +9,7 @@ class URL * * Take a URL string and split it to array parts * - * @param string $url - * + * @param string $url * @return array */ public static function parse(string $url): array @@ -34,46 +33,45 @@ class URL * * Take URL parts and combine them to a valid string * - * @param array $url - * @param array $ommit - * + * @param array $url + * @param array $ommit * @return string */ public static function unparse(array $url, array $ommit = []): string { if (isset($url['path']) && \mb_substr($url['path'], 0, 1) !== '/') { - $url['path'] = '/' . $url['path']; + $url['path'] = '/'.$url['path']; } $parts = []; - $parts['scheme'] = isset($url['scheme']) ? $url['scheme'] . '://' : ''; + $parts['scheme'] = isset($url['scheme']) ? $url['scheme'].'://' : ''; $parts['host'] = isset($url['host']) ? $url['host'] : ''; - $parts['port'] = isset($url['port']) ? ':' . $url['port'] : ''; + $parts['port'] = isset($url['port']) ? ':'.$url['port'] : ''; $parts['user'] = isset($url['user']) ? $url['user'] : ''; - $parts['pass'] = isset($url['pass']) ? ':' . $url['pass'] : ''; + $parts['pass'] = isset($url['pass']) ? ':'.$url['pass'] : ''; - $parts['pass'] = ($parts['user'] || $parts['pass']) ? $parts['pass'] . '@' : ''; + $parts['pass'] = ($parts['user'] || $parts['pass']) ? $parts['pass'].'@' : ''; $parts['path'] = isset($url['path']) ? $url['path'] : ''; - $parts['query'] = isset($url['query']) && !empty($url['query']) ? '?' . $url['query'] : ''; + $parts['query'] = isset($url['query']) && ! empty($url['query']) ? '?'.$url['query'] : ''; - $parts['fragment'] = isset($url['fragment']) ? '#' . $url['fragment'] : ''; + $parts['fragment'] = isset($url['fragment']) ? '#'.$url['fragment'] : ''; if ($ommit) { foreach ($ommit as $key) { - if (isset($parts[ $key ])) { - $parts[ $key ] = ''; + if (isset($parts[$key])) { + $parts[$key] = ''; } } } - return $parts['scheme'] . $parts['user'] . $parts['pass'] . $parts['host'] . $parts['port'] . $parts['path'] . $parts['query'] . $parts['fragment']; + return $parts['scheme'].$parts['user'].$parts['pass'].$parts['host'].$parts['port'].$parts['path'].$parts['query'].$parts['fragment']; } /** @@ -81,8 +79,7 @@ class URL * * Convert query string to array * - * @param string $query - * + * @param string $query * @return array */ public static function parseQuery(string $query): array @@ -97,8 +94,7 @@ class URL * * Convert query string array to string * - * @param array $query - * + * @param array $query * @return string */ public static function unparseQuery(array $query): string diff --git a/src/Appwrite/Utopia/Database/Validator/CustomId.php b/src/Appwrite/Utopia/Database/Validator/CustomId.php index 90d550371b..b6e913cb46 100644 --- a/src/Appwrite/Utopia/Database/Validator/CustomId.php +++ b/src/Appwrite/Utopia/Database/Validator/CustomId.php @@ -12,12 +12,10 @@ class CustomId extends Key * Returns true if valid or false if not. * * @param $value - * * @return bool */ public function isValid($value): bool { - return $value == 'unique()' || parent::isValid($value); } } diff --git a/src/Appwrite/Utopia/Database/Validator/ProjectId.php b/src/Appwrite/Utopia/Database/Validator/ProjectId.php index 46b0cdf53e..482a74fc57 100644 --- a/src/Appwrite/Utopia/Database/Validator/ProjectId.php +++ b/src/Appwrite/Utopia/Database/Validator/ProjectId.php @@ -12,7 +12,6 @@ class ProjectId extends Validator * Returns true if valid or false if not. * * @param $value - * * @return bool */ public function isValid($value): bool diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php b/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php index 1463316ad1..86264df395 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php @@ -2,8 +2,6 @@ namespace Appwrite\Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Select; - class Attributes extends Base { public const ALLOWED_ATTRIBUTES = [ @@ -13,12 +11,11 @@ class Attributes extends Base 'required', 'array', 'status', - 'error' + 'error', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Base.php b/src/Appwrite/Utopia/Database/Validator/Queries/Base.php index 3eea7b7b7e..eca03206f9 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Base.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Base.php @@ -2,24 +2,24 @@ namespace Appwrite\Utopia\Database\Validator\Queries; -use Appwrite\Extend\Exception; -use Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; -use Utopia\Database\Validator\Query\Cursor; -use Utopia\Database\Validator\Query\Filter; -use Utopia\Database\Validator\Query\Order; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Cursor; +use Utopia\Database\Validator\Query\Filter; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; +use Utopia\Database\Validator\Query\Order; class Base extends Queries { /** * Expression constructor * - * @param string $collection - * @param string[] $allowedAttributes + * @param string $collection + * @param string[] $allowedAttributes + * * @throws \Exception */ public function __construct(string $collection, array $allowedAttributes) @@ -36,7 +36,7 @@ class Base extends Queries $attributes = []; foreach ($collection['attributes'] as $attribute) { $key = $attribute['$id']; - if (!isset($allowedAttributesLookup[$key])) { + if (! isset($allowedAttributesLookup[$key])) { continue; } diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php b/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php index c4d187520f..91d467b203 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php @@ -10,12 +10,11 @@ class Buckets extends Base 'fileSecurity', 'maximumFileSize', 'encryption', - 'antivirus' + 'antivirus', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Collections.php b/src/Appwrite/Utopia/Database/Validator/Queries/Collections.php index 6e8fcb8339..9bf2381ed2 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Collections.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Collections.php @@ -7,12 +7,11 @@ class Collections extends Base public const ALLOWED_ATTRIBUTES = [ 'name', 'enabled', - 'documentSecurity' + 'documentSecurity', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Databases.php b/src/Appwrite/Utopia/Database/Validator/Queries/Databases.php index 22f7ad9b82..e47d9020d1 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Databases.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Databases.php @@ -5,12 +5,11 @@ namespace Appwrite\Utopia\Database\Validator\Queries; class Databases extends Base { public const ALLOWED_ATTRIBUTES = [ - 'name' + 'name', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php b/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php index 05b3326af1..20fe9a7123 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php @@ -13,7 +13,6 @@ class Deployments extends Base /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php b/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php index 2bfe46e28d..ca74367164 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php @@ -8,12 +8,11 @@ class Executions extends Base 'trigger', 'status', 'statusCode', - 'duration' + 'duration', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Files.php b/src/Appwrite/Utopia/Database/Validator/Queries/Files.php index 1941eabcdb..5984d32b9c 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Files.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Files.php @@ -10,12 +10,11 @@ class Files extends Base 'mimeType', 'sizeOriginal', 'chunksTotal', - 'chunksUploaded' + 'chunksUploaded', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php b/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php index a2ba368953..77b7e14028 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php @@ -12,12 +12,11 @@ class Functions extends Base 'schedule', 'scheduleNext', 'schedulePrevious', - 'timeout' + 'timeout', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php b/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php index cb0462ee13..346c2f4799 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php @@ -14,7 +14,6 @@ class Identities extends Base /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Indexes.php b/src/Appwrite/Utopia/Database/Validator/Queries/Indexes.php index d9290e5737..6ebf3cf50f 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Indexes.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Indexes.php @@ -14,7 +14,6 @@ class Indexes extends Base /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Memberships.php b/src/Appwrite/Utopia/Database/Validator/Queries/Memberships.php index 5ff0098662..73add15ac4 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Memberships.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Memberships.php @@ -9,12 +9,11 @@ class Memberships extends Base 'teamId', 'invited', 'joined', - 'confirm' + 'confirm', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php b/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php index 6b9e9e6d32..3cada3f633 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php @@ -11,12 +11,11 @@ class Migrations extends Base 'resources', 'statusCounters', 'resourceData', - 'errors' + 'errors', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php b/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php index 7fff26db7f..6f36d73660 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php @@ -2,18 +2,15 @@ namespace Appwrite\Utopia\Database\Validator\Queries; -use Appwrite\Utopia\Database\Validator\Queries\Base; - class Projects extends Base { public const ALLOWED_ATTRIBUTES = [ 'name', - 'teamId' + 'teamId', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php index 83dbf665f1..00beab4e1d 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php @@ -12,7 +12,6 @@ class Providers extends Base /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Teams.php b/src/Appwrite/Utopia/Database/Validator/Queries/Teams.php index 67aba71598..ccc5fdbf7c 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Teams.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Teams.php @@ -6,12 +6,11 @@ class Teams extends Base { public const ALLOWED_ATTRIBUTES = [ 'name', - 'total' + 'total', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Users.php b/src/Appwrite/Utopia/Database/Validator/Queries/Users.php index 9b0dfe61e6..b0fe844017 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Users.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Users.php @@ -12,12 +12,11 @@ class Users extends Base 'passwordUpdate', 'registration', 'emailVerification', - 'phoneVerification' + 'phoneVerification', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php b/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php index eff7007c58..978c763b84 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php @@ -2,17 +2,14 @@ namespace Appwrite\Utopia\Database\Validator\Queries; -use Appwrite\Utopia\Database\Validator\Queries\Base; - class Variables extends Base { public const ALLOWED_ATTRIBUTES = [ - 'key' + 'key', ]; /** * Expression constructor - * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php index 229c9dd53d..3f4d368e78 100644 --- a/src/Appwrite/Utopia/Request.php +++ b/src/Appwrite/Utopia/Request.php @@ -10,6 +10,7 @@ use Utopia\Swoole\Request as UtopiaRequest; class Request extends UtopiaRequest { private static ?Filter $filter = null; + private static ?Route $route = null; public function __construct(SwooleRequest $request) @@ -18,14 +19,14 @@ class Request extends UtopiaRequest } /** - * @inheritdoc + * {@inheritdoc} */ public function getParams(): array { $parameters = parent::getParams(); if (self::hasFilter() && self::hasRoute()) { - $endpointIdentifier = self::getRoute()->getLabel('sdk.namespace', 'unknown') . '.' . self::getRoute()->getLabel('sdk.method', 'unknown'); + $endpointIdentifier = self::getRoute()->getLabel('sdk.namespace', 'unknown').'.'.self::getRoute()->getLabel('sdk.method', 'unknown'); $parameters = self::getFilter()->parse($parameters, $endpointIdentifier); } @@ -35,8 +36,7 @@ class Request extends UtopiaRequest /** * Function to set a response filter * - * @param Filter|null $filter Filter the response filter to set - * + * @param Filter|null $filter Filter the response filter to set * @return void */ public static function setFilter(?Filter $filter): void @@ -67,8 +67,7 @@ class Request extends UtopiaRequest /** * Function to set a request route * - * @param Route|null $route the request route to set - * + * @param Route|null $route the request route to set * @return void */ public static function setRoute(?Route $route): void diff --git a/src/Appwrite/Utopia/Request/Filter.php b/src/Appwrite/Utopia/Request/Filter.php index 59346c7e17..4c1ea1bfd1 100644 --- a/src/Appwrite/Utopia/Request/Filter.php +++ b/src/Appwrite/Utopia/Request/Filter.php @@ -7,9 +7,8 @@ abstract class Filter /** * Parse params to another format. * - * @param array $content - * @param string $model - * + * @param array $content + * @param string $model * @return array */ abstract public function parse(array $content, string $model): array; diff --git a/src/Appwrite/Utopia/Request/Filters/V12.php b/src/Appwrite/Utopia/Request/Filters/V12.php index f2a65307ae..96fbf62885 100644 --- a/src/Appwrite/Utopia/Request/Filters/V12.php +++ b/src/Appwrite/Utopia/Request/Filters/V12.php @@ -11,44 +11,44 @@ class V12 extends Filter { switch ($model) { // No IDs -> Custom IDs - case "account.create": - case "account.createMagicURLSession": - case "users.create": + case 'account.create': + case 'account.createMagicURLSession': + case 'users.create': $content = $this->addId($content, 'userId'); break; - case "functions.create": + case 'functions.create': $content = $this->addId($content, 'functionId'); break; - case "teams.create": + case 'teams.create': $content = $this->addId($content, 'teamId'); break; - // Status integer -> boolean - case "users.updateStatus": + // Status integer -> boolean + case 'users.updateStatus': $content = $this->convertStatus($content); break; - // Deprecating order type - case "functions.listExecutions": + // Deprecating order type + case 'functions.listExecutions': $content = $this->removeOrderType($content); break; - // The rest (more complex) formats - case "database.createDocument": + // The rest (more complex) formats + case 'database.createDocument': $content = $this->addId($content, 'documentId'); $content = $this->removeParentProperties($content); break; - case "database.listDocuments": + case 'database.listDocuments': $content = $this->removeOrderCast($content); $content = $this->convertOrder($content); $content = $this->convertQueries($content); break; - case "database.createCollection": + case 'database.createCollection': $content = $this->addId($content, 'collectionId'); $content = $this->removeRules($content); $content = $this->addCollectionPermissionLevel($content); break; - case "database.updateCollection": + case 'database.updateCollection': $content = $this->removeRules($content); $content = $this->addCollectionPermissionLevel($content); break; @@ -62,12 +62,14 @@ class V12 extends Filter protected function addId(array $content, string $key): array { $content[$key] = 'unique()'; + return $content; } protected function addCollectionPermissionLevel(array $content): array { $content['permission'] = 'document'; + return $content; } @@ -76,18 +78,21 @@ class V12 extends Filter protected function removeRules(array $content): array { unset($content['rules']); + return $content; } protected function removeOrderType(array $content): array { unset($content['orderType']); + return $content; } protected function removeOrderCast(array $content): array { unset($content['orderCast']); + return $content; } @@ -102,6 +107,7 @@ class V12 extends Filter if (isset($content['parentPropertyType'])) { unset($content['parentPropertyType']); } + return $content; } @@ -112,18 +118,19 @@ class V12 extends Filter if (isset($content['status'])) { $content['status'] = $content['status'] === 2 ? false : true; } + return $content; } protected function convertOrder(array $content): array { if (isset($content['orderField'])) { - $content['orderAttributes'] = [ $content['orderField'] ]; + $content['orderAttributes'] = [$content['orderField']]; unset($content['orderField']); } if (isset($content['orderType'])) { - $content['orderTypes'] = [ $content['orderType'] ]; + $content['orderTypes'] = [$content['orderType']]; unset($content['orderType']); } @@ -134,7 +141,7 @@ class V12 extends Filter { $queries = []; - if (!empty($content['filters'])) { + if (! empty($content['filters'])) { foreach ($content['filters'] as $filter) { $operators = ['=' => 'equal', '!=' => 'notEqual', '>' => 'greater', '<' => 'lesser', '<=' => 'lesserEqual', '>=' => 'greaterEqual']; foreach ($operators as $operator => $operatorVerbose) { @@ -151,10 +158,10 @@ class V12 extends Filter // Let's keep it at true and false string, but without "" around // No action needed } else { - $filterValue = \is_numeric($filterValue) ? $filterValue : '"' . $filterValue . '"'; + $filterValue = \is_numeric($filterValue) ? $filterValue : '"'.$filterValue.'"'; } - $query = $attributeKey . '.' . $operators[$usedOperator] . '(' . $filterValue . ')'; + $query = $attributeKey.'.'.$operators[$usedOperator].'('.$filterValue.')'; \array_push($queries, $query); } } diff --git a/src/Appwrite/Utopia/Request/Filters/V13.php b/src/Appwrite/Utopia/Request/Filters/V13.php index e1122fdd71..3f297b5943 100644 --- a/src/Appwrite/Utopia/Request/Filters/V13.php +++ b/src/Appwrite/Utopia/Request/Filters/V13.php @@ -11,13 +11,13 @@ class V13 extends Filter { switch ($model) { // Replaced Types - case "database.createIntegerAttribute": - case "database.createFloatAttribute": - $content = $this->convertStringToNum($content, "min"); - $content = $this->convertStringToNum($content, "max"); - $content = $this->convertStringToNum($content, "default"); + case 'database.createIntegerAttribute': + case 'database.createFloatAttribute': + $content = $this->convertStringToNum($content, 'min'); + $content = $this->convertStringToNum($content, 'max'); + $content = $this->convertStringToNum($content, 'default'); break; - case "functions.createExecution": + case 'functions.createExecution': $content = $this->convertExecution($content); } @@ -26,13 +26,15 @@ class V13 extends Filter private function convertStringToNum($content, $value) { - $content[$value] = is_null($content[$value]) ? null : (int)$content[$value]; + $content[$value] = is_null($content[$value]) ? null : (int) $content[$value]; + return $content; } private function convertExecution($content) { $content['async'] = true; + return $content; } } diff --git a/src/Appwrite/Utopia/Request/Filters/V14.php b/src/Appwrite/Utopia/Request/Filters/V14.php index 7130307f0d..1b50404f82 100644 --- a/src/Appwrite/Utopia/Request/Filters/V14.php +++ b/src/Appwrite/Utopia/Request/Filters/V14.php @@ -2,8 +2,8 @@ namespace Appwrite\Utopia\Request\Filters; -use Appwrite\Utopia\Request\Filter; use Appwrite\Migration\Version\V13 as MigrationV13; +use Appwrite\Utopia\Request\Filter; class V14 extends Filter { @@ -11,10 +11,10 @@ class V14 extends Filter public function parse(array $content, string $model): array { switch ($model) { - case "functions.create": - case "functions.update": - case "projects.createWebhook": - case "projects.updateWebhook": + case 'functions.create': + case 'functions.update': + case 'projects.createWebhook': + case 'projects.updateWebhook': $content = $this->convertEvents($content); break; } @@ -27,7 +27,7 @@ class V14 extends Filter $migration = new MigrationV13(); $events = $content['events'] ?? []; - $content['events'] = $migration->migrateEvents($events); + $content['events'] = $migration->migrateEvents($events); return $content; } diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php index 318096fe0d..d535777350 100644 --- a/src/Appwrite/Utopia/Request/Filters/V15.php +++ b/src/Appwrite/Utopia/Request/Filters/V15.php @@ -5,8 +5,8 @@ namespace Appwrite\Utopia\Request\Filters; use Appwrite\Utopia\Request\Filter; use Utopia\Database\Database; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Query; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; class V15 extends Filter { @@ -81,11 +81,11 @@ class V15 extends Filter protected function convertLimitAndOffset($content) { if (isset($content['limit'])) { - $content['queries'][] = 'limit(' . $content['limit'] . ')'; + $content['queries'][] = 'limit('.$content['limit'].')'; } if (isset($content['offset'])) { - $content['queries'][] = 'offset(' . $content['offset'] . ')'; + $content['queries'][] = 'offset('.$content['offset'].')'; } unset($content['limit']); @@ -100,9 +100,9 @@ class V15 extends Filter $cursorDirection = $content['cursorDirection'] ?? Database::CURSOR_AFTER; if ($cursorDirection === Database::CURSOR_BEFORE) { - $content['queries'][] = 'cursorBefore("' . $content["cursor"] . '")'; + $content['queries'][] = 'cursorBefore("'.$content['cursor'].'")'; } else { - $content['queries'][] = 'cursorAfter("' . $content["cursor"] . '")'; + $content['queries'][] = 'cursorAfter("'.$content['cursor'].'")'; } } @@ -133,9 +133,9 @@ class V15 extends Filter $attribute = $content['orderAttributes'][$i] ?? ''; if ($type === Database::ORDER_DESC) { - $content['queries'][] = 'orderDesc("' . $attribute . '")'; + $content['queries'][] = 'orderDesc("'.$attribute.'")'; } else { - $content['queries'][] = 'orderAsc("' . $attribute . '")'; + $content['queries'][] = 'orderAsc("'.$attribute.'")'; } } } @@ -194,7 +194,7 @@ class V15 extends Filter protected function convertFilters($content) { - if (!isset($content['queries'])) { + if (! isset($content['queries'])) { return $content; } @@ -214,18 +214,19 @@ class V15 extends Filter $parts = explode($middle, $query); if (count($parts) > 1) { $attribute = $parts[0]; - $value = rtrim($parts[1], ")"); - $content['queries'][$i] = $newOperation . '("' . $attribute . '", [' . $value . '])'; + $value = rtrim($parts[1], ')'); + $content['queries'][$i] = $newOperation.'("'.$attribute.'", ['.$value.'])'; } } } } + return $content; } protected function convertExecute($content) { - if (!isset($content['execute'])) { + if (! isset($content['execute'])) { return $content; } @@ -247,7 +248,7 @@ class V15 extends Filter protected function convertExpire($content) { - if (!isset($content['expire'])) { + if (! isset($content['expire'])) { return $content; } diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 952226a8d9..2954fc9d0d 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -2,14 +2,6 @@ namespace Appwrite\Utopia; -use Appwrite\Utopia\Response\Model\Message; -use Appwrite\Utopia\Response\Model\Subscriber; -use Appwrite\Utopia\Response\Model\Topic; -use Exception; -use Swoole\Http\Request as SwooleRequest; -use Utopia\Swoole\Response as SwooleResponse; -use Swoole\Http\Response as SwooleHTTPResponse; -use Utopia\Database\Document; use Appwrite\Utopia\Response\Filter; use Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response\Model\Account; @@ -20,70 +12,72 @@ use Appwrite\Utopia\Response\Model\AlgoPhpass; use Appwrite\Utopia\Response\Model\AlgoScrypt; use Appwrite\Utopia\Response\Model\AlgoScryptModified; use Appwrite\Utopia\Response\Model\AlgoSha; -use Appwrite\Utopia\Response\Model\None; use Appwrite\Utopia\Response\Model\Any; use Appwrite\Utopia\Response\Model\Attribute; -use Appwrite\Utopia\Response\Model\AttributeList; -use Appwrite\Utopia\Response\Model\AttributeString; -use Appwrite\Utopia\Response\Model\AttributeInteger; -use Appwrite\Utopia\Response\Model\AttributeFloat; use Appwrite\Utopia\Response\Model\AttributeBoolean; +use Appwrite\Utopia\Response\Model\AttributeDatetime; use Appwrite\Utopia\Response\Model\AttributeEmail; use Appwrite\Utopia\Response\Model\AttributeEnum; +use Appwrite\Utopia\Response\Model\AttributeFloat; +use Appwrite\Utopia\Response\Model\AttributeInteger; use Appwrite\Utopia\Response\Model\AttributeIP; -use Appwrite\Utopia\Response\Model\AttributeURL; -use Appwrite\Utopia\Response\Model\AttributeDatetime; +use Appwrite\Utopia\Response\Model\AttributeList; use Appwrite\Utopia\Response\Model\AttributeRelationship; +use Appwrite\Utopia\Response\Model\AttributeString; +use Appwrite\Utopia\Response\Model\AttributeURL; use Appwrite\Utopia\Response\Model\AuthProvider; use Appwrite\Utopia\Response\Model\BaseList; +use Appwrite\Utopia\Response\Model\Bucket; +use Appwrite\Utopia\Response\Model\Build; use Appwrite\Utopia\Response\Model\Collection; -use Appwrite\Utopia\Response\Model\Database; +use Appwrite\Utopia\Response\Model\ConsoleVariables; use Appwrite\Utopia\Response\Model\Continent; use Appwrite\Utopia\Response\Model\Country; use Appwrite\Utopia\Response\Model\Currency; +use Appwrite\Utopia\Response\Model\Database; +use Appwrite\Utopia\Response\Model\Deployment; use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Domain; use Appwrite\Utopia\Response\Model\Error; use Appwrite\Utopia\Response\Model\ErrorDev; use Appwrite\Utopia\Response\Model\Execution; -use Appwrite\Utopia\Response\Model\Build; use Appwrite\Utopia\Response\Model\File; -use Appwrite\Utopia\Response\Model\Bucket; -use Appwrite\Utopia\Response\Model\ConsoleVariables; use Appwrite\Utopia\Response\Model\Func; -use Appwrite\Utopia\Response\Model\Identity; -use Appwrite\Utopia\Response\Model\Index; -use Appwrite\Utopia\Response\Model\JWT; -use Appwrite\Utopia\Response\Model\Key; -use Appwrite\Utopia\Response\Model\Language; -use Appwrite\Utopia\Response\Model\User; -use Appwrite\Utopia\Response\Model\Session; -use Appwrite\Utopia\Response\Model\Team; -use Appwrite\Utopia\Response\Model\Locale; -use Appwrite\Utopia\Response\Model\Log; -use Appwrite\Utopia\Response\Model\Membership; -use Appwrite\Utopia\Response\Model\Metric; -use Appwrite\Utopia\Response\Model\Permissions; -use Appwrite\Utopia\Response\Model\Phone; -use Appwrite\Utopia\Response\Model\Platform; -use Appwrite\Utopia\Response\Model\Project; -use Appwrite\Utopia\Response\Model\Rule; -use Appwrite\Utopia\Response\Model\Deployment; -use Appwrite\Utopia\Response\Model\TemplateEmail; -use Appwrite\Utopia\Response\Model\Token; -use Appwrite\Utopia\Response\Model\Webhook; -use Appwrite\Utopia\Response\Model\Preferences; use Appwrite\Utopia\Response\Model\HealthAntivirus; use Appwrite\Utopia\Response\Model\HealthQueue; use Appwrite\Utopia\Response\Model\HealthStatus; use Appwrite\Utopia\Response\Model\HealthTime; use Appwrite\Utopia\Response\Model\HealthVersion; +use Appwrite\Utopia\Response\Model\Identity; +use Appwrite\Utopia\Response\Model\Index; +use Appwrite\Utopia\Response\Model\JWT; +use Appwrite\Utopia\Response\Model\Key; +use Appwrite\Utopia\Response\Model\Language; +use Appwrite\Utopia\Response\Model\Locale; use Appwrite\Utopia\Response\Model\LocaleCode; -use Appwrite\Utopia\Response\Model\Mock; // Keep last +use Appwrite\Utopia\Response\Model\Log; +use Appwrite\Utopia\Response\Model\Membership; +use Appwrite\Utopia\Response\Model\Message; +use Appwrite\Utopia\Response\Model\Metric; +use Appwrite\Utopia\Response\Model\Migration; +use Appwrite\Utopia\Response\Model\MigrationFirebaseProject; +use Appwrite\Utopia\Response\Model\MigrationReport; +use Appwrite\Utopia\Response\Model\Mock; +use Appwrite\Utopia\Response\Model\None; +use Appwrite\Utopia\Response\Model\Phone; +use Appwrite\Utopia\Response\Model\Platform; +use Appwrite\Utopia\Response\Model\Preferences; +use Appwrite\Utopia\Response\Model\Project; use Appwrite\Utopia\Response\Model\Provider; use Appwrite\Utopia\Response\Model\Runtime; +use Appwrite\Utopia\Response\Model\Session; +use Appwrite\Utopia\Response\Model\Subscriber; use Appwrite\Utopia\Response\Model\Target; +use Appwrite\Utopia\Response\Model\Team; +use Appwrite\Utopia\Response\Model\TemplateEmail; use Appwrite\Utopia\Response\Model\TemplateSMS; +use Appwrite\Utopia\Response\Model\Token; // Keep last +use Appwrite\Utopia\Response\Model\Topic; use Appwrite\Utopia\Response\Model\UsageBuckets; use Appwrite\Utopia\Response\Model\UsageCollection; use Appwrite\Utopia\Response\Model\UsageDatabase; @@ -93,10 +87,13 @@ use Appwrite\Utopia\Response\Model\UsageFunctions; use Appwrite\Utopia\Response\Model\UsageProject; use Appwrite\Utopia\Response\Model\UsageStorage; use Appwrite\Utopia\Response\Model\UsageUsers; +use Appwrite\Utopia\Response\Model\User; use Appwrite\Utopia\Response\Model\Variable; -use Appwrite\Utopia\Response\Model\Migration; -use Appwrite\Utopia\Response\Model\MigrationFirebaseProject; -use Appwrite\Utopia\Response\Model\MigrationReport; +use Appwrite\Utopia\Response\Model\Webhook; +use Exception; +use Swoole\Http\Response as SwooleHTTPResponse; +use Utopia\Database\Document; +use Utopia\Swoole\Response as SwooleResponse; /** * @method int getStatusCode() @@ -106,152 +103,263 @@ class Response extends SwooleResponse { // General public const MODEL_NONE = 'none'; + public const MODEL_ANY = 'any'; + public const MODEL_LOG = 'log'; + public const MODEL_LOG_LIST = 'logList'; + public const MODEL_ERROR = 'error'; + public const MODEL_METRIC = 'metric'; + public const MODEL_METRIC_LIST = 'metricList'; + public const MODEL_ERROR_DEV = 'errorDev'; + public const MODEL_BASE_LIST = 'baseList'; + public const MODEL_USAGE_DATABASES = 'usageDatabases'; + public const MODEL_USAGE_DATABASE = 'usageDatabase'; + public const MODEL_USAGE_COLLECTION = 'usageCollection'; + public const MODEL_USAGE_USERS = 'usageUsers'; + public const MODEL_USAGE_BUCKETS = 'usageBuckets'; + public const MODEL_USAGE_STORAGE = 'usageStorage'; + public const MODEL_USAGE_FUNCTIONS = 'usageFunctions'; + public const MODEL_USAGE_FUNCTION = 'usageFunction'; + public const MODEL_USAGE_PROJECT = 'usageProject'; // Database public const MODEL_DATABASE = 'database'; + public const MODEL_DATABASE_LIST = 'databaseList'; + public const MODEL_COLLECTION = 'collection'; + public const MODEL_COLLECTION_LIST = 'collectionList'; + public const MODEL_INDEX = 'index'; + public const MODEL_INDEX_LIST = 'indexList'; + public const MODEL_DOCUMENT = 'document'; + public const MODEL_DOCUMENT_LIST = 'documentList'; // Database Attributes public const MODEL_ATTRIBUTE = 'attribute'; + public const MODEL_ATTRIBUTE_LIST = 'attributeList'; + public const MODEL_ATTRIBUTE_STRING = 'attributeString'; + public const MODEL_ATTRIBUTE_INTEGER = 'attributeInteger'; + public const MODEL_ATTRIBUTE_FLOAT = 'attributeFloat'; + public const MODEL_ATTRIBUTE_BOOLEAN = 'attributeBoolean'; + public const MODEL_ATTRIBUTE_EMAIL = 'attributeEmail'; + public const MODEL_ATTRIBUTE_ENUM = 'attributeEnum'; + public const MODEL_ATTRIBUTE_IP = 'attributeIp'; + public const MODEL_ATTRIBUTE_URL = 'attributeUrl'; + public const MODEL_ATTRIBUTE_DATETIME = 'attributeDatetime'; + public const MODEL_ATTRIBUTE_RELATIONSHIP = 'attributeRelationship'; // Users public const MODEL_ACCOUNT = 'account'; + public const MODEL_USER = 'user'; + public const MODEL_USER_LIST = 'userList'; + public const MODEL_SESSION = 'session'; + public const MODEL_SESSION_LIST = 'sessionList'; + public const MODEL_IDENTITY = 'identity'; + public const MODEL_IDENTITY_LIST = 'identityList'; + public const MODEL_TOKEN = 'token'; + public const MODEL_JWT = 'jwt'; + public const MODEL_PREFERENCES = 'preferences'; // Users password algos public const MODEL_ALGO_MD5 = 'algoMd5'; + public const MODEL_ALGO_SHA = 'algoSha'; + public const MODEL_ALGO_SCRYPT = 'algoScrypt'; + public const MODEL_ALGO_SCRYPT_MODIFIED = 'algoScryptModified'; + public const MODEL_ALGO_BCRYPT = 'algoBcrypt'; + public const MODEL_ALGO_ARGON2 = 'algoArgon2'; + public const MODEL_ALGO_PHPASS = 'algoPhpass'; // Storage public const MODEL_FILE = 'file'; + public const MODEL_FILE_LIST = 'fileList'; + public const MODEL_BUCKET = 'bucket'; + public const MODEL_BUCKET_LIST = 'bucketList'; // Locale public const MODEL_LOCALE = 'locale'; + public const MODEL_LOCALE_CODE = 'localeCode'; + public const MODEL_LOCALE_CODE_LIST = 'localeCodeList'; + public const MODEL_COUNTRY = 'country'; + public const MODEL_COUNTRY_LIST = 'countryList'; + public const MODEL_CONTINENT = 'continent'; + public const MODEL_CONTINENT_LIST = 'continentList'; + public const MODEL_CURRENCY = 'currency'; + public const MODEL_CURRENCY_LIST = 'currencyList'; + public const MODEL_LANGUAGE = 'language'; + public const MODEL_LANGUAGE_LIST = 'languageList'; + public const MODEL_PHONE = 'phone'; + public const MODEL_PHONE_LIST = 'phoneList'; // Messaging public const MODEL_PROVIDER = 'provider'; + public const MODEL_PROVIDER_LIST = 'providerList'; + public const MODEL_MESSAGE = 'message'; + public const MODEL_MESSAGE_LIST = 'messageList'; + public const MODEL_TOPIC = 'topic'; + public const MODEL_TOPIC_LIST = 'topicList'; + public const MODEL_SUBSCRIBER = 'subscriber'; + public const MODEL_SUBSCRIBER_LIST = 'subscriberList'; + public const MODEL_TARGET = 'target'; + public const MODEL_TARGET_LIST = 'targetList'; // Teams public const MODEL_TEAM = 'team'; + public const MODEL_TEAM_LIST = 'teamList'; + public const MODEL_MEMBERSHIP = 'membership'; + public const MODEL_MEMBERSHIP_LIST = 'membershipList'; // Functions public const MODEL_FUNCTION = 'function'; + public const MODEL_FUNCTION_LIST = 'functionList'; + public const MODEL_RUNTIME = 'runtime'; + public const MODEL_RUNTIME_LIST = 'runtimeList'; + public const MODEL_DEPLOYMENT = 'deployment'; + public const MODEL_DEPLOYMENT_LIST = 'deploymentList'; + public const MODEL_EXECUTION = 'execution'; + public const MODEL_EXECUTION_LIST = 'executionList'; + public const MODEL_BUILD = 'build'; + public const MODEL_BUILD_LIST = 'buildList'; // Not used anywhere yet + public const MODEL_FUNC_PERMISSIONS = 'funcPermissions'; // Migrations public const MODEL_MIGRATION = 'migration'; + public const MODEL_MIGRATION_LIST = 'migrationList'; + public const MODEL_MIGRATION_REPORT = 'migrationReport'; + public const MODEL_MIGRATION_FIREBASE_PROJECT = 'firebaseProject'; + public const MODEL_MIGRATION_FIREBASE_PROJECT_LIST = 'firebaseProjectList'; // Project public const MODEL_PROJECT = 'project'; + public const MODEL_PROJECT_LIST = 'projectList'; + public const MODEL_WEBHOOK = 'webhook'; + public const MODEL_WEBHOOK_LIST = 'webhookList'; + public const MODEL_KEY = 'key'; + public const MODEL_KEY_LIST = 'keyList'; + public const MODEL_AUTH_PROVIDER = 'authProvider'; + public const MODEL_AUTH_PROVIDER_LIST = 'authProviderList'; + public const MODEL_PLATFORM = 'platform'; + public const MODEL_PLATFORM_LIST = 'platformList'; + public const MODEL_DOMAIN = 'domain'; + public const MODEL_DOMAIN_LIST = 'domainList'; + public const MODEL_VARIABLE = 'variable'; + public const MODEL_VARIABLE_LIST = 'variableList'; + public const MODEL_SMS_TEMPLATE = 'smsTemplate'; + public const MODEL_EMAIL_TEMPLATE = 'emailTemplate'; // Health public const MODEL_HEALTH_STATUS = 'healthStatus'; + public const MODEL_HEALTH_VERSION = 'healthVersion'; + public const MODEL_HEALTH_QUEUE = 'healthQueue'; + public const MODEL_HEALTH_TIME = 'healthTime'; + public const MODEL_HEALTH_ANTIVIRUS = 'healthAntivirus'; + public const MODEL_HEALTH_STATUS_LIST = 'healthStatusList'; // Console @@ -259,7 +367,9 @@ class Response extends SwooleResponse // Deprecated public const MODEL_PERMISSIONS = 'permissions'; + public const MODEL_RULE = 'rule'; + public const MODEL_TASK = 'task'; // Tests (keep last) @@ -278,7 +388,7 @@ class Response extends SwooleResponse /** * Response constructor. * - * @param float $time + * @param float $time */ public function __construct(SwooleHTTPResponse $response) { @@ -421,6 +531,7 @@ class Response extends SwooleResponse * HTTP content types */ public const CONTENT_TYPE_YAML = 'application/x-yaml'; + public const CONTENT_TYPE_NULL = 'null'; /** @@ -443,14 +554,15 @@ class Response extends SwooleResponse /** * Get Model Object * - * @param string $key + * @param string $key * @return Model + * * @throws Exception */ public function getModel(string $key): Model { - if (!isset($this->models[$key])) { - throw new Exception('Undefined model: ' . $key); + if (! isset($this->models[$key])) { + throw new Exception('Undefined model: '.$key); } return $this->models[$key]; @@ -470,10 +582,11 @@ class Response extends SwooleResponse * Validate response objects and outputs * the response according to given format type * - * @param Document $document - * @param string $model + * @param Document $document + * @param string $model * * return void + * * @throws Exception */ public function dynamic(Document $document, string $model): void @@ -487,11 +600,11 @@ class Response extends SwooleResponse switch ($this->getContentType()) { case self::CONTENT_TYPE_JSON: - $this->json(!empty($output) ? $output : new \stdClass()); + $this->json(! empty($output) ? $output : new \stdClass()); break; case self::CONTENT_TYPE_YAML: - $this->yaml(!empty($output) ? $output : new \stdClass()); + $this->yaml(! empty($output) ? $output : new \stdClass()); break; case self::CONTENT_TYPE_NULL: @@ -501,7 +614,7 @@ class Response extends SwooleResponse if ($model === self::MODEL_NONE) { $this->noContent(); } else { - $this->json(!empty($output) ? $output : new \stdClass()); + $this->json(! empty($output) ? $output : new \stdClass()); } break; } @@ -510,18 +623,19 @@ class Response extends SwooleResponse /** * Generate valid response object from document data * - * @param Document $document - * @param string $model + * @param Document $document + * @param string $model * * return array * @return array + * * @throws Exception */ public function output(Document $document, string $model): array { - $data = new Document($document->getArrayCopy()); - $model = $this->getModel($model); - $output = []; + $data = new Document($document->getArrayCopy()); + $model = $this->getModel($model); + $output = []; $data = $model->filter($document); @@ -532,17 +646,17 @@ class Response extends SwooleResponse } foreach ($model->getRules() as $key => $rule) { - if (!$document->isSet($key) && $rule['required']) { // do not set attribute in response if not required + if (! $document->isSet($key) && $rule['required']) { // do not set attribute in response if not required if (\array_key_exists('default', $rule)) { $data->setAttribute($key, $rule['default']); } else { - throw new Exception('Model ' . $model->getName() . ' is missing response key: ' . $key); + throw new Exception('Model '.$model->getName().' is missing response key: '.$key); } } if ($rule['array']) { - if (!is_array($document[$key])) { - throw new Exception($key . ' must be an array of type ' . $rule['type']); + if (! is_array($document[$key])) { + throw new Exception($key.' must be an array of type '.$rule['type']); } foreach ($document[$key] as $index => $item) { @@ -552,7 +666,7 @@ class Response extends SwooleResponse $condition = false; foreach ($this->getModel($type)->conditions as $attribute => $val) { $condition = $item->getAttribute($attribute) === $val; - if (!$condition) { + if (! $condition) { break; } } @@ -565,8 +679,8 @@ class Response extends SwooleResponse $ruleType = $rule['type']; } - if (!array_key_exists($ruleType, $this->models)) { - throw new Exception('Missing model for rule: ' . $ruleType); + if (! array_key_exists($ruleType, $this->models)) { + throw new Exception('Missing model for rule: '.$ruleType); } $data[$key][$index] = $this->output($item, $ruleType); @@ -591,14 +705,13 @@ class Response extends SwooleResponse * * Generate HTTP response output including the response header (+cookies) and body and prints them. * - * @param string $body - * + * @param string $body * @return void */ public function file(string $body = ''): void { $this->payload = [ - 'payload' => $body + 'payload' => $body, ]; $this->send($body); @@ -612,14 +725,14 @@ class Response extends SwooleResponse * * @see https://en.wikipedia.org/wiki/YAML * - * @param array $data - * + * @param array $data * @return void + * * @throws Exception */ public function yaml(array $data): void { - if (!extension_loaded('yaml')) { + if (! extension_loaded('yaml')) { throw new Exception('Missing yaml extension. Learn more at: https://www.php.net/manual/en/book.yaml.php'); } @@ -640,7 +753,6 @@ class Response extends SwooleResponse * Function to set a response filter * * @param $filter the response filter to set - * * @return void */ public static function setFilter(?Filter $filter) diff --git a/src/Appwrite/Utopia/Response/Filter.php b/src/Appwrite/Utopia/Response/Filter.php index 9110abd07a..47cca955fe 100644 --- a/src/Appwrite/Utopia/Response/Filter.php +++ b/src/Appwrite/Utopia/Response/Filter.php @@ -7,9 +7,8 @@ abstract class Filter /** * Parse the content to another format. * - * @param array $content - * @param string $model - * + * @param array $content + * @param string $model * @return array */ abstract public function parse(array $content, string $model): array; diff --git a/src/Appwrite/Utopia/Response/Filters/V11.php b/src/Appwrite/Utopia/Response/Filters/V11.php index 8fa22f42b2..09f9fbfc06 100644 --- a/src/Appwrite/Utopia/Response/Filters/V11.php +++ b/src/Appwrite/Utopia/Response/Filters/V11.php @@ -42,7 +42,7 @@ class V11 extends Filter $parsedResponse = $this->parseFunctionsList($content); break; - // Convert status from boolean to int + // Convert status from boolean to int case Response::MODEL_USER: $parsedResponse = $this->parseStatus($content); break; @@ -50,7 +50,7 @@ class V11 extends Filter $parsedResponse = $this->parseUserList($content); break; - // Convert all Health responses back to original + // Convert all Health responses back to original case Response::MODEL_HEALTH_STATUS: $parsedResponse = $this->parseHealthStatus($content); break; @@ -67,7 +67,7 @@ class V11 extends Filter $parsedResponse = $this->parseHealthAntivirus($content); break; - // Complex filters + // Complex filters case Response::MODEL_COLLECTION: $parsedResponse = $this->parseCollection($content); break; @@ -101,6 +101,7 @@ class V11 extends Filter $parsedResponse[] = $this->parsePermissions($document); } $content['documents'] = $parsedResponse; + return $content; } @@ -112,6 +113,7 @@ class V11 extends Filter $parsedResponse[] = $this->parsePermissions($file); } $content['files'] = $parsedResponse; + return $content; } @@ -123,6 +125,7 @@ class V11 extends Filter $parsedResponse[] = $this->parseExecutionPermissions($execution); } $content['executions'] = $parsedResponse; + return $content; } @@ -134,6 +137,7 @@ class V11 extends Filter $parsedResponse[] = $this->parseFunctionPermissions($function); } $content['functions'] = $parsedResponse; + return $content; } @@ -145,6 +149,7 @@ class V11 extends Filter $parsedResponse[] = $this->parseStatus($user); } $content['users'] = $parsedResponse; + return $content; } @@ -159,6 +164,7 @@ class V11 extends Filter $parsedResponse = $this->addDate($content, 'dateCreated'); $parsedResponse = $this->addDate($content, 'dateUpdated'); $parsedResponse = $this->parseAttributes($content); + return $parsedResponse; } @@ -170,6 +176,7 @@ class V11 extends Filter $parsedResponse[] = $this->parseCollection($collection); } $content['collections'] = $parsedResponse; + return $content; } @@ -181,6 +188,7 @@ class V11 extends Filter $parsedResponse = $this->removeRule($content, 'userName'); $parsedResponse = $this->removeRule($content, 'mode'); $parsedResponse = $this->removeRule($content, 'sum'); + return $parsedResponse; } @@ -192,6 +200,7 @@ class V11 extends Filter $parsedResponse[] = $this->parseLog($log); } $content['logs'] = $parsedResponse; + return $content; } @@ -203,6 +212,7 @@ class V11 extends Filter $parsedResponse = $this->parseOAuths($content); $parsedResponse = $this->parseAuthsStatus($content); $parsedResponse = $this->removeServicesStatus($content); + return $parsedResponse; } @@ -214,6 +224,7 @@ class V11 extends Filter $parsedResponse[] = $this->parseProject($project); } $content['projects'] = $parsedResponse; + return $content; } @@ -248,7 +259,6 @@ class V11 extends Filter return $content; } - protected function parseHealthQueue(array $content) { // Did not change @@ -303,15 +313,15 @@ class V11 extends Filter protected function parseOAuths(array $content) { - $regexPattern = "/provider([a-zA-Z0-9]+)(Appid|Secret)/"; + $regexPattern = '/provider([a-zA-Z0-9]+)(Appid|Secret)/'; foreach ($content as $key => $value) { \preg_match_all($regexPattern, $key, $regexGroups); if (\count($regexGroups[1]) > 0 && \count($regexGroups[2]) > 0) { $providerName = $regexGroups[1][0]; $valueKey = $regexGroups[2][0]; - $content['usersOauth2' . $providerName . $valueKey] = $value; - unset($content['provider' . $providerName . $valueKey]); + $content['usersOauth2'.$providerName.$valueKey] = $value; + unset($content['provider'.$providerName.$valueKey]); } } @@ -320,7 +330,7 @@ class V11 extends Filter protected function parseAuthsStatus(array $content) { - $regexPattern = "/auth([a-zA-Z0-9]+)/"; + $regexPattern = '/auth([a-zA-Z0-9]+)/'; foreach ($content as $key => $value) { \preg_match_all($regexPattern, $key, $regexGroups); @@ -328,7 +338,7 @@ class V11 extends Filter $providerName = $regexGroups[1][0]; $content[$providerName] = $value; - unset($content['auth' . $providerName]); + unset($content['auth'.$providerName]); } } @@ -377,15 +387,16 @@ class V11 extends Filter protected function parsePermissions(array $content) { - $content['$permissions'] = [ 'read' => $content['$read'], 'write' => $content['$write'] ]; + $content['$permissions'] = ['read' => $content['$read'], 'write' => $content['$write']]; unset($content['$read']); unset($content['$write']); + return $content; } protected function parseFunctionPermissions(array $content) { - $content['$permissions'] = [ 'execute' => $content['execute'] ]; + $content['$permissions'] = ['execute' => $content['execute']]; unset($content['execute']); return $content; @@ -393,7 +404,7 @@ class V11 extends Filter protected function parseExecutionPermissions(array $content) { - $content['$permissions'] = [ 'read' => $content['$read'] ]; + $content['$permissions'] = ['read' => $content['$read']]; unset($content['$read']); return $content; diff --git a/src/Appwrite/Utopia/Response/Filters/V12.php b/src/Appwrite/Utopia/Response/Filters/V12.php index 79d22ad044..795135bf43 100644 --- a/src/Appwrite/Utopia/Response/Filters/V12.php +++ b/src/Appwrite/Utopia/Response/Filters/V12.php @@ -99,6 +99,7 @@ class V12 extends Filter protected function parseError(array $content) { unset($content['type']); + return $content; } @@ -124,6 +125,7 @@ class V12 extends Filter $content['sessions'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); + return $content; } @@ -146,6 +148,7 @@ class V12 extends Filter $content['files'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); + return $content; } @@ -153,6 +156,7 @@ class V12 extends Filter { $content['tag'] = $content['deployment']; unset($content['deployment']); + return $content; } @@ -166,6 +170,7 @@ class V12 extends Filter $content['functions'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); + return $content; } @@ -173,6 +178,7 @@ class V12 extends Filter { $content['functionId'] = $content['resourceId']; $content['command'] = $content['entrypoint']; + return $content; } @@ -186,12 +192,14 @@ class V12 extends Filter $content['deployments'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); + return $content; } protected function parseUsageBuckets(array $content) { unset($content['filesStorage']); + return $content; } @@ -237,6 +245,7 @@ class V12 extends Filter $content['executions'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); + return $content; } @@ -244,6 +253,7 @@ class V12 extends Filter { $content['sum'] = $content['total']; unset($content['total']); + return $content; } @@ -257,6 +267,7 @@ class V12 extends Filter $content['teams'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); + return $content; } @@ -264,6 +275,7 @@ class V12 extends Filter { $content['sum'] = $content['total']; unset($content['total']); + return $content; } } diff --git a/src/Appwrite/Utopia/Response/Filters/V13.php b/src/Appwrite/Utopia/Response/Filters/V13.php index d48473593e..2c613280ac 100644 --- a/src/Appwrite/Utopia/Response/Filters/V13.php +++ b/src/Appwrite/Utopia/Response/Filters/V13.php @@ -55,6 +55,7 @@ class V13 extends Filter $parsedResponse[] = $this->parseExecution($document); } $content['executions'] = $parsedResponse; + return $content; } @@ -74,6 +75,7 @@ class V13 extends Filter $parsedResponse[] = $this->parseProject($document); } $content['projects'] = $parsedResponse; + return $content; } @@ -98,6 +100,7 @@ class V13 extends Filter $parsedResponse[] = $this->parseMembership($document); } $content['memberships'] = $parsedResponse; + return $content; } } diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index 232feec201..fadf426f1d 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -210,11 +210,13 @@ class V15 extends Filter if (array_key_exists($attribute, $content)) { if (empty($content[$attribute])) { $content[$attribute] = 0; + continue; } $content[$attribute] = strtotime($content[$attribute]); } } + return $content; } @@ -225,18 +227,20 @@ class V15 extends Filter unset($content['hashOptions']); $content = $this->parseDatetimeAttributes($content, ['registration', 'passwordUpdate', '$createdAt', '$updatedAt']); + return $content; } protected function parseMetric(array $content) { $content = $this->parseDatetimeAttributes($content, ['date']); + return $content; } protected function parsePermissions(array $content) { - if (!isset($content['$permissions'])) { + if (! isset($content['$permissions'])) { return $content; } @@ -248,10 +252,10 @@ class V15 extends Filter $permission = Permission::parse($permission); $permission_value = $permission->getRole(); if ($permission->getIdentifier()) { - $permission_value .= ':' . $permission->getIdentifier(); + $permission_value .= ':'.$permission->getIdentifier(); } if ($permission->getDimension()) { - $permission_value .= '/' . $permission->getDimension(); + $permission_value .= '/'.$permission->getDimension(); } // Old type permissions meant that 'write' is equivalent to 'create', 'update' and 'delete' @@ -305,6 +309,7 @@ class V15 extends Filter unset($content['documentSecurity']); $content = $this->parsePermissions($content); $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + return $content; } @@ -312,6 +317,7 @@ class V15 extends Filter { $content = $this->parsePermissions($content); $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + return $content; } @@ -325,6 +331,7 @@ class V15 extends Filter unset($content['$databaseId']); $content = $this->parsePermissionsCreatedAtUpdatedAt($content); + return $content; } @@ -354,6 +361,7 @@ class V15 extends Filter private function parseCreatedAtUpdatedAt($content) { $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + return $content; } @@ -386,24 +394,28 @@ class V15 extends Filter private function parseKey($content) { $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'expire']); + return $content; } private function parseLog($content) { $content = $this->parseDatetimeAttributes($content, ['time']); + return $content; } private function parseMembership($content) { $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'invited', 'joined']); + return $content; } private function parseSession($content) { $content = $this->parseDatetimeAttributes($content, ['$createdAt', 'expire', 'providerAccessTokenExpiry']); + return $content; } diff --git a/src/Appwrite/Utopia/Response/Model.php b/src/Appwrite/Utopia/Response/Model.php index 8a0bb78cba..4aa4189248 100644 --- a/src/Appwrite/Utopia/Response/Model.php +++ b/src/Appwrite/Utopia/Response/Model.php @@ -7,12 +7,19 @@ use Utopia\Database\Document; abstract class Model { public const TYPE_STRING = 'string'; + public const TYPE_INTEGER = 'integer'; + public const TYPE_FLOAT = 'double'; + public const TYPE_BOOLEAN = 'boolean'; + public const TYPE_JSON = 'json'; + public const TYPE_DATETIME = 'datetime'; + public const TYPE_DATETIME_EXAMPLE = '2020-10-15T06:38:00.000+00:00'; + public const TYPE_RELATIONSHIP = 'relationship'; /** @@ -40,7 +47,6 @@ abstract class Model */ public array $conditions = []; - /** * Filter Document Structure * @@ -79,8 +85,8 @@ abstract class Model * Add a New Rule * If rule is an array of documents with varying models * - * @param string $key - * @param array $options + * @param string $key + * @param array $options * @return Model */ protected function addRule(string $key, array $options): self @@ -89,7 +95,7 @@ abstract class Model 'required' => true, 'array' => false, 'description' => '', - 'example' => '' + 'example' => '', ], $options); return $this; @@ -99,7 +105,7 @@ abstract class Model * Delete an existing Rule * If rule exists, it will be removed * - * @param string $key + * @param string $key * @return Model */ protected function removeRule(string $key): self diff --git a/src/Appwrite/Utopia/Response/Model/AlgoArgon2.php b/src/Appwrite/Utopia/Response/Model/AlgoArgon2.php index 3e162bb905..ff2b0f94e0 100644 --- a/src/Appwrite/Utopia/Response/Model/AlgoArgon2.php +++ b/src/Appwrite/Utopia/Response/Model/AlgoArgon2.php @@ -34,8 +34,7 @@ class AlgoArgon2 extends Model 'description' => 'Number of threads used to compute hash.', 'default' => '', 'example' => 3, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/AlgoScrypt.php b/src/Appwrite/Utopia/Response/Model/AlgoScrypt.php index 4dda297d71..066f976433 100644 --- a/src/Appwrite/Utopia/Response/Model/AlgoScrypt.php +++ b/src/Appwrite/Utopia/Response/Model/AlgoScrypt.php @@ -39,8 +39,7 @@ class AlgoScrypt extends Model 'description' => 'Length used to compute hash.', 'default' => 64, 'example' => 64, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/AlgoScryptModified.php b/src/Appwrite/Utopia/Response/Model/AlgoScryptModified.php index 40b9df1dad..73104eba7a 100644 --- a/src/Appwrite/Utopia/Response/Model/AlgoScryptModified.php +++ b/src/Appwrite/Utopia/Response/Model/AlgoScryptModified.php @@ -33,8 +33,7 @@ class AlgoScryptModified extends Model 'description' => 'Key used to compute hash.', 'default' => '', 'example' => 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ==', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Attribute.php b/src/Appwrite/Utopia/Response/Model/Attribute.php index 9f9ceca317..c7a014bd32 100644 --- a/src/Appwrite/Utopia/Response/Model/Attribute.php +++ b/src/Appwrite/Utopia/Response/Model/Attribute.php @@ -46,8 +46,7 @@ class Attribute extends Model 'default' => false, 'required' => false, 'example' => false, - ]) - ; + ]); } public array $conditions = []; diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php index 05846817ca..e96140d0b3 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -28,13 +28,12 @@ class AttributeBoolean extends Attribute 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', 'default' => null, 'required' => false, - 'example' => false - ]) - ; + 'example' => false, + ]); } public array $conditions = [ - 'type' => self::TYPE_BOOLEAN + 'type' => self::TYPE_BOOLEAN, ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php index 4651aebd06..ccad8e7627 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php @@ -37,12 +37,11 @@ class AttributeDatetime extends Attribute 'example' => self::TYPE_DATETIME_EXAMPLE, 'array' => false, 'required' => false, - ]) - ; + ]); } public array $conditions = [ - 'type' => self::TYPE_DATETIME + 'type' => self::TYPE_DATETIME, ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php index 078087dd4b..ffcdbc6eb1 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -35,13 +35,12 @@ class AttributeEmail extends Attribute 'default' => null, 'required' => false, 'example' => 'default@example.com', - ]) - ; + ]); } public array $conditions = [ 'type' => self::TYPE_STRING, - 'format' => \APP_DATABASE_ATTRIBUTE_EMAIL + 'format' => \APP_DATABASE_ATTRIBUTE_EMAIL, ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEnum.php b/src/Appwrite/Utopia/Response/Model/AttributeEnum.php index 992b62ee3a..0549c3cbe6 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEnum.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEnum.php @@ -42,13 +42,12 @@ class AttributeEnum extends Attribute 'default' => null, 'required' => false, 'example' => 'element', - ]) - ; + ]); } public array $conditions = [ 'type' => self::TYPE_STRING, - 'format' => \APP_DATABASE_ATTRIBUTE_ENUM + 'format' => \APP_DATABASE_ATTRIBUTE_ENUM, ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index 266b89c330..28bd88e749 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -43,8 +43,7 @@ class AttributeFloat extends Attribute 'default' => null, 'required' => false, 'example' => 2.5, - ]) - ; + ]); } public array $conditions = [ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php index cfa309317a..2e746d735a 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeIP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -35,13 +35,12 @@ class AttributeIP extends Attribute 'default' => null, 'required' => false, 'example' => '192.0.2.0', - ]) - ; + ]); } public array $conditions = [ 'type' => self::TYPE_STRING, - 'format' => \APP_DATABASE_ATTRIBUTE_IP + 'format' => \APP_DATABASE_ATTRIBUTE_IP, ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index fddfe57445..f672592553 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -43,8 +43,7 @@ class AttributeInteger extends Attribute 'default' => null, 'required' => false, 'example' => 10, - ]) - ; + ]); } public array $conditions = [ @@ -53,6 +52,7 @@ class AttributeInteger extends Attribute /** * Get Name * + * * @return string */ public function getName(): string diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php index 8b04475a14..b093dd7fe9 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeList.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -27,13 +27,12 @@ class AttributeList extends Model Response::MODEL_ATTRIBUTE_IP, Response::MODEL_ATTRIBUTE_DATETIME, Response::MODEL_ATTRIBUTE_RELATIONSHIP, - Response::MODEL_ATTRIBUTE_STRING // needs to be last, since its condition would dominate any other string attribute + Response::MODEL_ATTRIBUTE_STRING, // needs to be last, since its condition would dominate any other string attribute ], 'description' => 'List of attributes.', 'default' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php b/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php index d88fbd1530..73b6a566f2 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php @@ -47,8 +47,7 @@ class AttributeRelationship extends Attribute 'description' => 'Whether this is the parent or child side of the relationship', 'default' => '', 'example' => 'parent|child', - ]) - ; + ]); } public array $conditions = [ @@ -83,7 +82,7 @@ class AttributeRelationship extends Attribute public function filter(Document $document): Document { $options = $document->getAttribute('options'); - if (!\is_null($options)) { + if (! \is_null($options)) { $document->setAttribute('relatedCollection', $options['relatedCollection']); $document->setAttribute('relationType', $options['relationType']); $document->setAttribute('twoWay', $options['twoWay']); @@ -91,6 +90,7 @@ class AttributeRelationship extends Attribute $document->setAttribute('side', $options['side']); $document->setAttribute('onDelete', $options['onDelete']); } + return $document; } } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index 12bb42009d..eb72d705e6 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -23,8 +23,7 @@ class AttributeString extends Attribute 'default' => null, 'required' => false, 'example' => 'default', - ]) - ; + ]); } public array $conditions = [ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php index 633d5b49d7..78bd9c24d2 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeURL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -35,13 +35,12 @@ class AttributeURL extends Attribute 'default' => null, 'required' => false, 'example' => 'http://example.com', - ]) - ; + ]); } public array $conditions = [ 'type' => self::TYPE_STRING, - 'format' => \APP_DATABASE_ATTRIBUTE_URL + 'format' => \APP_DATABASE_ATTRIBUTE_URL, ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AuthProvider.php b/src/Appwrite/Utopia/Response/Model/AuthProvider.php index 0171a3c152..840a2aa661 100644 --- a/src/Appwrite/Utopia/Response/Model/AuthProvider.php +++ b/src/Appwrite/Utopia/Response/Model/AuthProvider.php @@ -43,8 +43,7 @@ class AuthProvider extends Model 'type' => self::TYPE_BOOLEAN, 'description' => 'Auth Provider is active and can be used to create session.', 'example' => '', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/BaseList.php b/src/Appwrite/Utopia/Response/Model/BaseList.php index 0c2cc072f3..cb0010a4e9 100644 --- a/src/Appwrite/Utopia/Response/Model/BaseList.php +++ b/src/Appwrite/Utopia/Response/Model/BaseList.php @@ -17,12 +17,12 @@ class BaseList extends Model protected string $type = ''; /** - * @param string $name - * @param string $type - * @param string $key - * @param string $model - * @param bool $paging - * @param bool $public + * @param string $name + * @param string $type + * @param string $key + * @param string $model + * @param bool $paging + * @param bool $public */ public function __construct(string $name, string $type, string $key, string $model, bool $paging = true, bool $public = true) { @@ -34,13 +34,13 @@ class BaseList extends Model $namesWithCap = [ 'documents', 'collections', 'users', 'files', 'buckets', 'functions', 'deployments', 'executions', 'projects', 'webhooks', 'keys', - 'platforms', 'domains', 'memberships', 'teams', 'targets' + 'platforms', 'domains', 'memberships', 'teams', 'targets', ]; if (\in_array($name, $namesWithCap)) { - $description = 'Total number of ' . $key . ' documents that matched your query used as reference for offset pagination. When the `total` number of ' . $key . ' documents available is greater than 5000, total returned will be capped at 5000, and cursor pagination should be used. Read more about [pagination](https://appwrite.io/docs/pagination).'; + $description = 'Total number of '.$key.' documents that matched your query used as reference for offset pagination. When the `total` number of '.$key.' documents available is greater than 5000, total returned will be capped at 5000, and cursor pagination should be used. Read more about [pagination](https://appwrite.io/docs/pagination).'; } else { - $description = 'Total number of ' . $key . ' documents that matched your query.'; + $description = 'Total number of '.$key.' documents that matched your query.'; } $this->addRule('total', [ @@ -52,7 +52,7 @@ class BaseList extends Model } $this->addRule($key, [ 'type' => $model, - 'description' => 'List of ' . $key . '.', + 'description' => 'List of '.$key.'.', 'default' => [], 'array' => true, ]); diff --git a/src/Appwrite/Utopia/Response/Model/Bucket.php b/src/Appwrite/Utopia/Response/Model/Bucket.php index 0276c1d1f9..16f1b02f24 100644 --- a/src/Appwrite/Utopia/Response/Model/Bucket.php +++ b/src/Appwrite/Utopia/Response/Model/Bucket.php @@ -64,14 +64,14 @@ class Bucket extends Model 'description' => 'Allowed file extensions.', 'default' => [], 'example' => ['jpg', 'png'], - 'array' => true + 'array' => true, ]) ->addRule('compression', [ 'type' => self::TYPE_STRING, - 'description' => 'Compression algorithm choosen for compression. Will be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd).', + 'description' => 'Compression algorithm choosen for compression. Will be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd).', 'default' => '', 'example' => 'gzip', - 'array' => false + 'array' => false, ]) ->addRule('encryption', [ 'type' => self::TYPE_BOOLEAN, @@ -84,8 +84,7 @@ class Bucket extends Model 'description' => 'Virus scanning is enabled.', 'default' => true, 'example' => false, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Build.php b/src/Appwrite/Utopia/Response/Model/Build.php index b76f0ee083..f8709bd027 100644 --- a/src/Appwrite/Utopia/Response/Model/Build.php +++ b/src/Appwrite/Utopia/Response/Model/Build.php @@ -62,8 +62,7 @@ class Build extends Model 'description' => 'The build duration in seconds.', 'default' => 0, 'example' => 0, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Collection.php b/src/Appwrite/Utopia/Response/Model/Collection.php index ae3e283378..2c876f2809 100644 --- a/src/Appwrite/Utopia/Response/Model/Collection.php +++ b/src/Appwrite/Utopia/Response/Model/Collection.php @@ -33,7 +33,7 @@ class Collection extends Model 'description' => 'Collection permissions. [Learn more about permissions](/docs/permissions).', 'default' => '', 'example' => ['read("any")'], - 'array' => true + 'array' => true, ]) ->addRule('databaseId', [ 'type' => self::TYPE_STRING, @@ -82,9 +82,8 @@ class Collection extends Model 'description' => 'Collection indexes.', 'default' => [], 'example' => new \stdClass(), - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Continent.php b/src/Appwrite/Utopia/Response/Model/Continent.php index 5291424a4a..4fd5c9e095 100644 --- a/src/Appwrite/Utopia/Response/Model/Continent.php +++ b/src/Appwrite/Utopia/Response/Model/Continent.php @@ -21,8 +21,7 @@ class Continent extends Model 'description' => 'Continent two letter code.', 'default' => '', 'example' => 'EU', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Country.php b/src/Appwrite/Utopia/Response/Model/Country.php index 64590a54d4..866460f929 100644 --- a/src/Appwrite/Utopia/Response/Model/Country.php +++ b/src/Appwrite/Utopia/Response/Model/Country.php @@ -21,8 +21,7 @@ class Country extends Model 'description' => 'Country two-character ISO 3166-1 alpha code.', 'default' => '', 'example' => 'US', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Currency.php b/src/Appwrite/Utopia/Response/Model/Currency.php index 883ef486d8..e938f8a454 100644 --- a/src/Appwrite/Utopia/Response/Model/Currency.php +++ b/src/Appwrite/Utopia/Response/Model/Currency.php @@ -51,8 +51,7 @@ class Currency extends Model 'description' => 'Currency plural name', 'default' => '', 'example' => 'US dollars', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Database.php b/src/Appwrite/Utopia/Response/Model/Database.php index bd9ae4625c..14e89419c3 100644 --- a/src/Appwrite/Utopia/Response/Model/Database.php +++ b/src/Appwrite/Utopia/Response/Model/Database.php @@ -39,8 +39,7 @@ class Database extends Model 'description' => 'Database enabled.', 'default' => true, 'example' => false, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Deployment.php b/src/Appwrite/Utopia/Response/Model/Deployment.php index 8862d6a14e..be571810b8 100644 --- a/src/Appwrite/Utopia/Response/Model/Deployment.php +++ b/src/Appwrite/Utopia/Response/Model/Deployment.php @@ -87,8 +87,7 @@ class Deployment extends Model 'description' => 'The current build time in seconds.', 'default' => 0, 'example' => 128, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Domain.php b/src/Appwrite/Utopia/Response/Model/Domain.php index 135bb52f90..9218a6fdf9 100644 --- a/src/Appwrite/Utopia/Response/Model/Domain.php +++ b/src/Appwrite/Utopia/Response/Model/Domain.php @@ -62,8 +62,7 @@ class Domain extends Model 'description' => 'Certificate ID.', 'default' => '', 'example' => '6ejea5c13377e', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Error.php b/src/Appwrite/Utopia/Response/Model/Error.php index 99cf3cbce2..6fc182214d 100644 --- a/src/Appwrite/Utopia/Response/Model/Error.php +++ b/src/Appwrite/Utopia/Response/Model/Error.php @@ -33,8 +33,7 @@ class Error extends Model 'description' => 'Server version number.', 'default' => '', 'example' => '1.0', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/ErrorDev.php b/src/Appwrite/Utopia/Response/Model/ErrorDev.php index 9319397c77..4911da6bc7 100644 --- a/src/Appwrite/Utopia/Response/Model/ErrorDev.php +++ b/src/Appwrite/Utopia/Response/Model/ErrorDev.php @@ -34,8 +34,7 @@ class ErrorDev extends Error 'default' => [], 'example' => '', 'array' => true, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Execution.php b/src/Appwrite/Utopia/Response/Model/Execution.php index 8672a91598..d4bd212e93 100644 --- a/src/Appwrite/Utopia/Response/Model/Execution.php +++ b/src/Appwrite/Utopia/Response/Model/Execution.php @@ -83,8 +83,7 @@ class Execution extends Model 'description' => 'The script execution duration in seconds.', 'default' => 0, 'example' => 0.400, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/File.php b/src/Appwrite/Utopia/Response/Model/File.php index 53469f46b3..a9a89d2a41 100644 --- a/src/Appwrite/Utopia/Response/Model/File.php +++ b/src/Appwrite/Utopia/Response/Model/File.php @@ -76,8 +76,7 @@ class File extends Model 'description' => 'Total number of chunks uploaded', 'default' => 0, 'example' => 17890, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Func.php b/src/Appwrite/Utopia/Response/Model/Func.php index c4044c0f2e..b3424b5e7c 100644 --- a/src/Appwrite/Utopia/Response/Model/Func.php +++ b/src/Appwrite/Utopia/Response/Model/Func.php @@ -4,8 +4,6 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; -use stdClass; -use Utopia\Database\Document; class Func extends Model { @@ -66,7 +64,7 @@ class Func extends Model 'description' => 'Function variables.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('events', [ 'type' => self::TYPE_STRING, @@ -86,8 +84,7 @@ class Func extends Model 'description' => 'Function execution timeout in seconds.', 'default' => 15, 'example' => 15, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthAntivirus.php b/src/Appwrite/Utopia/Response/Model/HealthAntivirus.php index 7a74195371..97d608ff09 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthAntivirus.php +++ b/src/Appwrite/Utopia/Response/Model/HealthAntivirus.php @@ -21,8 +21,7 @@ class HealthAntivirus extends Model 'description' => 'Antivirus status. Possible values can are: `disabled`, `offline`, `online`', 'default' => '', 'example' => 'online', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthQueue.php b/src/Appwrite/Utopia/Response/Model/HealthQueue.php index da7c49a43f..5990a4c5d3 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthQueue.php +++ b/src/Appwrite/Utopia/Response/Model/HealthQueue.php @@ -15,8 +15,7 @@ class HealthQueue extends Model 'description' => 'Amount of actions in the queue.', 'default' => 0, 'example' => 8, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthStatus.php b/src/Appwrite/Utopia/Response/Model/HealthStatus.php index ba340107ac..2bd8706763 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthStatus.php +++ b/src/Appwrite/Utopia/Response/Model/HealthStatus.php @@ -27,8 +27,7 @@ class HealthStatus extends Model 'description' => 'Service status. Possible values can are: `pass`, `fail`', 'default' => '', 'example' => 'pass', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthTime.php b/src/Appwrite/Utopia/Response/Model/HealthTime.php index 042d073ce5..0484b8ec33 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthTime.php +++ b/src/Appwrite/Utopia/Response/Model/HealthTime.php @@ -27,8 +27,7 @@ class HealthTime extends Model 'description' => 'Difference of unix remote and local timestamps in milliseconds.', 'default' => 0, 'example' => 93, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthVersion.php b/src/Appwrite/Utopia/Response/Model/HealthVersion.php index 15a73c0e75..6fab34576d 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthVersion.php +++ b/src/Appwrite/Utopia/Response/Model/HealthVersion.php @@ -15,8 +15,7 @@ class HealthVersion extends Model 'description' => 'Version of the Appwrite instance.', 'default' => '', 'example' => '0.11.0', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Identity.php b/src/Appwrite/Utopia/Response/Model/Identity.php index ff7f57a3e6..c23948acbf 100644 --- a/src/Appwrite/Utopia/Response/Model/Identity.php +++ b/src/Appwrite/Utopia/Response/Model/Identity.php @@ -69,8 +69,7 @@ class Identity extends Model 'description' => 'Identity Provider Refresh Token.', 'default' => '', 'example' => 'MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Index.php b/src/Appwrite/Utopia/Response/Model/Index.php index 3d3d1a3b52..dcda9d11c6 100644 --- a/src/Appwrite/Utopia/Response/Model/Index.php +++ b/src/Appwrite/Utopia/Response/Model/Index.php @@ -48,8 +48,7 @@ class Index extends Model 'example' => [], 'array' => true, 'required' => false, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/JWT.php b/src/Appwrite/Utopia/Response/Model/JWT.php index a2563a2ad8..debb81b28e 100644 --- a/src/Appwrite/Utopia/Response/Model/JWT.php +++ b/src/Appwrite/Utopia/Response/Model/JWT.php @@ -14,8 +14,7 @@ class JWT extends Model 'type' => self::TYPE_STRING, 'description' => 'JWT encoded string.', 'example' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Key.php b/src/Appwrite/Utopia/Response/Model/Key.php index 1179a73d62..1dba4e771b 100644 --- a/src/Appwrite/Utopia/Response/Model/Key.php +++ b/src/Appwrite/Utopia/Response/Model/Key.php @@ -60,18 +60,17 @@ class Key extends Model ]) ->addRule('accessedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_KEY_ACCCESS / 60 / 60 . ' hours.', + 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after '.APP_KEY_ACCCESS / 60 / 60 .' hours.', 'default' => '', - 'example' => self::TYPE_DATETIME_EXAMPLE + 'example' => self::TYPE_DATETIME_EXAMPLE, ]) ->addRule('sdks', [ 'type' => self::TYPE_STRING, 'description' => 'List of SDK user agents that used this key.', 'default' => null, 'example' => 'appwrite:flutter', - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Language.php b/src/Appwrite/Utopia/Response/Model/Language.php index 64f99a006f..c3f1072c82 100644 --- a/src/Appwrite/Utopia/Response/Model/Language.php +++ b/src/Appwrite/Utopia/Response/Model/Language.php @@ -27,8 +27,7 @@ class Language extends Model 'description' => 'Language native name.', 'default' => '', 'example' => 'Italiano', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Locale.php b/src/Appwrite/Utopia/Response/Model/Locale.php index fdfa363acd..61f371e7ac 100644 --- a/src/Appwrite/Utopia/Response/Model/Locale.php +++ b/src/Appwrite/Utopia/Response/Model/Locale.php @@ -51,8 +51,7 @@ class Locale extends Model 'description' => 'Currency code in [ISO 4217-1](http://en.wikipedia.org/wiki/ISO_4217) three-character format', 'default' => '', 'example' => 'USD', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/LocaleCode.php b/src/Appwrite/Utopia/Response/Model/LocaleCode.php index e73ceff6a5..d629c9a1a5 100644 --- a/src/Appwrite/Utopia/Response/Model/LocaleCode.php +++ b/src/Appwrite/Utopia/Response/Model/LocaleCode.php @@ -21,8 +21,7 @@ class LocaleCode extends Model 'description' => 'Locale name', 'default' => '', 'example' => 'US', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Log.php b/src/Appwrite/Utopia/Response/Model/Log.php index bc2c923494..7177cad078 100644 --- a/src/Appwrite/Utopia/Response/Model/Log.php +++ b/src/Appwrite/Utopia/Response/Model/Log.php @@ -135,8 +135,7 @@ class Log extends Model 'description' => 'Country name.', 'default' => '', 'example' => 'United States', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Membership.php b/src/Appwrite/Utopia/Response/Model/Membership.php index c134142185..2364ca5ec8 100644 --- a/src/Appwrite/Utopia/Response/Model/Membership.php +++ b/src/Appwrite/Utopia/Response/Model/Membership.php @@ -82,8 +82,7 @@ class Membership extends Model 'default' => [], 'example' => ['owner'], 'array' => true, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Metric.php b/src/Appwrite/Utopia/Response/Model/Metric.php index 16cf7f7df2..6b52f97e21 100644 --- a/src/Appwrite/Utopia/Response/Model/Metric.php +++ b/src/Appwrite/Utopia/Response/Model/Metric.php @@ -20,7 +20,7 @@ class Metric extends Model 'type' => self::TYPE_DATETIME, 'description' => 'The date at which this metric was aggregated in ISO 8601 format.', 'default' => '', - 'example' => self::TYPE_DATETIME_EXAMPLE + 'example' => self::TYPE_DATETIME_EXAMPLE, ]); } diff --git a/src/Appwrite/Utopia/Response/Model/Migration.php b/src/Appwrite/Utopia/Response/Model/Migration.php index 78e8658032..33bccd23d2 100644 --- a/src/Appwrite/Utopia/Response/Model/Migration.php +++ b/src/Appwrite/Utopia/Response/Model/Migration.php @@ -51,7 +51,7 @@ class Migration extends Model 'description' => 'Resources to migration.', 'default' => [], 'example' => ['user'], - 'array' => true + 'array' => true, ]) ->addRule('statusCounters', [ 'type' => self::TYPE_JSON, @@ -70,8 +70,7 @@ class Migration extends Model 'description' => 'All errors that occurred during the migration process.', 'default' => [], 'example' => [], - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Mock.php b/src/Appwrite/Utopia/Response/Model/Mock.php index afdae66084..7332e589f1 100644 --- a/src/Appwrite/Utopia/Response/Model/Mock.php +++ b/src/Appwrite/Utopia/Response/Model/Mock.php @@ -15,8 +15,7 @@ class Mock extends Model 'description' => 'Result message.', 'default' => '', 'example' => 'Success', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Phone.php b/src/Appwrite/Utopia/Response/Model/Phone.php index 226955919b..d732d0dc2e 100644 --- a/src/Appwrite/Utopia/Response/Model/Phone.php +++ b/src/Appwrite/Utopia/Response/Model/Phone.php @@ -27,8 +27,7 @@ class Phone extends Model 'description' => 'Country name.', 'default' => '', 'example' => 'United States', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Platform.php b/src/Appwrite/Utopia/Response/Model/Platform.php index 4b8ffb1486..a25d819947 100644 --- a/src/Appwrite/Utopia/Response/Model/Platform.php +++ b/src/Appwrite/Utopia/Response/Model/Platform.php @@ -73,8 +73,7 @@ class Platform extends Model 'description' => 'HTTP basic authentication password.', 'default' => '', 'example' => 'password', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 35c3cf0e1f..511952b142 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -178,7 +178,7 @@ class Project extends Model 'description' => 'Status for custom SMTP', 'default' => false, 'example' => false, - 'array' => false + 'array' => false, ]) ->addRule('smtpSender', [ 'type' => self::TYPE_STRING, @@ -215,8 +215,7 @@ class Project extends Model 'description' => 'SMTP server secure protocol', 'default' => '', 'example' => 'tls', - ]) - ; + ]); $services = Config::getParam('services', []); $auth = Config::getParam('auth', []); @@ -226,17 +225,16 @@ class Project extends Model $key = $method['key'] ?? ''; $this - ->addRule('auth' . ucfirst($key), [ + ->addRule('auth'.ucfirst($key), [ 'type' => self::TYPE_BOOLEAN, - 'description' => $name . ' auth method status', + 'description' => $name.' auth method status', 'example' => true, 'default' => true, - ]) - ; + ]); } foreach ($services as $service) { - if (!$service['optional']) { + if (! $service['optional']) { continue; } @@ -244,13 +242,12 @@ class Project extends Model $key = $service['key'] ?? ''; $this - ->addRule('serviceStatusFor' . ucfirst($key), [ + ->addRule('serviceStatusFor'.ucfirst($key), [ 'type' => self::TYPE_BOOLEAN, - 'description' => $name . ' service status', + 'description' => $name.' service status', 'example' => true, 'default' => true, - ]) - ; + ]); } } @@ -296,12 +293,12 @@ class Project extends Model $services = Config::getParam('services', []); foreach ($services as $service) { - if (!$service['optional']) { + if (! $service['optional']) { continue; } $key = $service['key'] ?? ''; $value = $values[$key] ?? true; - $document->setAttribute('serviceStatusFor' . ucfirst($key), $value); + $document->setAttribute('serviceStatusFor'.ucfirst($key), $value); } // Auth @@ -318,7 +315,7 @@ class Project extends Model foreach ($auth as $index => $method) { $key = $method['key']; $value = $authValues[$key] ?? true; - $document->setAttribute('auth' . ucfirst($key), $value); + $document->setAttribute('auth'.ucfirst($key), $value); } // Providers @@ -327,7 +324,7 @@ class Project extends Model $projectProviders = []; foreach ($providers as $key => $provider) { - if (!$provider['enabled']) { + if (! $provider['enabled']) { // Disabled by Appwrite configuration, exclude from response continue; } @@ -335,13 +332,13 @@ class Project extends Model $projectProviders[] = new Document([ 'key' => $key, 'name' => $provider['name'] ?? '', - 'appId' => $providerValues[$key . 'Appid'] ?? '', - 'secret' => $providerValues[$key . 'Secret'] ?? '', - 'enabled' => $providerValues[$key . 'Enabled'] ?? false, + 'appId' => $providerValues[$key.'Appid'] ?? '', + 'secret' => $providerValues[$key.'Secret'] ?? '', + 'enabled' => $providerValues[$key.'Enabled'] ?? false, ]); } - $document->setAttribute("providers", $projectProviders); + $document->setAttribute('providers', $projectProviders); return $document; } diff --git a/src/Appwrite/Utopia/Response/Model/Runtime.php b/src/Appwrite/Utopia/Response/Model/Runtime.php index 8bc42cb418..43cf711994 100644 --- a/src/Appwrite/Utopia/Response/Model/Runtime.php +++ b/src/Appwrite/Utopia/Response/Model/Runtime.php @@ -20,7 +20,7 @@ class Runtime extends Model 'type' => self::TYPE_STRING, 'description' => 'Runtime Name.', 'default' => '', - 'example' => 'Python' + 'example' => 'Python', ]) ->addRule('version', [ 'type' => self::TYPE_STRING, @@ -52,8 +52,7 @@ class Runtime extends Model 'default' => '', 'example' => 'amd64', 'array' => true, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Session.php b/src/Appwrite/Utopia/Response/Model/Session.php index d961966b24..7b71780c4e 100644 --- a/src/Appwrite/Utopia/Response/Model/Session.php +++ b/src/Appwrite/Utopia/Response/Model/Session.php @@ -159,8 +159,7 @@ class Session extends Model 'description' => 'Returns true if this the current user session.', 'default' => false, 'example' => true, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Team.php b/src/Appwrite/Utopia/Response/Model/Team.php index d080a82bb1..e180afbbeb 100644 --- a/src/Appwrite/Utopia/Response/Model/Team.php +++ b/src/Appwrite/Utopia/Response/Model/Team.php @@ -46,8 +46,7 @@ class Team extends Model 'description' => 'Team preferences as a key-value object', 'default' => new \stdClass(), 'example' => ['theme' => 'pink', 'timezone' => 'UTC'], - ]) - ; + ]); } /** @@ -65,6 +64,7 @@ class Team extends Model if (is_array($prefs) && empty($prefs)) { $document->setAttribute('prefs', new \stdClass()); } + return $document; } diff --git a/src/Appwrite/Utopia/Response/Model/Template.php b/src/Appwrite/Utopia/Response/Model/Template.php index 3ce9cacdb3..9d4f81068a 100644 --- a/src/Appwrite/Utopia/Response/Model/Template.php +++ b/src/Appwrite/Utopia/Response/Model/Template.php @@ -26,7 +26,6 @@ abstract class Template extends Model 'description' => 'Template message', 'default' => '', 'example' => 'Click on the link to verify your account.', - ]) - ; + ]); } } diff --git a/src/Appwrite/Utopia/Response/Model/TemplateEmail.php b/src/Appwrite/Utopia/Response/Model/TemplateEmail.php index ecdf89e774..1babef9f90 100644 --- a/src/Appwrite/Utopia/Response/Model/TemplateEmail.php +++ b/src/Appwrite/Utopia/Response/Model/TemplateEmail.php @@ -33,8 +33,7 @@ class TemplateEmail extends Template 'description' => 'Email subject', 'default' => '', 'example' => 'Please verify your email address', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/TemplateSMS.php b/src/Appwrite/Utopia/Response/Model/TemplateSMS.php index 2b19ef4878..f0abcdc511 100644 --- a/src/Appwrite/Utopia/Response/Model/TemplateSMS.php +++ b/src/Appwrite/Utopia/Response/Model/TemplateSMS.php @@ -10,6 +10,7 @@ class TemplateSMS extends Template { parent::__construct(); } + /** * Get Name * diff --git a/src/Appwrite/Utopia/Response/Model/Token.php b/src/Appwrite/Utopia/Response/Model/Token.php index c409e37f03..05bbe10302 100644 --- a/src/Appwrite/Utopia/Response/Model/Token.php +++ b/src/Appwrite/Utopia/Response/Model/Token.php @@ -39,8 +39,7 @@ class Token extends Model 'description' => 'Token expiration date in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageBuckets.php b/src/Appwrite/Utopia/Response/Model/UsageBuckets.php index 83b8744760..1f708a0b4d 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageBuckets.php +++ b/src/Appwrite/Utopia/Response/Model/UsageBuckets.php @@ -21,16 +21,15 @@ class UsageBuckets extends Model 'description' => 'Aggregated stats for total number of files in this bucket.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('filesStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total storage of files in this bucket.', 'default' => [], 'example' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageCollection.php b/src/Appwrite/Utopia/Response/Model/UsageCollection.php index 5abcf46b7d..fd5350af86 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageCollection.php +++ b/src/Appwrite/Utopia/Response/Model/UsageCollection.php @@ -21,9 +21,8 @@ class UsageCollection extends Model 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageDatabase.php b/src/Appwrite/Utopia/Response/Model/UsageDatabase.php index 58d49c506e..fac50676a6 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageDatabase.php +++ b/src/Appwrite/Utopia/Response/Model/UsageDatabase.php @@ -21,16 +21,15 @@ class UsageDatabase extends Model 'description' => 'Aggregated stats for total number of collections.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('documentsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageDatabases.php b/src/Appwrite/Utopia/Response/Model/UsageDatabases.php index a6008ca9e6..20c2a1aecb 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageDatabases.php +++ b/src/Appwrite/Utopia/Response/Model/UsageDatabases.php @@ -21,23 +21,22 @@ class UsageDatabases extends Model 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('collectionsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of collections.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('documentsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageFunction.php b/src/Appwrite/Utopia/Response/Model/UsageFunction.php index 03acaa750a..013bf4056d 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageFunction.php +++ b/src/Appwrite/Utopia/Response/Model/UsageFunction.php @@ -21,42 +21,42 @@ class UsageFunction extends Model 'description' => 'Aggregated stats for number of function deployments.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('deploymentsStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function deployments storage.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('buildsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function builds.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('buildsStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for builds storage.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('buildsTime', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function build compute.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('executionsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function executions.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('executionsTime', [ @@ -64,9 +64,8 @@ class UsageFunction extends Model 'description' => 'Aggregated stats for function execution compute.', 'default' => [], 'example' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageFunctions.php b/src/Appwrite/Utopia/Response/Model/UsageFunctions.php index 6ab36e21ac..003f6390ad 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageFunctions.php +++ b/src/Appwrite/Utopia/Response/Model/UsageFunctions.php @@ -21,49 +21,49 @@ class UsageFunctions extends Model 'description' => 'Aggregated stats for number of functions.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('deploymentsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function deployments.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('deploymentsStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function deployments storage.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('buildsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function builds.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('buildsStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for builds storage.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('buildsTime', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function build compute.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('executionsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function executions.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('executionsTime', [ @@ -71,9 +71,8 @@ class UsageFunctions extends Model 'description' => 'Aggregated stats for function execution compute.', 'default' => [], 'example' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageProject.php b/src/Appwrite/Utopia/Response/Model/UsageProject.php index 641613809a..41acef102f 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageProject.php +++ b/src/Appwrite/Utopia/Response/Model/UsageProject.php @@ -21,58 +21,57 @@ class UsageProject extends Model 'description' => 'Aggregated stats for number of requests.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('network', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for consumed bandwidth.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('executionsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function executions.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('documentsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of documents.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('databasesTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of databases.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('usersTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of users.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('filesStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for the occupied storage size (in bytes).', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('bucketsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of buckets.', 'default' => [], 'example' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageStorage.php b/src/Appwrite/Utopia/Response/Model/UsageStorage.php index 88d0beca01..4d83948fb8 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageStorage.php +++ b/src/Appwrite/Utopia/Response/Model/UsageStorage.php @@ -21,23 +21,22 @@ class UsageStorage extends Model 'description' => 'Aggregated stats for total number of buckets.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('filesTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of files.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('filesStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for the occupied storage size (in bytes).', 'default' => [], 'example' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageUsers.php b/src/Appwrite/Utopia/Response/Model/UsageUsers.php index c0cc4baa54..71774bf61d 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageUsers.php +++ b/src/Appwrite/Utopia/Response/Model/UsageUsers.php @@ -21,7 +21,7 @@ class UsageUsers extends Model 'description' => 'Aggregated stats for total number of users.', 'default' => [], 'example' => [], - 'array' => true + 'array' => true, ]) ->addRule('sessionsTotal', [ @@ -29,9 +29,8 @@ class UsageUsers extends Model 'description' => 'Aggregated stats for sessions created.', 'default' => [], 'example' => [], - 'array' => true - ]) - ; + 'array' => true, + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/User.php b/src/Appwrite/Utopia/Response/Model/User.php index d6988b47f4..a69c30f9d1 100644 --- a/src/Appwrite/Utopia/Response/Model/User.php +++ b/src/Appwrite/Utopia/Response/Model/User.php @@ -129,11 +129,10 @@ class User extends Model ]) ->addRule('accessedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_USER_ACCCESS / 60 / 60 . ' hours.', + 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after '.APP_USER_ACCCESS / 60 / 60 .' hours.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, - ]) - ; + ]); } /** @@ -151,6 +150,7 @@ class User extends Model if (is_array($prefs) && empty($prefs)) { $document->setAttribute('prefs', new \stdClass()); } + return $document; } diff --git a/src/Appwrite/Utopia/Response/Model/Variable.php b/src/Appwrite/Utopia/Response/Model/Variable.php index f4b3bcf2bb..7d84e8803f 100644 --- a/src/Appwrite/Utopia/Response/Model/Variable.php +++ b/src/Appwrite/Utopia/Response/Model/Variable.php @@ -46,8 +46,7 @@ class Variable extends Model 'description' => 'Function ID.', 'default' => '', 'example' => '5e5ea5c16897e', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Webhook.php b/src/Appwrite/Utopia/Response/Model/Webhook.php index 781bb9186d..d9e0f4be3c 100644 --- a/src/Appwrite/Utopia/Response/Model/Webhook.php +++ b/src/Appwrite/Utopia/Response/Model/Webhook.php @@ -75,8 +75,7 @@ class Webhook extends Model 'description' => 'Signature key which can be used to validated incoming', 'default' => '', 'example' => 'ad3d581ca230e2b7059c545e5a', - ]) - ; + ]); } /** diff --git a/src/Appwrite/Utopia/View.php b/src/Appwrite/Utopia/View.php index e4ed8164c9..ba0a1f0fc6 100644 --- a/src/Appwrite/Utopia/View.php +++ b/src/Appwrite/Utopia/View.php @@ -11,8 +11,9 @@ class View extends OldView * * Convert all applicable characters to HTML entities * - * @param string $str + * @param string $str * @return string + * * @deprecated Use print method with escape filter */ public function escape($str) diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index bd49e5cf20..4e158eb362 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -8,13 +8,21 @@ use Utopia\App; class Executor { public const METHOD_GET = 'GET'; + public const METHOD_POST = 'POST'; + public const METHOD_PUT = 'PUT'; + public const METHOD_PATCH = 'PATCH'; + public const METHOD_DELETE = 'DELETE'; + public const METHOD_HEAD = 'HEAD'; + public const METHOD_OPTIONS = 'OPTIONS'; + public const METHOD_CONNECT = 'CONNECT'; + public const METHOD_TRACE = 'TRACE'; private bool $selfSigned = false; @@ -29,7 +37,7 @@ class Executor public function __construct(string $endpoint) { - if (!filter_var($endpoint, FILTER_VALIDATE_URL)) { + if (! filter_var($endpoint, FILTER_VALIDATE_URL)) { throw new Exception('Unsupported endpoint'); } @@ -38,7 +46,7 @@ class Executor $this->memory = intval(App::getEnv('_APP_FUNCTIONS_MEMORY', '512')); $this->headers = [ 'content-type' => 'application/json', - 'authorization' => 'Bearer ' . App::getEnv('_APP_EXECUTOR_SECRET', ''), + 'authorization' => 'Bearer '.App::getEnv('_APP_EXECUTOR_SECRET', ''), ]; } @@ -47,16 +55,16 @@ class Executor * * Launches a runtime container for a deployment ready for execution * - * @param string $deploymentId - * @param string $projectId - * @param string $source - * @param string $image - * @param bool $remove - * @param string $entrypoint - * @param string $workdir - * @param string $destination - * @param array $variables - * @param array $commands + * @param string $deploymentId + * @param string $projectId + * @param string $source + * @param string $image + * @param bool $remove + * @param string $entrypoint + * @param string $workdir + * @param string $destination + * @param array $variables + * @param array $commands */ public function createRuntime( string $deploymentId, @@ -71,8 +79,8 @@ class Executor array $commands = [] ) { $runtimeId = "$projectId-$deploymentId"; - $route = "/runtimes"; - $headers = [ 'x-opr-runtime-id' => $runtimeId ]; + $route = '/runtimes'; + $headers = ['x-opr-runtime-id' => $runtimeId]; $params = [ 'runtimeId' => $runtimeId, 'source' => $source, @@ -87,7 +95,7 @@ class Executor 'memory' => $this->memory, ]; - $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); + $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $timeout); @@ -103,15 +111,14 @@ class Executor /** * Create an execution * - * @param string $projectId - * @param string $deploymentId - * @param string $payload - * @param array $variables - * @param int $timeout - * @param string $image - * @param string $source - * @param string $entrypoint - * + * @param string $projectId + * @param string $deploymentId + * @param string $payload + * @param array $variables + * @param int $timeout + * @param string $image + * @param string $source + * @param string $entrypoint * @return array */ public function createExecution( @@ -125,8 +132,8 @@ class Executor string $entrypoint, ) { $runtimeId = "$projectId-$deploymentId"; - $route = '/runtimes/' . $runtimeId . '/execution'; - $headers = [ 'x-opr-runtime-id' => $runtimeId ]; + $route = '/runtimes/'.$runtimeId.'/execution'; + $headers = ['x-opr-runtime-id' => $runtimeId]; $params = [ 'runtimeId' => $runtimeId, 'variables' => $variables, @@ -140,7 +147,7 @@ class Executor 'memory' => $this->memory, ]; - $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); + $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $timeout); @@ -158,22 +165,23 @@ class Executor * * Make an API call * - * @param string $method - * @param string $path - * @param array $params - * @param array $headers - * @param bool $decode + * @param string $method + * @param string $path + * @param array $params + * @param array $headers + * @param bool $decode * @return array|string + * * @throws Exception */ public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true, int $timeout = 15) { - $headers = array_merge($this->headers, $headers); - $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); - $responseHeaders = []; - $responseStatus = -1; - $responseType = ''; - $responseBody = ''; + $headers = array_merge($this->headers, $headers); + $ch = curl_init($this->endpoint.$path.(($method == self::METHOD_GET && ! empty($params)) ? '?'.http_build_query($params) : '')); + $responseHeaders = []; + $responseStatus = -1; + $responseType = ''; + $responseBody = ''; switch ($headers['content-type']) { case 'application/json': @@ -190,7 +198,7 @@ class Executor } foreach ($headers as $i => $header) { - $headers[] = $i . ':' . $header; + $headers[] = $i.':'.$header; unset($headers[$i]); } @@ -223,8 +231,8 @@ class Executor curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - $responseBody = curl_exec($ch); - $responseType = $responseHeaders['content-type'] ?? ''; + $responseBody = curl_exec($ch); + $responseType = $responseHeaders['content-type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($decode) { @@ -233,7 +241,7 @@ class Executor $json = json_decode($responseBody, true); if ($json === null) { - throw new Exception('Failed to parse response: ' . $responseBody); + throw new Exception('Failed to parse response: '.$responseBody); } $responseBody = $json; @@ -243,7 +251,7 @@ class Executor } if ((curl_errno($ch)/* || 200 != $responseStatus*/)) { - throw new Exception(curl_error($ch) . ' with status code ' . $responseStatus, $responseStatus); + throw new Exception(curl_error($ch).' with status code '.$responseStatus, $responseStatus); } curl_close($ch); @@ -252,21 +260,21 @@ class Executor return [ 'headers' => $responseHeaders, - 'body' => $responseBody + 'body' => $responseBody, ]; } /** * Parse Cookie String * - * @param string $cookie + * @param string $cookie * @return array */ public function parseCookie(string $cookie): array { $cookies = []; - parse_str(strtr($cookie, array('&' => '%26', '+' => '%2B', ';' => '&')), $cookies); + parse_str(strtr($cookie, ['&' => '%26', '+' => '%2B', ';' => '&']), $cookies); return $cookies; } @@ -274,8 +282,8 @@ class Executor /** * Flatten params array to PHP multiple format * - * @param array $data - * @param string $prefix + * @param array $data + * @param string $prefix * @return array */ protected function flatten(array $data, string $prefix = ''): array diff --git a/tests/e2e/Client.php b/tests/e2e/Client.php index 21e4ccc958..6a9176232b 100644 --- a/tests/e2e/Client.php +++ b/tests/e2e/Client.php @@ -7,13 +7,21 @@ use Exception; class Client { public const METHOD_GET = 'GET'; + public const METHOD_POST = 'POST'; + public const METHOD_PUT = 'PUT'; + public const METHOD_PATCH = 'PATCH'; + public const METHOD_DELETE = 'DELETE'; + public const METHOD_HEAD = 'HEAD'; + public const METHOD_OPTIONS = 'OPTIONS'; + public const METHOD_CONNECT = 'CONNECT'; + public const METHOD_TRACE = 'TRACE'; /** @@ -52,8 +60,7 @@ class Client * * Your Appwrite project ID. You can find your project ID in your Appwrite console project settings. * - * @param string $value - * + * @param string $value * @return self $this */ public function setProject(string $value): self @@ -68,8 +75,7 @@ class Client * * Your Appwrite project secret key. You can can create a new API key from your Appwrite console API keys dashboard. * - * @param string $value - * + * @param string $value * @return self $this */ public function setKey(string $value): self @@ -82,8 +88,7 @@ class Client /** * Set Locale * - * @param string $value - * + * @param string $value * @return self $this */ public function setLocale(string $value): self @@ -96,8 +101,7 @@ class Client /** * Set Mode * - * @param string $value - * + * @param string $value * @return self $this */ public function setMode(string $value): self @@ -108,7 +112,7 @@ class Client } /** - * @param bool $status true + * @param bool $status true * @return self $this */ public function setSelfSigned(bool $status = true): self @@ -119,7 +123,7 @@ class Client } /** - * @param string $endpoint + * @param string $endpoint * @return self $this */ public function setEndpoint(string $endpoint): self @@ -138,9 +142,8 @@ class Client } /** - * @param string $key - * @param string $value - * + * @param string $key + * @param string $value * @return self $this */ public function addHeader(string $key, string $value): self @@ -155,19 +158,20 @@ class Client * * Make an API call * - * @param string $method - * @param string $path - * @param array $params - * @param array $headers - * @param bool $decode + * @param string $method + * @param string $path + * @param array $params + * @param array $headers + * @param bool $decode * @return array + * * @throws Exception */ public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true): array { - $headers = array_merge($this->headers, $headers); - $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); - $responseHeaders = []; + $headers = array_merge($this->headers, $headers); + $ch = curl_init($this->endpoint.$path.(($method == self::METHOD_GET && ! empty($params)) ? '?'.http_build_query($params) : '')); + $responseHeaders = []; $query = match ($headers['content-type']) { 'application/json' => json_encode($params), @@ -177,7 +181,7 @@ class Client }; foreach ($headers as $i => $header) { - $headers[] = $i . ':' . $header; + $headers[] = $i.':'.$header; unset($headers[$i]); } @@ -212,15 +216,15 @@ class Client curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - $responseBody = curl_exec($ch); - $responseType = $responseHeaders['content-type'] ?? ''; + $responseBody = curl_exec($ch); + $responseType = $responseHeaders['content-type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($decode && substr($responseType, 0, strpos($responseType, ';')) == 'application/json') { $json = json_decode($responseBody, true); if ($json === null) { - throw new Exception('Failed to parse response: ' . $responseBody); + throw new Exception('Failed to parse response: '.$responseBody); } $responseBody = $json; @@ -228,7 +232,7 @@ class Client } if ((curl_errno($ch))) { - throw new Exception(curl_error($ch) . ' with status code ' . $responseStatus, $responseStatus); + throw new Exception(curl_error($ch).' with status code '.$responseStatus, $responseStatus); } curl_close($ch); @@ -236,19 +240,19 @@ class Client $responseHeaders['status-code'] = $responseStatus; if ($responseStatus === 500) { - echo 'Server error(' . $method . ': ' . $path . '. Params: ' . json_encode($params) . '): ' . json_encode($responseBody) . "\n"; + echo 'Server error('.$method.': '.$path.'. Params: '.json_encode($params).'): '.json_encode($responseBody)."\n"; } return [ 'headers' => $responseHeaders, - 'body' => $responseBody + 'body' => $responseBody, ]; } /** * Parse Cookie String * - * @param string $cookie + * @param string $cookie * @return array */ public function parseCookie(string $cookie): array @@ -263,8 +267,8 @@ class Client /** * Flatten params array to PHP multiple format * - * @param array $data - * @param string $prefix + * @param array $data + * @param string $prefix * @return array */ protected function flatten(array $data, string $prefix = ''): array diff --git a/tests/e2e/General/AbuseTest.php b/tests/e2e/General/AbuseTest.php index f5a2829974..ded164af21 100644 --- a/tests/e2e/General/AbuseTest.php +++ b/tests/e2e/General/AbuseTest.php @@ -34,13 +34,13 @@ class AbuseTest extends Scope $max = 120; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'documentId' => ID::unique(), 'data' => [ - 'title' => 'The Hulk ' . $i, + 'title' => 'The Hulk '.$i, ], ]); @@ -59,7 +59,7 @@ class AbuseTest extends Scope $collectionId = $data['collectionId']; $max = 120; - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -73,12 +73,12 @@ class AbuseTest extends Scope $documentId = $document['body']['$id']; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, [ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$documentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'data' => [ - 'title' => 'The Hulk ' . $i, + 'title' => 'The Hulk '.$i, ], ]); @@ -98,7 +98,7 @@ class AbuseTest extends Scope $max = 60; for ($i = 0; $i <= $max + 1; $i++) { - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -111,7 +111,7 @@ class AbuseTest extends Scope $documentId = $document['body']['$id']; - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, [ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$documentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -131,12 +131,12 @@ class AbuseTest extends Scope $max = 60; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../resources/logo.png'), 'image/png', 'permissions.png'), ]); if ($i < $max) { @@ -153,23 +153,23 @@ class AbuseTest extends Scope $bucketId = $data['bucketId']; $max = 60; - $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $response['body']['$id']; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $response = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'name' => 'permissions' . $i . '.png', + 'name' => 'permissions'.$i.'.png', ]); if ($i < $max) { @@ -187,18 +187,18 @@ class AbuseTest extends Scope $max = 60; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $response['body']['$id']; - $response = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $response = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -216,7 +216,7 @@ class AbuseTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'AbuseDatabase', @@ -227,10 +227,10 @@ class AbuseTest extends Scope $databaseId = $database['body']['$id']; - $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', [ + $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -244,10 +244,10 @@ class AbuseTest extends Scope $collectionId = $movies['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', [ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'key' => 'title', 'size' => 256, diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php index 087b984f9d..e3533e31d6 100644 --- a/tests/e2e/General/HTTPTest.php +++ b/tests/e2e/General/HTTPTest.php @@ -68,7 +68,7 @@ class HTTPTest extends Scope { // Preparation $previousEndpoint = $this->client->getEndpoint(); - $this->client->setEndpoint("http://localhost"); + $this->client->setEndpoint('http://localhost'); /** * Test for SUCCESS @@ -96,7 +96,7 @@ class HTTPTest extends Scope public function testSpecs() { - $directory = __DIR__ . '/../../../app/config/specs/'; + $directory = __DIR__.'/../../../app/config/specs/'; $files = scandir($directory); $client = new Client(); @@ -120,7 +120,7 @@ class HTTPTest extends Scope break; } } - if (!$allowed) { + if (! $allowed) { continue; } @@ -129,7 +129,7 @@ class HTTPTest extends Scope */ $response = $client->call(Client::METHOD_POST, '/validator/debug', [ 'content-type' => 'application/json', - ], json_decode(file_get_contents($directory . $file), true)); + ], json_decode(file_get_contents($directory.$file), true)); $response['body'] = json_decode($response['body'], true); $this->assertEquals(200, $response['headers']['status-code']); diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index c8c4f21165..d9a662b6ac 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -2,13 +2,12 @@ namespace Tests\E2E\General; +use CURLFile; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use CURLFile; use Tests\E2E\Services\Functions\FunctionsBase; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -20,6 +19,7 @@ class UsageTest extends Scope use FunctionsBase; private const WAIT = 35; + private const CREATE = 20; protected string $projectId; @@ -46,21 +46,21 @@ class UsageTest extends Scope $headers['x-appwrite-key'] = $project['apiKey']; $headers['content-type'] = 'application/json'; - $usersTotal = 0; + $usersTotal = 0; $requestsTotal = 0; for ($i = 0; $i < self::CREATE; $i++) { - $email = uniqid() . 'user@usage.test'; + $email = uniqid().'user@usage.test'; $password = 'password'; - $name = uniqid() . 'User'; + $name = uniqid().'User'; $res = $this->client->call( Client::METHOD_POST, '/users', $headers, [ - 'userId' => 'unique()', - 'email' => $email, + 'userId' => 'unique()', + 'email' => $email, 'password' => $password, - 'name' => $name, + 'name' => $name, ] ); @@ -71,7 +71,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $userId = $res['body']['$id']; - $res = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, $headers); + $res = $this->client->call(Client::METHOD_DELETE, '/users/'.$userId, $headers); $this->assertEmpty($res['body']); $requestsTotal++; $usersTotal--; @@ -79,10 +79,10 @@ class UsageTest extends Scope } return [ - 'projectId' => $projectId, - 'headers' => $headers, - 'usersTotal' => $usersTotal, - 'requestsTotal' => $requestsTotal + 'projectId' => $projectId, + 'headers' => $headers, + 'usersTotal' => $usersTotal, + 'requestsTotal' => $requestsTotal, ]; } @@ -93,15 +93,15 @@ class UsageTest extends Scope { sleep(self::WAIT); - $projectId = $data['projectId']; - $headers = $data['headers']; - $usersTotal = $data['usersTotal']; + $projectId = $data['projectId']; + $headers = $data['headers']; + $usersTotal = $data['usersTotal']; $requestsTotal = $data['requestsTotal']; $consoleHeaders = [ 'origin' => 'http://localhost', 'x-appwrite-project' => 'console', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], 'x-appwrite-project' => $projectId, 'x-appwrite-mode' => 'admin', ]; @@ -151,9 +151,8 @@ class UsageTest extends Scope $storageTotal = 0; $filesTotal = 0; - for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid() . ' bucket'; + $name = uniqid().' bucket'; $res = $this->client->call( Client::METHOD_POST, '/storage/buckets', @@ -179,7 +178,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/storage/buckets/' . $bucketId, + '/storage/buckets/'.$bucketId, $headers ); $this->assertEmpty($res['body']); @@ -191,19 +190,19 @@ class UsageTest extends Scope // upload some files $files = [ [ - 'path' => realpath(__DIR__ . '/../../resources/logo.png'), + 'path' => realpath(__DIR__.'/../../resources/logo.png'), 'name' => 'logo.png', ], [ - 'path' => realpath(__DIR__ . '/../../resources/file.png'), + 'path' => realpath(__DIR__.'/../../resources/file.png'), 'name' => 'file.png', ], [ - 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-3.gif'), + 'path' => realpath(__DIR__.'/../../resources/disk-a/kitten-3.gif'), 'name' => 'kitten-3.gif', ], [ - 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'), + 'path' => realpath(__DIR__.'/../../resources/disk-a/kitten-1.jpg'), 'name' => 'kitten-1.jpg', ], ]; @@ -213,7 +212,7 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_POST, - '/storage/buckets/' . $bucketId . '/files', + '/storage/buckets/'.$bucketId.'/files', array_merge($headers, ['content-type' => 'multipart/form-data']), [ 'fileId' => 'unique()', @@ -232,13 +231,13 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/storage/buckets/' . $bucketId . '/files/' . $fileId, + '/storage/buckets/'.$bucketId.'/files/'.$fileId, $headers ); $this->assertEmpty($res['body']); $requestsTotal++; $filesTotal--; - $storageTotal -= $fileSize; + $storageTotal -= $fileSize; } } @@ -256,11 +255,11 @@ class UsageTest extends Scope */ public function testStorageStats(array $data): array { - $bucketId = $data['bucketId']; - $bucketsTotal = $data['bucketsTotal']; + $bucketId = $data['bucketId']; + $bucketsTotal = $data['bucketsTotal']; $requestsTotal = $data['requestsTotal']; - $storageTotal = $data['storageTotal']; - $filesTotal = $data['filesTotal']; + $storageTotal = $data['storageTotal']; + $filesTotal = $data['filesTotal']; sleep(self::WAIT); @@ -301,7 +300,7 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_GET, - '/storage/' . $bucketId . '/usage?range=30d', + '/storage/'.$bucketId.'/usage?range=30d', array_merge( $data['headers'], $data['consoleHeaders'] @@ -328,7 +327,7 @@ class UsageTest extends Scope $documentsTotal = 0; for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid() . ' database'; + $name = uniqid().' database'; $res = $this->client->call( Client::METHOD_POST, '/databases', @@ -339,7 +338,6 @@ class UsageTest extends Scope ] ); - $this->assertEquals($name, $res['body']['name']); $this->assertNotEmpty($res['body']['$id']); $databaseId = $res['body']['$id']; @@ -350,7 +348,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/databases/' . $databaseId, + '/databases/'.$databaseId, $headers ); $this->assertEmpty($res['body']); @@ -361,10 +359,10 @@ class UsageTest extends Scope } for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid() . ' collection'; + $name = uniqid().' collection'; $res = $this->client->call( Client::METHOD_POST, - '/databases/' . $databaseId . '/collections', + '/databases/'.$databaseId.'/collections', $headers, [ 'collectionId' => 'unique()', @@ -389,7 +387,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/databases/' . $databaseId . '/collections/' . $collectionId, + '/databases/'.$databaseId.'/collections/'.$collectionId, $headers ); $this->assertEmpty($res['body']); @@ -400,7 +398,7 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_POST, - '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes' . '/string', + '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes'.'/string', $headers, [ 'key' => 'name', @@ -415,14 +413,14 @@ class UsageTest extends Scope sleep(self::WAIT); for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid() . ' collection'; + $name = uniqid().' collection'; $res = $this->client->call( Client::METHOD_POST, - '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', + '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', $headers, [ 'documentId' => 'unique()', - 'data' => ['name' => $name] + 'data' => ['name' => $name], ] ); $this->assertEquals($name, $res['body']['name']); @@ -435,7 +433,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, + '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$documentId, $headers ); $this->assertEmpty($res['body']); @@ -455,10 +453,8 @@ class UsageTest extends Scope } /** @depends testPrepareDatabaseStats */ - public function testDatabaseStats(array $data): array { - $projectId = $data['projectId']; $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; @@ -502,7 +498,7 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_GET, - '/databases/' . $databaseId . '/usage?range=30d', + '/databases/'.$databaseId.'/usage?range=30d', $data['consoleHeaders'] ); $res = $res['body']; @@ -513,7 +509,7 @@ class UsageTest extends Scope $this->assertEquals($documentsTotal, $res['documentsTotal'][array_key_last($res['documentsTotal'])]['value']); $this->validateDates($res['documentsTotal']); - $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', $data['consoleHeaders']); + $res = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/usage?range=30d', $data['consoleHeaders']); $res = $res['body']; $this->assertEquals($documentsTotal, $res['documentsTotal'][array_key_last($res['documentsTotal'])]['value']); @@ -524,7 +520,6 @@ class UsageTest extends Scope return $data; } - /** @depends testDatabaseStats */ public function testPrepareFunctionsStats(array $data): array { @@ -561,17 +556,17 @@ class UsageTest extends Scope $this->assertEquals(201, $response1['headers']['status-code']); $this->assertNotEmpty($response1['body']['$id']); - $code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz"; + $code = realpath(__DIR__.'/../../resources/functions').'/php/code.tar.gz'; $this->packageCode('php'); $deployment = $this->client->call( Client::METHOD_POST, - '/functions/' . $functionId . '/deployments', - array_merge($headers, ['content-type' => 'multipart/form-data',]), + '/functions/'.$functionId.'/deployments', + array_merge($headers, ['content-type' => 'multipart/form-data']), [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), - 'activate' => true + 'activate' => true, ] ); @@ -587,7 +582,7 @@ class UsageTest extends Scope $response = $this->client->call( Client::METHOD_PATCH, - '/functions/' . $functionId . '/deployments/' . $deploymentId, + '/functions/'.$functionId.'/deployments/'.$deploymentId, $headers ); @@ -600,7 +595,7 @@ class UsageTest extends Scope $execution = $this->client->call( Client::METHOD_POST, - '/functions/' . $functionId . '/executions', + '/functions/'.$functionId.'/executions', $headers, [ 'async' => false, @@ -621,7 +616,7 @@ class UsageTest extends Scope $execution = $this->client->call( Client::METHOD_POST, - '/functions/' . $functionId . '/executions', + '/functions/'.$functionId.'/executions', $headers, [ 'async' => false, @@ -640,7 +635,7 @@ class UsageTest extends Scope $execution = $this->client->call( Client::METHOD_POST, - '/functions/' . $functionId . '/executions', + '/functions/'.$functionId.'/executions', $headers, [ 'async' => true, @@ -655,7 +650,7 @@ class UsageTest extends Scope $execution = $this->client->call( Client::METHOD_GET, - '/functions/' . $functionId . '/executions/' . $execution['body']['$id'], + '/functions/'.$functionId.'/executions/'.$execution['body']['$id'], $headers ); @@ -686,7 +681,7 @@ class UsageTest extends Scope $response = $this->client->call( Client::METHOD_GET, - '/functions/' . $functionId . '/usage?range=30d', + '/functions/'.$functionId.'/usage?range=30d', $data['consoleHeaders'] ); diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index ee41129fde..7146ebc392 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -13,19 +13,19 @@ trait ProjectCustom protected static $project = []; /** - * @param bool $fresh + * @param bool $fresh * @return array */ public function getProject(bool $fresh = false): array { - if (!empty(self::$project) && !$fresh) { + if (! empty(self::$project) && ! $fresh) { return self::$project; } $team = $this->client->call(Client::METHOD_POST, '/teams', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'teamId' => ID::unique(), @@ -38,7 +38,7 @@ trait ProjectCustom $project = $this->client->call(Client::METHOD_POST, '/projects', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'projectId' => ID::unique(), @@ -52,10 +52,10 @@ trait ProjectCustom $this->assertEquals(201, $project['headers']['status-code']); $this->assertNotEmpty($project['body']); - $key = $this->client->call(Client::METHOD_POST, '/projects/' . $project['body']['$id'] . '/keys', [ + $key = $this->client->call(Client::METHOD_POST, '/projects/'.$project['body']['$id'].'/keys', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'name' => 'Demo Project Key', @@ -92,10 +92,10 @@ trait ProjectCustom $this->assertNotEmpty($key['body']); $this->assertNotEmpty($key['body']['secret']); - $webhook = $this->client->call(Client::METHOD_POST, '/projects/' . $project['body']['$id'] . '/webhooks', [ + $webhook = $this->client->call(Client::METHOD_POST, '/projects/'.$project['body']['$id'].'/webhooks', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'name' => 'Webhook Test', @@ -104,7 +104,7 @@ trait ProjectCustom // 'functions.*', TODO @christyjacob4 : enable test once we allow functions.* events 'buckets.*', 'teams.*', - 'users.*' + 'users.*', ], 'url' => 'http://request-catcher:5000/webhook', 'security' => false, @@ -130,13 +130,12 @@ trait ProjectCustom public function getNewKey(array $scopes) { - $projectId = self::$project['$id']; - $key = $this->client->call(Client::METHOD_POST, '/projects/' . $projectId . '/keys', [ + $key = $this->client->call(Client::METHOD_POST, '/projects/'.$projectId.'/keys', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'name' => 'Demo Project Key', diff --git a/tests/e2e/Scopes/Scope.php b/tests/e2e/Scopes/Scope.php index 14eb83897b..4eaf846c27 100644 --- a/tests/e2e/Scopes/Scope.php +++ b/tests/e2e/Scopes/Scope.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Scopes; use Appwrite\Tests\Retryable; -use Tests\E2E\Client; use PHPUnit\Framework\TestCase; +use Tests\E2E\Client; use Utopia\Database\Helpers\ID; abstract class Scope extends TestCase @@ -12,6 +12,7 @@ abstract class Scope extends TestCase use Retryable; protected ?Client $client = null; + protected string $endpoint = 'http://localhost/v1'; protected function setUp(): void @@ -72,7 +73,7 @@ abstract class Scope extends TestCase return self::$root; } - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -98,7 +99,7 @@ abstract class Scope extends TestCase 'password' => $password, ]); - $session = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_console']; + $session = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_console']; self::$root = [ '$id' => ID::custom($root['body']['$id']), @@ -124,7 +125,7 @@ abstract class Scope extends TestCase return self::$user[$this->getProject()['$id']]; } - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -150,7 +151,7 @@ abstract class Scope extends TestCase 'password' => $password, ]); - $token = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $token = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; self::$user[$this->getProject()['$id']] = [ '$id' => ID::custom($user['body']['$id']), diff --git a/tests/e2e/Scopes/SideClient.php b/tests/e2e/Scopes/SideClient.php index 54f77a9747..2348da8e6b 100644 --- a/tests/e2e/Scopes/SideClient.php +++ b/tests/e2e/Scopes/SideClient.php @@ -8,7 +8,7 @@ trait SideClient { return [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $this->getUser()['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$this->getUser()['session'], ]; } diff --git a/tests/e2e/Scopes/SideConsole.php b/tests/e2e/Scopes/SideConsole.php index 74a0dd0c60..f067977c14 100644 --- a/tests/e2e/Scopes/SideConsole.php +++ b/tests/e2e/Scopes/SideConsole.php @@ -8,8 +8,8 @@ trait SideConsole { return [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], - 'x-appwrite-mode' => 'admin' + 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'x-appwrite-mode' => 'admin', ]; } diff --git a/tests/e2e/Scopes/SideServer.php b/tests/e2e/Scopes/SideServer.php index b5e15150e9..f72ac1f2e2 100644 --- a/tests/e2e/Scopes/SideServer.php +++ b/tests/e2e/Scopes/SideServer.php @@ -12,7 +12,7 @@ trait SideServer public function getHeaders(): array { return [ - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]; } diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 291d55b221..84c32aede9 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -4,15 +4,15 @@ namespace Tests\E2E\Services\Account; use Appwrite\Tests\Retry; use Tests\E2E\Client; -use Utopia\Database\Helpers\ID; use Utopia\Database\DateTime; +use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; trait AccountBase { public function testCreateAccount(): array { - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -126,13 +126,13 @@ trait AccountBase $this->assertNotFalse(\DateTime::createFromFormat('Y-m-d\TH:i:s.uP', $response['body']['expire'])); $sessionId = $response['body']['$id']; - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; // apiKey is only available in custom client test $apiKey = $this->getProject()['apiKey']; - if (!empty($apiKey)) { + if (! empty($apiKey)) { $userId = $response['body']['userId']; - $response = $this->client->call(Client::METHOD_GET, '/users/' . $userId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/'.$userId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -163,7 +163,7 @@ trait AccountBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]), [ - 'email' => $email . 'x', + 'email' => $email.'x', 'password' => $password, ]); @@ -175,7 +175,7 @@ trait AccountBase 'x-appwrite-project' => $this->getProject()['$id'], ]), [ 'email' => $email, - 'password' => $password . 'x', + 'password' => $password.'x', ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -213,7 +213,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -237,7 +237,7 @@ trait AccountBase $response = $this->client->call(Client::METHOD_GET, '/account', [ 'content-type' => 'application/json', - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session . 'xx', + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session.'xx', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -260,7 +260,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -297,7 +297,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -357,7 +357,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -365,7 +365,7 @@ trait AccountBase $this->assertNotEmpty($response['body']['logs']); $this->assertCount(3, $response['body']['logs']); $this->assertIsNumeric($response['body']['total']); - $this->assertContains($response['body']['logs'][1]['event'], ["session.create"]); + $this->assertContains($response['body']['logs'][1]['event'], ['session.create']); $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['logs'][1]['time'])); @@ -387,7 +387,7 @@ trait AccountBase $this->assertEquals('--', $response['body']['logs'][1]['countryCode']); $this->assertEquals('Unknown', $response['body']['logs'][1]['countryName']); - $this->assertContains($response['body']['logs'][2]['event'], ["user.create"]); + $this->assertContains($response['body']['logs'][2]['event'], ['user.create']); $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['logs'][2]['time'])); @@ -413,9 +413,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'queries' => [ 'limit(1)' ], + 'queries' => ['limit(1)'], ]); $this->assertEquals($responseLimit['headers']['status-code'], 200); @@ -430,9 +430,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'queries' => [ 'offset(1)' ], + 'queries' => ['offset(1)'], ]); $this->assertEquals($responseOffset['headers']['status-code'], 200); @@ -447,9 +447,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'queries' => [ 'limit(1)', 'offset(1)' ], + 'queries' => ['limit(1)', 'offset(1)'], ]); $this->assertEquals($responseLimitOffset['headers']['status-code'], 200); @@ -491,9 +491,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'name' => $newName + 'name' => $newName, ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -519,7 +519,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -528,9 +528,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'name' => 'ocSRq1d3QphHivJyUmYY7WMnrxyjdk5YvVwcDqx2zS0coxESN8RmsQwLWw5Whnf0WbVohuFWTRAaoKgCOO0Y0M7LwgFnZmi8881Y72222222222222222222222222222' + 'name' => 'ocSRq1d3QphHivJyUmYY7WMnrxyjdk5YvVwcDqx2zS0coxESN8RmsQwLWw5Whnf0WbVohuFWTRAaoKgCOO0Y0M7LwgFnZmi8881Y72222222222222222222222222222', ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -557,7 +557,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'password' => 'new-password', 'oldPassword' => $password, @@ -595,7 +595,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -607,7 +607,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'password' => 'new-password', 'oldPassword' => $password, @@ -621,9 +621,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'password' => 'new-password' + 'password' => 'new-password', ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -637,7 +637,7 @@ trait AccountBase */ public function testUpdateAccountEmail($data): array { - $newEmail = uniqid() . 'new@localhost.test'; + $newEmail = uniqid().'new@localhost.test'; $session = $data['session'] ?? ''; /** @@ -647,7 +647,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'email' => $newEmail, 'password' => 'new-password', @@ -675,7 +675,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -691,9 +691,9 @@ trait AccountBase 'x-appwrite-project' => $this->getProject()['$id'], ]), [ 'userId' => ID::unique(), - 'email' => $data['email'], - 'password' => $data['password'], - 'name' => $data['name'], + 'email' => $data['email'], + 'password' => $data['password'], + 'name' => $data['name'], ]); $this->assertEquals($response['headers']['status-code'], 201); @@ -703,7 +703,6 @@ trait AccountBase $this->assertEquals($response['body']['email'], $data['email']); $this->assertEquals($response['body']['name'], $data['name']); - $data['email'] = $newEmail; return $data; @@ -714,7 +713,7 @@ trait AccountBase */ public function testUpdateAccountPrefs($data): array { - $newEmail = uniqid() . 'new@localhost.test'; + $newEmail = uniqid().'new@localhost.test'; $session = $data['session'] ?? ''; /** @@ -724,12 +723,12 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'prefs' => [ 'prefKey1' => 'prefValue1', 'prefKey2' => 'prefValue2', - ] + ], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -753,21 +752,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'prefs' => '{}' - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - - $response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), [ - 'prefs' => '[]' + 'prefs' => '{}', ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -776,9 +763,20 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'prefs' => '{"test": "value"}' + 'prefs' => '[]', + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + ]), [ + 'prefs' => '{"test": "value"}', ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -786,29 +784,29 @@ trait AccountBase /** * Prefs size exceeded */ - $prefsObject = ["longValue" => str_repeat("🍰", 100000)]; + $prefsObject = ['longValue' => str_repeat('🍰', 100000)]; $response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'prefs' => $prefsObject + 'prefs' => $prefsObject, ]); $this->assertEquals(400, $response['headers']['status-code']); // Now let's test the same thing, but with normal symbol instead of multi-byte cake emoji - $prefsObject = ["longValue" => str_repeat("-", 100000)]; + $prefsObject = ['longValue' => str_repeat('-', 100000)]; $response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'prefs' => $prefsObject + 'prefs' => $prefsObject, ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -832,7 +830,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'url' => 'http://localhost/verification', @@ -850,14 +848,14 @@ trait AccountBase $this->assertEquals('Account Verification', $lastEmail['subject']); $verification = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); - $expireTime = strpos($lastEmail['text'], 'expire=' . urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0); + $expireTime = strpos($lastEmail['text'], 'expire='.urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0); $this->assertNotFalse($expireTime); - $secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0); + $secretTest = strpos($lastEmail['text'], 'secret='.$response['body']['secret'], 0); $this->assertNotFalse($secretTest); - $userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0); + $userIDTest = strpos($lastEmail['text'], 'userId='.$response['body']['userId'], 0); $this->assertNotFalse($userIDTest); @@ -868,7 +866,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'url' => 'localhost/verification', ]); @@ -879,7 +877,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'url' => 'http://remotehost/verification', ]); @@ -907,7 +905,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'userId' => $id, 'secret' => $verification, @@ -922,7 +920,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'userId' => ID::custom('ewewe'), 'secret' => $verification, @@ -934,7 +932,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'userId' => $id, 'secret' => 'sdasdasdasd', @@ -967,7 +965,7 @@ trait AccountBase ]); $sessionNewId = $response['body']['$id']; - $sessionNew = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $sessionNew = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $this->assertEquals($response['headers']['status-code'], 201); @@ -975,16 +973,16 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, ]); $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionNewId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionNewId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, ])); $this->assertEquals($response['headers']['status-code'], 204); @@ -993,7 +991,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -1005,7 +1003,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -1033,14 +1031,14 @@ trait AccountBase 'password' => $password, ]); - $sessionNew = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $sessionNew = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $this->assertEquals($response['headers']['status-code'], 201); $response = $this->client->call(Client::METHOD_GET, '/account', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -1049,7 +1047,7 @@ trait AccountBase $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/current', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -1061,7 +1059,7 @@ trait AccountBase $response = $this->client->call(Client::METHOD_GET, '/account', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -1084,7 +1082,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 204); @@ -1115,7 +1113,7 @@ trait AccountBase 'password' => $password, ]); - $data['session'] = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $data['session'] = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; return $data; } @@ -1153,15 +1151,15 @@ trait AccountBase $recovery = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); - $expireTime = strpos($lastEmail['text'], 'expire=' . urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0); + $expireTime = strpos($lastEmail['text'], 'expire='.urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0); $this->assertNotFalse($expireTime); - $secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0); + $secretTest = strpos($lastEmail['text'], 'secret='.$response['body']['secret'], 0); $this->assertNotFalse($secretTest); - $userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0); + $userIDTest = strpos($lastEmail['text'], 'userId='.$response['body']['userId'], 0); $this->assertNotFalse($userIDTest); @@ -1268,7 +1266,7 @@ trait AccountBase ]), [ 'userId' => $id, 'secret' => $recovery, - 'password' => $newPassowrd . 'x', + 'password' => $newPassowrd.'x', 'passwordAgain' => $newPassowrd, ]); @@ -1279,7 +1277,7 @@ trait AccountBase public function testCreateMagicUrl(): array { - $email = \time() . 'user@appwrite.io'; + $email = \time().'user@appwrite.io'; /** * Test for SUCCESS @@ -1307,15 +1305,15 @@ trait AccountBase $token = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); - $expireTime = strpos($lastEmail['text'], 'expire=' . urlencode($response['body']['expire']), 0); + $expireTime = strpos($lastEmail['text'], 'expire='.urlencode($response['body']['expire']), 0); $this->assertNotFalse($expireTime); - $secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0); + $secretTest = strpos($lastEmail['text'], 'secret='.$response['body']['secret'], 0); $this->assertNotFalse($secretTest); - $userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0); + $userIDTest = strpos($lastEmail['text'], 'userId='.$response['body']['userId'], 0); $this->assertNotFalse($userIDTest); @@ -1391,13 +1389,13 @@ trait AccountBase $this->assertNotEmpty($response['body']['userId']); $sessionId = $response['body']['$id']; - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -1432,7 +1430,6 @@ trait AccountBase $this->assertEquals(401, $response['headers']['status-code']); - $data['sessionId'] = $sessionId; $data['session'] = $session; @@ -1454,9 +1451,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'password' => 'new-password' + 'password' => 'new-password', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -1492,7 +1489,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -1504,7 +1501,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'password' => 'new-password', 'oldPassword' => 'wrong-password', @@ -1518,9 +1515,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'password' => 'new-password' + 'password' => 'new-password', ]); $this->assertEquals($response['headers']['status-code'], 401); diff --git a/tests/e2e/Services/Account/AccountConsoleClientTest.php b/tests/e2e/Services/Account/AccountConsoleClientTest.php index b517d8c408..c1a248ac49 100644 --- a/tests/e2e/Services/Account/AccountConsoleClientTest.php +++ b/tests/e2e/Services/Account/AccountConsoleClientTest.php @@ -3,11 +3,11 @@ namespace Tests\E2E\Services\Account; use Appwrite\Extend\Exception; -use Tests\E2E\Scopes\Scope; +use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; -use Tests\E2E\Client; use Utopia\Database\Validator\Datetime as DatetimeValidator; class AccountConsoleClientTest extends Scope @@ -18,7 +18,7 @@ class AccountConsoleClientTest extends Scope public function testCreateAccountWithInvite(): void { - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -34,7 +34,7 @@ class AccountConsoleClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'code' => 'Invalid Code' + 'code' => 'Invalid Code', ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -66,7 +66,7 @@ class AccountConsoleClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'code' => 'code-zero' + 'code' => 'code-zero', ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -76,7 +76,7 @@ class AccountConsoleClientTest extends Scope $this->assertEquals($response['body']['email'], $email); $this->assertEquals($response['body']['name'], $name); - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $response = $this->client->call(Client::METHOD_POST, '/account/invite', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', @@ -86,7 +86,7 @@ class AccountConsoleClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'code' => 'code-one' + 'code' => 'code-one', ]); $this->assertEquals(201, $response['headers']['status-code']); diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index d225496a65..7ca0798a61 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -3,18 +3,16 @@ namespace Tests\E2E\Services\Account; use Appwrite\Extend\Exception; -use Appwrite\SMS\Adapter\Mock; use Appwrite\Tests\Retry; +use function sleep; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; -use function sleep; - class AccountCustomClientTest extends Scope { use AccountBase; @@ -23,7 +21,7 @@ class AccountCustomClientTest extends Scope public function testCreateAccountWithInvite(): void { - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -40,7 +38,7 @@ class AccountCustomClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'code' => 'Invalid Code' + 'code' => 'Invalid Code', ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -59,11 +57,11 @@ class AccountCustomClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => 'console', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), [ 'provider' => $provider, 'appId' => $appId, @@ -73,7 +71,7 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/'.$provider, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -88,11 +86,11 @@ class AccountCustomClientTest extends Scope /** * Test for Failure when disabled */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => 'console', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), [ 'provider' => $provider, 'appId' => $appId, @@ -102,7 +100,7 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/'.$provider, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -118,7 +116,7 @@ class AccountCustomClientTest extends Scope public function testBlockedAccount(): array { - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name (blocked)'; @@ -152,18 +150,18 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 201); $sessionId = $response['body']['$id']; - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $id . '/status', [ + $response = $this->client->call(Client::METHOD_PATCH, '/users/'.$id.'/status', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -177,7 +175,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 401); @@ -196,10 +194,9 @@ class AccountCustomClientTest extends Scope return []; } - public function testSelfBlockedAccount(): array { - $email = uniqid() . 'user55@localhost.test'; + $email = uniqid().'user55@localhost.test'; $password = 'password'; $name = 'User Name (self blocked)'; @@ -232,13 +229,13 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 201); - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -246,20 +243,20 @@ class AccountCustomClientTest extends Scope $response = $this->client->call(Client::METHOD_PATCH, '/account/status', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ], [ 'status' => false, ]); $this->assertEquals($response['headers']['status-code'], 200); - $this->assertStringContainsString('a_session_' . $this->getProject()['$id'] . '=deleted', $response['headers']['set-cookie']); + $this->assertStringContainsString('a_session_'.$this->getProject()['$id'].'=deleted', $response['headers']['set-cookie']); $this->assertEquals('[]', $response['headers']['x-fallback-cookies']); $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 401); @@ -280,7 +277,7 @@ class AccountCustomClientTest extends Scope public function testCreateJWT(): array { - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name (JWT)'; @@ -314,13 +311,13 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 201); $sessionId = $response['body']['$id']; - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -329,7 +326,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 201); @@ -357,11 +354,11 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 204); @@ -394,13 +391,13 @@ class AccountCustomClientTest extends Scope $this->assertNotEmpty($response['body']); $this->assertNotEmpty($response['body']['$id']); - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; \usleep(1000 * 30); // wait for 30ms to let the shutdown update accessedAt $apiKey = $this->getProject()['apiKey']; $userId = $response['body']['userId']; - $response = $this->client->call(Client::METHOD_GET, '/users/' . $userId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/'.$userId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -417,7 +414,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]); $this->assertEquals(401, $response['headers']['status-code']); @@ -437,7 +434,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'oldPassword' => '', ]); @@ -452,7 +449,7 @@ class AccountCustomClientTest extends Scope */ public function testUpdateAnonymousAccountEmail($session) { - $email = uniqid() . 'new@localhost.test'; + $email = uniqid().'new@localhost.test'; /** * Test for FAILURE @@ -461,7 +458,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'email' => $email, 'password' => '', @@ -475,7 +472,7 @@ class AccountCustomClientTest extends Scope public function testConvertAnonymousAccount() { $session = $this->testCreateAnonymousAccount(); - $email = uniqid() . 'new@localhost.test'; + $email = uniqid().'new@localhost.test'; $password = 'new-password'; /** @@ -488,14 +485,14 @@ class AccountCustomClientTest extends Scope ]), [ 'userId' => ID::unique(), 'email' => $email, - 'password' => $password + 'password' => $password, ]); $response = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'email' => $email, 'password' => $password, @@ -506,13 +503,13 @@ class AccountCustomClientTest extends Scope /** * Test for SUCCESS */ - $email = uniqid() . 'new@localhost.test'; + $email = uniqid().'new@localhost.test'; $response = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'email' => $email, 'password' => $password, @@ -540,12 +537,11 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'url' => 'http://localhost' + 'url' => 'http://localhost', ]); - $this->assertEquals($response['headers']['status-code'], 201); return []; @@ -565,18 +561,18 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); $userId = $response['body']['$id'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => 'console', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), [ 'provider' => $provider, 'appId' => $appId, @@ -586,17 +582,17 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/'.$provider, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'success' => 'http://localhost/v1/mock/tests/general/oauth2/success', 'failure' => 'http://localhost/v1/mock/tests/general/oauth2/failure', ]); - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('success', $response['body']['result']); @@ -605,7 +601,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -621,7 +617,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals(200, $response['headers']['status-code']); @@ -637,7 +633,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals(200, $response['headers']['status-code']); @@ -656,7 +652,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -664,11 +660,11 @@ class AccountCustomClientTest extends Scope $sessionID = $response['body']['$id']; - $response = $this->client->call(Client::METHOD_GET, '/account/sessions/' . $sessionID, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/account/sessions/'.$sessionID, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -678,7 +674,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 404); @@ -741,7 +737,7 @@ class AccountCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'search' => '"' . $email . '"', + 'search' => '"'.$email.'"', ]); @@ -766,7 +762,6 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['body']['users'][0]['email'], $email); } - public function testCreatePhone(): array { $number = '+123456789'; @@ -798,7 +793,7 @@ class AccountCustomClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]), [ - 'userId' => ID::unique() + 'userId' => ID::unique(), ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -874,13 +869,13 @@ class AccountCustomClientTest extends Scope $this->assertNotEmpty($response['body']['$id']); $this->assertNotEmpty($response['body']['userId']); - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -915,19 +910,19 @@ class AccountCustomClientTest extends Scope public function testConvertPhoneToPassword(array $data): array { $session = $data['session']; - $email = uniqid() . 'new@localhost.test'; + $email = uniqid().'new@localhost.test'; $password = 'new-password'; /** * Test for SUCCESS */ - $email = uniqid() . 'new@localhost.test'; + $email = uniqid().'new@localhost.test'; $response = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'email' => $email, 'password' => $password, @@ -969,10 +964,10 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'phone' => $newPhone, - 'password' => 'new-password' + 'password' => 'new-password', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -997,7 +992,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -1022,7 +1017,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); @@ -1036,7 +1031,7 @@ class AccountCustomClientTest extends Scope $smsRequest = $this->getLastRequest(); return \array_merge($data, [ - 'token' => $smsRequest['data']['message'] + 'token' => $smsRequest['data']['message'], ]); } @@ -1056,7 +1051,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'userId' => $id, 'secret' => $secret, @@ -1071,7 +1066,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'userId' => ID::custom('ewewe'), 'secret' => $secret, @@ -1083,7 +1078,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'userId' => $id, 'secret' => '999999', diff --git a/tests/e2e/Services/Account/AccountCustomServerTest.php b/tests/e2e/Services/Account/AccountCustomServerTest.php index 143277608d..6c6c2df654 100644 --- a/tests/e2e/Services/Account/AccountCustomServerTest.php +++ b/tests/e2e/Services/Account/AccountCustomServerTest.php @@ -15,7 +15,7 @@ class AccountCustomServerTest extends Scope public function testCreateAccount(): array { - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; diff --git a/tests/e2e/Services/Avatars/AvatarsBase.php b/tests/e2e/Services/Avatars/AvatarsBase.php index e2ddc1a863..a7518d38af 100644 --- a/tests/e2e/Services/Avatars/AvatarsBase.php +++ b/tests/e2e/Services/Avatars/AvatarsBase.php @@ -45,7 +45,6 @@ trait AvatarsBase /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/avatars/credit-cards/unknown', [ 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -108,7 +107,6 @@ trait AvatarsBase /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/avatars/browsers/unknown', [ 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -262,7 +260,7 @@ trait AvatarsBase $response = $this->client->call(Client::METHOD_GET, '/avatars/image', [ 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'url' => 'invalid://appwrite.io/images/apple.png' + 'url' => 'invalid://appwrite.io/images/apple.png', ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -349,7 +347,7 @@ trait AvatarsBase $this->assertEquals(400, $image->getImageWidth()); $this->assertEquals(400, $image->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/qr/qr-default.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/qr/qr-default.png')), strlen($response['body'])); $response = $this->client->call(Client::METHOD_GET, '/avatars/qr', [ 'x-appwrite-project' => $this->getProject()['$id'], @@ -367,7 +365,7 @@ trait AvatarsBase $this->assertEquals(200, $image->getImageWidth()); $this->assertEquals(200, $image->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/qr/qr-size-200.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/qr/qr-size-200.png')), strlen($response['body'])); $response = $this->client->call(Client::METHOD_GET, '/avatars/qr', [ 'x-appwrite-project' => $this->getProject()['$id'], @@ -386,7 +384,7 @@ trait AvatarsBase $this->assertEquals(200, $image->getImageWidth()); $this->assertEquals(200, $image->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/qr/qr-size-200-margin-10.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/qr/qr-size-200-margin-10.png')), strlen($response['body'])); $response = $this->client->call(Client::METHOD_GET, '/avatars/qr', [ 'x-appwrite-project' => $this->getProject()['$id'], @@ -402,7 +400,7 @@ trait AvatarsBase $this->assertEquals(200, $image->getImageWidth()); $this->assertEquals(200, $image->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/qr/qr-size-200-margin-10.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/qr/qr-size-200-margin-10.png')), strlen($response['body'])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('attachment; filename="qr.png"', $response['headers']['content-disposition']); @@ -448,7 +446,6 @@ trait AvatarsBase return []; } - public function testGetInitials() { /** @@ -529,11 +526,11 @@ trait AvatarsBase $image = new \Imagick(); $image->readImageBlob($response['body']); - $original = new \Imagick(__DIR__ . '/../../../resources/initials.png'); + $original = new \Imagick(__DIR__.'/../../../resources/initials.png'); $this->assertEquals($image->getImageWidth(), $original->getImageWidth()); $this->assertEquals($image->getImageHeight(), $original->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/initials.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/initials.png')), strlen($response['body'])); } } diff --git a/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php b/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php index a59d694114..bfd17ef1e9 100644 --- a/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php +++ b/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Avatars; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class AvatarsConsoleClientTest extends Scope diff --git a/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php b/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php index dc399971a0..edf09d5ba1 100644 --- a/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php +++ b/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Avatars; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class AvatarsCustomClientTest extends Scope diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index c2c1c70bd6..9bc081d2ab 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -5,12 +5,11 @@ namespace Tests\E2E\Services\Databases; use Appwrite\Extend\Exception; use Tests\E2E\Client; use Utopia\Database\Database; -use Utopia\Database\Document; use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Query; use Utopia\Database\Validator\Datetime as DatetimeValidator; trait DatabasesBase @@ -23,10 +22,10 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'databaseId' => ID::unique(), - 'name' => 'Test Database' + 'name' => 'Test Database', ]); $this->assertNotEmpty($database['body']['$id']); @@ -45,10 +44,10 @@ trait DatabasesBase /** * Test for SUCCESS */ - $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -61,10 +60,10 @@ trait DatabasesBase $this->assertEquals(201, $movies['headers']['status-code']); $this->assertEquals($movies['body']['name'], 'Movies'); - $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -93,10 +92,10 @@ trait DatabasesBase /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$data['moviesId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Movies', 'enabled' => false, @@ -107,7 +106,7 @@ trait DatabasesBase $this->assertFalse($response['body']['enabled']); if ($this->getSide() === 'client') { - $responseCreateDocument = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $responseCreateDocument = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -124,14 +123,14 @@ trait DatabasesBase $this->assertEquals(404, $responseCreateDocument['headers']['status-code']); - $responseListDocument = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $responseListDocument = $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())); $this->assertEquals(404, $responseListDocument['headers']['status-code']); - $responseGetDocument = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/someID', array_merge([ + $responseGetDocument = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/someID', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -139,10 +138,10 @@ trait DatabasesBase $this->assertEquals(404, $responseGetDocument['headers']['status-code']); } - $response = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$data['moviesId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Movies', 'enabled' => true, @@ -160,20 +159,20 @@ trait DatabasesBase { $databaseId = $data['databaseId']; - $title = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/string', array_merge([ + $title = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); - $description = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/string', array_merge([ + $description = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'description', 'size' => 512, @@ -181,10 +180,10 @@ trait DatabasesBase 'default' => '', ]); - $tagline = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/string', array_merge([ + $tagline = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'tagline', 'size' => 512, @@ -192,10 +191,10 @@ trait DatabasesBase 'default' => '', ]); - $releaseYear = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/integer', array_merge([ + $releaseYear = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'releaseYear', 'required' => true, @@ -203,20 +202,20 @@ trait DatabasesBase 'max' => 2200, ]); - $duration = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/integer', array_merge([ + $duration = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'duration', 'required' => false, 'min' => 60, ]); - $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/string', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'actors', 'size' => 256, @@ -224,25 +223,25 @@ trait DatabasesBase 'array' => true, ]); - $datetime = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/datetime', array_merge([ + $datetime = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'birthDay', 'required' => false, ]); - $relationship = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/relationship', array_merge([ + $relationship = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $data['actorsId'], 'type' => 'oneToMany', 'twoWay' => true, 'key' => 'starringActors', - 'twoWayKey' => 'movie' + 'twoWayKey' => 'movie', ]); $this->assertEquals(202, $title['headers']['status-code']); @@ -298,10 +297,10 @@ trait DatabasesBase // wait for database worker to create attributes sleep(2); - $movies = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'], array_merge([ + $movies = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertIsArray($movies['body']['attributes']); @@ -324,7 +323,7 @@ trait DatabasesBase public function testListAttributes(array $data): void { $databaseId = $data['databaseId']; - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -333,7 +332,7 @@ trait DatabasesBase ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(2, \count($response['body']['attributes'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -350,10 +349,10 @@ trait DatabasesBase public function testAttributeResponseModels(array $data): array { $databaseId = $data['databaseId']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Response Models', @@ -366,12 +365,12 @@ trait DatabasesBase $collectionId = $collection['body']['$id']; - $attributesPath = "/databases/" . $databaseId . "/collections/{$collectionId}/attributes"; + $attributesPath = '/databases/'.$databaseId."/collections/{$collectionId}/attributes"; - $string = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ + $string = $this->client->call(Client::METHOD_POST, $attributesPath.'/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'string', 'size' => 16, @@ -379,20 +378,20 @@ trait DatabasesBase 'default' => 'default', ]); - $email = $this->client->call(Client::METHOD_POST, $attributesPath . '/email', array_merge([ + $email = $this->client->call(Client::METHOD_POST, $attributesPath.'/email', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'email', 'required' => false, 'default' => 'default@example.com', ]); - $enum = $this->client->call(Client::METHOD_POST, $attributesPath . '/enum', array_merge([ + $enum = $this->client->call(Client::METHOD_POST, $attributesPath.'/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'enum', 'elements' => ['yes', 'no', 'maybe'], @@ -400,80 +399,80 @@ trait DatabasesBase 'default' => 'maybe', ]); - $ip = $this->client->call(Client::METHOD_POST, $attributesPath . '/ip', array_merge([ + $ip = $this->client->call(Client::METHOD_POST, $attributesPath.'/ip', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'ip', 'required' => false, 'default' => '192.0.2.0', ]); - $url = $this->client->call(Client::METHOD_POST, $attributesPath . '/url', array_merge([ + $url = $this->client->call(Client::METHOD_POST, $attributesPath.'/url', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'url', 'required' => false, 'default' => 'http://example.com', ]); - $integer = $this->client->call(Client::METHOD_POST, $attributesPath . '/integer', array_merge([ + $integer = $this->client->call(Client::METHOD_POST, $attributesPath.'/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'integer', 'required' => false, 'min' => 1, 'max' => 5, - 'default' => 3 + 'default' => 3, ]); - $float = $this->client->call(Client::METHOD_POST, $attributesPath . '/float', array_merge([ + $float = $this->client->call(Client::METHOD_POST, $attributesPath.'/float', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'float', 'required' => false, 'min' => 1.5, 'max' => 5.5, - 'default' => 3.5 + 'default' => 3.5, ]); - $boolean = $this->client->call(Client::METHOD_POST, $attributesPath . '/boolean', array_merge([ + $boolean = $this->client->call(Client::METHOD_POST, $attributesPath.'/boolean', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'boolean', 'required' => false, 'default' => true, ]); - $datetime = $this->client->call(Client::METHOD_POST, $attributesPath . '/datetime', array_merge([ + $datetime = $this->client->call(Client::METHOD_POST, $attributesPath.'/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'datetime', 'required' => false, 'default' => null, ]); - $relationship = $this->client->call(Client::METHOD_POST, $attributesPath . '/relationship', array_merge([ + $relationship = $this->client->call(Client::METHOD_POST, $attributesPath.'/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $data['actorsId'], 'type' => 'oneToMany', 'twoWay' => true, 'key' => 'relationship', - 'twoWayKey' => 'twoWayKey' + 'twoWayKey' => 'twoWayKey', ]); $this->assertEquals(202, $string['headers']['status-code']); @@ -563,64 +562,64 @@ trait DatabasesBase // Wait for database worker to create attributes sleep(5); - $stringResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $string['body']['key'], array_merge([ + $stringResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$string['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $emailResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $email['body']['key'], array_merge([ + $emailResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$email['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $enumResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $enum['body']['key'], array_merge([ + $enumResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$enum['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $ipResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $ip['body']['key'], array_merge([ + $ipResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$ip['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $urlResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $url['body']['key'], array_merge([ + $urlResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$url['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $integerResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $integer['body']['key'], array_merge([ + $integerResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$integer['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $floatResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $float['body']['key'], array_merge([ + $floatResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$float['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $booleanResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $boolean['body']['key'], array_merge([ + $booleanResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$boolean['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $datetimeResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $datetime['body']['key'], array_merge([ + $datetimeResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$datetime['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $relationshipResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $relationship['body']['key'], array_merge([ + $relationshipResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$relationship['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $stringResponse['headers']['status-code']); @@ -716,10 +715,10 @@ trait DatabasesBase $this->assertEquals($relationship['body']['twoWay'], $relationshipResponse['body']['twoWay']); $this->assertEquals($relationship['body']['twoWayKey'], $relationshipResponse['body']['twoWayKey']); - $attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes', array_merge([ + $attributes = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $attributes['headers']['status-code']); @@ -812,10 +811,10 @@ trait DatabasesBase $this->assertEquals($relationshipResponse['body']['twoWay'], $attributes[9]['twoWay']); $this->assertEquals($relationshipResponse['body']['twoWayKey'], $attributes[9]['twoWayKey']); - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -911,10 +910,10 @@ trait DatabasesBase /** * Test for FAILURE */ - $badEnum = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ + $badEnum = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'enum', 'elements' => ['yes', 'no', ''], @@ -935,10 +934,10 @@ trait DatabasesBase { $databaseId = $data['databaseId']; - $titleIndex = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $titleIndex = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'titleIndex', 'type' => 'fulltext', @@ -951,10 +950,10 @@ trait DatabasesBase $this->assertCount(1, $titleIndex['body']['attributes']); $this->assertEquals('title', $titleIndex['body']['attributes'][0]); - $releaseYearIndex = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $releaseYearIndex = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'releaseYear', 'type' => 'key', @@ -967,10 +966,10 @@ trait DatabasesBase $this->assertCount(1, $releaseYearIndex['body']['attributes']); $this->assertEquals('releaseYear', $releaseYearIndex['body']['attributes'][0]); - $releaseWithDate = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $releaseWithDate = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'releaseYearDated', 'type' => 'key', @@ -988,10 +987,10 @@ trait DatabasesBase // wait for database worker to create index sleep(2); - $movies = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'], array_merge([ + $movies = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), []); $this->assertIsArray($movies['body']['indexes']); @@ -1003,10 +1002,10 @@ trait DatabasesBase $this->assertEquals('available', $movies['body']['indexes'][1]['status']); $this->assertEquals('available', $movies['body']['indexes'][2]['status']); - $releaseWithDate = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $releaseWithDate = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'birthDay', 'type' => 'key', @@ -1020,10 +1019,10 @@ trait DatabasesBase $this->assertEquals('birthDay', $releaseWithDate['body']['attributes'][0]); // Test for failure - $fulltextReleaseYear = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $fulltextReleaseYear = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'releaseYearDated', 'type' => 'fulltext', @@ -1033,10 +1032,10 @@ trait DatabasesBase $this->assertEquals(400, $fulltextReleaseYear['headers']['status-code']); $this->assertEquals($fulltextReleaseYear['body']['message'], 'Attribute "releaseYear" cannot be part of a FULLTEXT index, must be of type string'); - $noAttributes = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $noAttributes = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'none', 'type' => 'key', @@ -1046,10 +1045,10 @@ trait DatabasesBase $this->assertEquals(400, $noAttributes['headers']['status-code']); $this->assertEquals($noAttributes['body']['message'], 'No attributes provided for index'); - $duplicates = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $duplicates = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'duplicate', 'type' => 'fulltext', @@ -1059,7 +1058,7 @@ trait DatabasesBase $this->assertEquals(400, $duplicates['headers']['status-code']); $this->assertEquals($duplicates['body']['message'], 'Duplicate attributes provided'); - $tooLong = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $tooLong = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -1081,7 +1080,7 @@ trait DatabasesBase public function testListIndexes(array $data): void { $databaseId = $data['databaseId']; - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -1090,7 +1089,7 @@ trait DatabasesBase ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(2, \count($response['body']['indexes'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -1107,7 +1106,7 @@ trait DatabasesBase public function testCreateDocument(array $data): array { $databaseId = $data['databaseId']; - $document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $document1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1119,16 +1118,16 @@ trait DatabasesBase 'actors' => [ 'Chris Evans', 'Samuel Jackson', - ] + ], ], 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); - $document2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $document2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1141,16 +1140,16 @@ trait DatabasesBase 'Tom Holland', 'Zendaya Maree Stoermer', 'Samuel Jackson', - ] + ], ], 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); - $document3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $document3 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1169,10 +1168,10 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); - $document4 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $document4 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1184,7 +1183,7 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); $this->assertEquals(201, $document1['headers']['status-code']); @@ -1232,7 +1231,7 @@ trait DatabasesBase $this->assertEquals(400, $document4['headers']['status-code']); // Delete document 4 with incomplete path - $this->assertEquals(404, $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/', array_merge([ + $this->assertEquals(404, $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()))['headers']['status-code']); @@ -1246,7 +1245,7 @@ trait DatabasesBase public function testListDocuments(array $data): array { $databaseId = $data['databaseId']; - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1268,7 +1267,7 @@ trait DatabasesBase $this->assertEquals($databaseId, $document['$databaseId']); } - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1290,10 +1289,10 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'databaseId' => ID::custom('default'), - 'name' => 'Default' + 'name' => 'Default', ]); $this->assertNotEmpty($database['body']['$id']); @@ -1302,11 +1301,10 @@ trait DatabasesBase /** * Test for SUCCESS */ - $movies = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -1328,8 +1326,7 @@ trait DatabasesBase /** * Test for SUCCESS */ - - $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ + $documents = $this->client->call(Client::METHOD_GET, '/database/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1347,7 +1344,7 @@ trait DatabasesBase { $databaseId = $data['databaseId']; foreach ($data['documents'] as $document) { - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $document['$collectionId'] . '/documents/' . $document['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$document['$collectionId'].'/documents/'.$document['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1373,7 +1370,7 @@ trait DatabasesBase $databaseId = $data['databaseId']; $document = $data['documents'][0]; - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $document['$collectionId'] . '/documents/' . $document['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$document['$collectionId'].'/documents/'.$document['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1397,7 +1394,7 @@ trait DatabasesBase /** * Test after without order. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $base = $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())); @@ -1408,11 +1405,11 @@ trait DatabasesBase $this->assertEquals('Spider-Man: Homecoming', $base['body']['documents'][2]['title']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['cursorAfter("' . $base['body']['documents'][0]['$id'] . '")'], + 'queries' => ['cursorAfter("'.$base['body']['documents'][0]['$id'].'")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1420,11 +1417,11 @@ trait DatabasesBase $this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][1]['$id']); $this->assertCount(2, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['cursorAfter("' . $base['body']['documents'][2]['$id'] . '")'], + 'queries' => ['cursorAfter("'.$base['body']['documents'][2]['$id'].'")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1433,7 +1430,7 @@ trait DatabasesBase /** * Test with ASC order and after. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $base = $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()), [ @@ -1446,11 +1443,11 @@ trait DatabasesBase $this->assertEquals(2019, $base['body']['documents'][2]['releaseYear']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['cursorAfter("' . $base['body']['documents'][1]['$id'] . '")', 'orderAsc("releaseYear")'], + 'queries' => ['cursorAfter("'.$base['body']['documents'][1]['$id'].'")', 'orderAsc("releaseYear")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1460,7 +1457,7 @@ trait DatabasesBase /** * Test with DESC order and after. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $base = $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()), [ @@ -1473,11 +1470,11 @@ trait DatabasesBase $this->assertEquals(2019, $base['body']['documents'][0]['releaseYear']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['cursorAfter("' . $base['body']['documents'][1]['$id'] . '")', 'orderDesc("releaseYear")'], + 'queries' => ['cursorAfter("'.$base['body']['documents'][1]['$id'].'")', 'orderDesc("releaseYear")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1487,7 +1484,7 @@ trait DatabasesBase /** * Test after with unknown document. */ - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1508,7 +1505,7 @@ trait DatabasesBase /** * Test before without order. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $base = $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())); @@ -1519,11 +1516,11 @@ trait DatabasesBase $this->assertEquals('Spider-Man: Homecoming', $base['body']['documents'][2]['title']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['cursorBefore("' . $base['body']['documents'][2]['$id'] . '")'], + 'queries' => ['cursorBefore("'.$base['body']['documents'][2]['$id'].'")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1531,11 +1528,11 @@ trait DatabasesBase $this->assertEquals($base['body']['documents'][1]['$id'], $documents['body']['documents'][1]['$id']); $this->assertCount(2, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['cursorBefore("' . $base['body']['documents'][0]['$id'] . '")'], + 'queries' => ['cursorBefore("'.$base['body']['documents'][0]['$id'].'")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1544,7 +1541,7 @@ trait DatabasesBase /** * Test with ASC order and after. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $base = $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()), [ @@ -1557,11 +1554,11 @@ trait DatabasesBase $this->assertEquals(2019, $base['body']['documents'][2]['releaseYear']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['cursorBefore("' . $base['body']['documents'][1]['$id'] . '")', 'orderAsc("releaseYear")'], + 'queries' => ['cursorBefore("'.$base['body']['documents'][1]['$id'].'")', 'orderAsc("releaseYear")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1571,7 +1568,7 @@ trait DatabasesBase /** * Test with DESC order and after. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $base = $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()), [ @@ -1584,11 +1581,11 @@ trait DatabasesBase $this->assertEquals(2019, $base['body']['documents'][0]['releaseYear']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['cursorBefore("' . $base['body']['documents'][1]['$id'] . '")', 'orderDesc("releaseYear")'], + 'queries' => ['cursorBefore("'.$base['body']['documents'][1]['$id'].'")', 'orderDesc("releaseYear")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1604,7 +1601,7 @@ trait DatabasesBase public function testListDocumentsLimitAndOffset(array $data): array { $databaseId = $data['databaseId']; - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1615,7 +1612,7 @@ trait DatabasesBase $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']); $this->assertCount(1, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1636,7 +1633,7 @@ trait DatabasesBase public function testDocumentsListQueries(array $data): array { $databaseId = $data['databaseId']; - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1647,18 +1644,18 @@ trait DatabasesBase $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']); $this->assertCount(1, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['equal("$id", "' . $documents['body']['documents'][0]['$id'] . '")'], + 'queries' => ['equal("$id", "'.$documents['body']['documents'][0]['$id'].'")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']); $this->assertCount(1, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1669,7 +1666,7 @@ trait DatabasesBase $this->assertEquals(2017, $documents['body']['documents'][0]['releaseYear']); $this->assertCount(1, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1681,7 +1678,7 @@ trait DatabasesBase $this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']); $this->assertCount(2, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1691,7 +1688,7 @@ trait DatabasesBase $this->assertCount(1, $documents['body']['documents']); $this->assertEquals('Captain America', $documents['body']['documents'][0]['title']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1702,7 +1699,7 @@ trait DatabasesBase $this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['title']); $this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['title']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1711,7 +1708,7 @@ trait DatabasesBase $this->assertCount(3, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1720,7 +1717,7 @@ trait DatabasesBase $this->assertCount(0, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1728,7 +1725,7 @@ trait DatabasesBase ]); $this->assertEquals(200, $documents['headers']['status-code']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1749,11 +1746,11 @@ trait DatabasesBase $conditions[] = $i; } - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['equal("releaseYear", [' . implode(',', $conditions) . '])'], + 'queries' => ['equal("releaseYear", ['.implode(',', $conditions).'])'], ]); $this->assertEquals(400, $documents['headers']['status-code']); @@ -1761,19 +1758,19 @@ trait DatabasesBase $conditions = []; for ($i = 0; $i < 101; $i++) { - $conditions[] = "[" . $i . "] Too long title to cross 2k chars query limit"; + $conditions[] = '['.$i.'] Too long title to cross 2k chars query limit'; } - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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' => ['search("title", ' . implode(',', $conditions) . ')'], + 'queries' => ['search("title", '.implode(',', $conditions).')'], ]); $this->assertEquals(400, $documents['headers']['status-code']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $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()), [ @@ -1791,7 +1788,7 @@ trait DatabasesBase public function testUpdateDocument(array $data): array { $databaseId = $data['databaseId']; - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1801,7 +1798,7 @@ trait DatabasesBase 'releaseYear' => 2017, 'birthDay' => '1976-06-12 14:12:55', 'actors' => [], - '$createdAt' => 5 // Should be ignored + '$createdAt' => 5, // Should be ignored ], 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), @@ -1825,7 +1822,7 @@ trait DatabasesBase $this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $document['body']['$permissions']); $this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $document['body']['$permissions']); - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1850,7 +1847,7 @@ trait DatabasesBase $this->assertContains(Permission::update(Role::users()), $document['body']['$permissions']); $this->assertContains(Permission::delete(Role::users()), $document['body']['$permissions']); - $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1864,7 +1861,7 @@ trait DatabasesBase $this->assertEquals($document['body']['title'], 'Thor: Ragnarok'); $this->assertEquals($document['body']['releaseYear'], 2017); - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-timestamp' => DateTime::formatTz(DateTime::now()), @@ -1879,8 +1876,7 @@ trait DatabasesBase /** * Test for failure */ - - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-timestamp' => 'invalid', @@ -1894,7 +1890,7 @@ trait DatabasesBase $this->assertEquals('Invalid X-Appwrite-Timestamp header value', $response['body']['message']); $this->assertEquals(Exception::GENERAL_ARGUMENT_INVALID, $response['body']['type']); - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-timestamp' => DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -1000)), @@ -1917,7 +1913,7 @@ trait DatabasesBase public function testDeleteDocument(array $data): array { $databaseId = $data['databaseId']; - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1932,28 +1928,28 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); $id = $document['body']['$id']; $this->assertEquals(201, $document['headers']['status-code']); - $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $document['headers']['status-code']); - $document = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(204, $document['headers']['status-code']); - $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1968,7 +1964,7 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'InvalidDocumentDatabase', @@ -1977,10 +1973,10 @@ trait DatabasesBase $this->assertEquals('InvalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'invalidDocumentStructure', @@ -1996,48 +1992,48 @@ trait DatabasesBase $collectionId = $collection['body']['$id']; - $email = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email', array_merge([ + $email = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'email', 'required' => false, ]); - $enum = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ + $enum = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'enum', 'elements' => ['yes', 'no', 'maybe'], 'required' => false, ]); - $ip = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip', array_merge([ + $ip = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'ip', 'required' => false, ]); - $url = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url', array_merge([ + $url = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'url', 'size' => 256, 'required' => false, ]); - $range = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ + $range = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'range', 'required' => false, @@ -2046,10 +2042,10 @@ trait DatabasesBase ]); // TODO@kodumbeats min and max are rounded in error message - $floatRange = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float', array_merge([ + $floatRange = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'floatRange', 'required' => false, @@ -2057,10 +2053,10 @@ trait DatabasesBase 'max' => 1.4, ]); - $probability = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float', array_merge([ + $probability = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'probability', 'required' => false, @@ -2069,20 +2065,20 @@ trait DatabasesBase 'max' => 1, ]); - $upperBound = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ + $upperBound = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'upperBound', 'required' => false, 'max' => 10, ]); - $lowerBound = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ + $lowerBound = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'lowerBound', 'required' => false, @@ -2092,10 +2088,9 @@ trait DatabasesBase /** * Test for failure */ - - $invalidRange = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ + $invalidRange = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'invalidRange', 'required' => false, @@ -2103,9 +2098,9 @@ trait DatabasesBase 'max' => 3, ]); - $defaultArray = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ + $defaultArray = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'defaultArray', 'required' => false, @@ -2113,54 +2108,54 @@ trait DatabasesBase 'array' => true, ]); - $defaultRequired = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ + $defaultRequired = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'attributeId' => ID::custom('defaultRequired'), 'required' => true, - 'default' => 12 + 'default' => 12, ]); - $enumDefault = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ + $enumDefault = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'attributeId' => ID::custom('enumDefault'), 'elements' => ['north', 'west'], - 'default' => 'south' + 'default' => 'south', ]); - $enumDefaultStrict = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ + $enumDefaultStrict = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'attributeId' => ID::custom('enumDefault'), 'elements' => ['north', 'west'], - 'default' => 'NORTH' + 'default' => 'NORTH', ]); - $goodDatetime = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime', array_merge([ + $goodDatetime = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'birthDay', 'required' => false, - 'default' => null + 'default' => null, ]); - $datetimeDefault = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime', array_merge([ + $datetimeDefault = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'badBirthDay', 'required' => false, - 'default' => 'bad' + 'default' => 'bad', ]); $this->assertEquals(202, $email['headers']['status-code']); @@ -2184,7 +2179,7 @@ trait DatabasesBase // wait for worker to add attributes sleep(3); - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -2195,8 +2190,7 @@ trait DatabasesBase /** * Test for successful validation */ - - $goodEmail = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $goodEmail = $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()), [ @@ -2208,10 +2202,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $goodEnum = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $goodEnum = $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()), [ @@ -2223,10 +2217,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $goodIp = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $goodIp = $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()), [ @@ -2238,10 +2232,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $goodUrl = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $goodUrl = $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()), [ @@ -2253,10 +2247,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $goodRange = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $goodRange = $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()), [ @@ -2268,10 +2262,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $goodFloatRange = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $goodFloatRange = $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()), [ @@ -2283,10 +2277,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $goodProbability = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $goodProbability = $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()), [ @@ -2298,10 +2292,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $notTooHigh = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $notTooHigh = $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()), [ @@ -2313,10 +2307,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $notTooLow = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $notTooLow = $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()), [ @@ -2328,7 +2322,7 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); $this->assertEquals(201, $goodEmail['headers']['status-code']); @@ -2345,7 +2339,7 @@ trait DatabasesBase * Test that custom validators reject documents */ - $badEmail = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $badEmail = $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()), [ @@ -2357,10 +2351,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $badEnum = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $badEnum = $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()), [ @@ -2372,10 +2366,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $badIp = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $badIp = $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()), [ @@ -2387,10 +2381,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $badUrl = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $badUrl = $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()), [ @@ -2402,10 +2396,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $badRange = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $badRange = $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()), [ @@ -2417,10 +2411,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $badFloatRange = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $badFloatRange = $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()), [ @@ -2432,10 +2426,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $badProbability = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $badProbability = $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()), [ @@ -2447,10 +2441,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $tooHigh = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $tooHigh = $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()), [ @@ -2462,10 +2456,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $tooLow = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $tooLow = $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()), [ @@ -2477,10 +2471,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); - $badTime = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $badTime = $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()), [ @@ -2488,8 +2482,8 @@ trait DatabasesBase 'data' => [ 'birthDay' => '2020-10-10 27:30:10+01:00', ], - 'read' => ['user:' . $this->getUser()['$id']], - 'write' => ['user:' . $this->getUser()['$id']], + 'read' => ['user:'.$this->getUser()['$id']], + 'write' => ['user:'.$this->getUser()['$id']], ]); $this->assertEquals(400, $badEmail['headers']['status-code']); @@ -2519,7 +2513,7 @@ trait DatabasesBase public function testDefaultPermissions(array $data): array { $databaseId = $data['databaseId']; - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2552,7 +2546,7 @@ trait DatabasesBase // Updated Permissions - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2563,7 +2557,7 @@ trait DatabasesBase ], 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])) + Permission::update(Role::user($this->getUser()['$id'])), ], ]); @@ -2580,7 +2574,7 @@ trait DatabasesBase Permission::update(Role::user($this->getUser()['$id'])), ], $document['body']['$permissions']); - $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2597,7 +2591,7 @@ trait DatabasesBase // Reset Permissions - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2616,7 +2610,7 @@ trait DatabasesBase $this->assertEquals([], $document['body']['$permissions']); // Check client side can no longer read the document. - $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2638,7 +2632,7 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'EnforceCollectionAndDocumentPermissions', @@ -2648,10 +2642,10 @@ trait DatabasesBase $databaseId = $database['body']['$id']; $user = $this->getUser()['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'enforceCollectionAndDocumentPermissions', @@ -2672,10 +2666,10 @@ trait DatabasesBase sleep(2); - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'attribute', 'size' => 64, @@ -2688,10 +2682,10 @@ trait DatabasesBase // wait for db to add attribute sleep(2); - $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'key_attribute', 'type' => 'key', @@ -2704,7 +2698,7 @@ trait DatabasesBase // wait for db to add attribute sleep(2); - $document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $document1 = $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()), [ @@ -2716,12 +2710,12 @@ trait DatabasesBase Permission::read(Role::user($user)), Permission::update(Role::user($user)), Permission::delete(Role::user($user)), - ] + ], ]); $this->assertEquals(201, $document1['headers']['status-code']); - $document2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $document2 = $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()), [ @@ -2732,15 +2726,15 @@ trait DatabasesBase 'permissions' => [ Permission::update(Role::user($user)), Permission::delete(Role::user($user)), - ] + ], ]); $this->assertEquals(201, $document2['headers']['status-code']); - $document3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ + $document3 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'documentId' => ID::unique(), 'data' => [ @@ -2754,7 +2748,7 @@ trait DatabasesBase $this->assertEquals(201, $document3['headers']['status-code']); - $documentsUser1 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $documentsUser1 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2763,7 +2757,7 @@ trait DatabasesBase $this->assertEquals(3, $documentsUser1['body']['total']); $this->assertCount(3, $documentsUser1['body']['documents']); - $document3GetWithCollectionRead = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document3['body']['$id'], array_merge([ + $document3GetWithCollectionRead = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document3['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2771,7 +2765,7 @@ trait DatabasesBase // Current user has read permission on the collection so can get any document $this->assertEquals(200, $document3GetWithCollectionRead['headers']['status-code']); - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; $this->client->call(Client::METHOD_POST, '/account', [ @@ -2792,33 +2786,33 @@ trait DatabasesBase 'email' => $email, 'password' => $password, ]); - $session2 = $this->client->parseCookie((string)$session2['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session2 = $this->client->parseCookie((string) $session2['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; - $document3GetWithDocumentRead = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document3['body']['$id'], [ + $document3GetWithDocumentRead = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document3['body']['$id'], [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, ]); // Current user has no collection permissions but has read permission for this document $this->assertEquals(200, $document3GetWithDocumentRead['headers']['status-code']); - $document2GetFailure = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document2['body']['$id'], [ + $document2GetFailure = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document2['body']['$id'], [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, ]); // Current user has no collection or document permissions for this document $this->assertEquals(404, $document2GetFailure['headers']['status-code']); - $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ + $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, ]); // Current user has no collection permissions but has read permission for one document @@ -2831,7 +2825,7 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'EnforceCollectionPermissions', @@ -2841,10 +2835,10 @@ trait DatabasesBase $databaseId = $database['body']['$id']; $user = $this->getUser()['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'enforceCollectionPermissions', @@ -2864,10 +2858,10 @@ trait DatabasesBase sleep(2); - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'attribute', 'size' => 64, @@ -2880,10 +2874,10 @@ trait DatabasesBase // wait for db to add attribute sleep(2); - $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'key_attribute', 'type' => 'key', @@ -2896,7 +2890,7 @@ trait DatabasesBase // wait for db to add attribute sleep(2); - $document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $document1 = $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()), [ @@ -2908,12 +2902,12 @@ trait DatabasesBase Permission::read(Role::user($user)), Permission::update(Role::user($user)), Permission::delete(Role::user($user)), - ] + ], ]); $this->assertEquals(201, $document1['headers']['status-code']); - $document2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $document2 = $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()), [ @@ -2924,15 +2918,15 @@ trait DatabasesBase 'permissions' => [ Permission::update(Role::user($user)), Permission::delete(Role::user($user)), - ] + ], ]); $this->assertEquals(201, $document2['headers']['status-code']); - $document3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ + $document3 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'documentId' => ID::unique(), 'data' => [ @@ -2946,7 +2940,7 @@ trait DatabasesBase $this->assertEquals(201, $document3['headers']['status-code']); - $documentsUser1 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $documentsUser1 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2955,7 +2949,7 @@ trait DatabasesBase $this->assertEquals(3, $documentsUser1['body']['total']); $this->assertCount(3, $documentsUser1['body']['documents']); - $document3GetWithCollectionRead = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document3['body']['$id'], array_merge([ + $document3GetWithCollectionRead = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document3['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2963,7 +2957,7 @@ trait DatabasesBase // Current user has read permission on the collection so can get any document $this->assertEquals(200, $document3GetWithCollectionRead['headers']['status-code']); - $email = uniqid() . 'user2@localhost.test'; + $email = uniqid().'user2@localhost.test'; $password = 'password'; $name = 'User Name'; $this->client->call(Client::METHOD_POST, '/account', [ @@ -2984,43 +2978,43 @@ trait DatabasesBase 'email' => $email, 'password' => $password, ]); - $session2 = $this->client->parseCookie((string)$session2['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session2 = $this->client->parseCookie((string) $session2['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; - $document3GetWithDocumentRead = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document3['body']['$id'], [ + $document3GetWithDocumentRead = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document3['body']['$id'], [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, ]); // Current user has no collection permissions and document permissions are disabled $this->assertEquals(404, $document3GetWithDocumentRead['headers']['status-code']); - $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ + $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, ]); // Current user has no collection permissions and document permissions are disabled $this->assertEquals(404, $documentsUser2['headers']['status-code']); // Enable document permissions - $collection = $this->client->call(CLient::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId, [ + $collection = $this->client->call(CLient::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$collectionId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'name' => $collection['body']['name'], 'documentSecurity' => true, ]); - $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ + $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, ]); // Current user has no collection permissions read access to one document @@ -3034,10 +3028,10 @@ trait DatabasesBase public function testUniqueIndexDuplicate(array $data): array { $databaseId = $data['databaseId']; - $uniqueIndex = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + $uniqueIndex = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'unique_title', 'type' => 'unique', @@ -3049,7 +3043,7 @@ trait DatabasesBase sleep(2); // test for failure - $duplicate = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $duplicate = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3060,19 +3054,19 @@ trait DatabasesBase 'actors' => [ 'Chris Evans', 'Samuel Jackson', - ] + ], ], 'permissions' => [ Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); $this->assertEquals(409, $duplicate['headers']['status-code']); // Test for exception when updating document to conflict - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3083,19 +3077,19 @@ trait DatabasesBase 'actors' => [ 'Chris Evans', 'Samuel Jackson', - ] + ], ], 'permissions' => [ Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); $this->assertEquals(201, $document['headers']['status-code']); // Test for exception when updating document to conflict - $duplicate = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $document['body']['$id'], array_merge([ + $duplicate = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$document['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3106,13 +3100,13 @@ trait DatabasesBase 'actors' => [ 'Chris Evans', 'Samuel Jackson', - ] + ], ], 'permissions' => [ Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); $this->assertEquals(409, $duplicate['headers']['status-code']); @@ -3131,15 +3125,15 @@ trait DatabasesBase ], $this->getHeaders()) : [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]; - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['moviesId'] . '/documents', $headers, [ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$data['databaseId'].'/collections/'.$data['moviesId'].'/documents', $headers, [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Creation Date Test', - 'releaseYear' => 2000 - ] + 'releaseYear' => 2000, + ], ]); $this->assertEquals($document['body']['title'], 'Creation Date Test'); @@ -3150,10 +3144,10 @@ trait DatabasesBase \sleep(1); - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, $headers, [ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$data['databaseId'].'/collections/'.$data['moviesId'].'/documents/'.$documentId, $headers, [ 'data' => [ 'title' => 'Updated Date Test', - ] + ], ]); $updatedAtSecond = $document['body']['$updatedAt']; @@ -3164,12 +3158,12 @@ trait DatabasesBase \sleep(1); - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, $headers, [ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$data['databaseId'].'/collections/'.$data['moviesId'].'/documents/'.$documentId, $headers, [ 'data' => [ 'title' => 'Again Updated Date Test', '$createdAt' => '2022-08-01 13:09:23.040', // $createdAt is not updatable - '$updatedAt' => '2022-08-01 13:09:23.050' // system will update it not api - ] + '$updatedAt' => '2022-08-01 13:09:23.050', // system will update it not api + ], ]); $this->assertEquals($document['body']['title'], 'Again Updated Date Test'); @@ -3188,7 +3182,7 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'Empty Permissions', @@ -3198,10 +3192,10 @@ trait DatabasesBase $databaseId = $database['body']['$id']; // Create collection - $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -3220,10 +3214,10 @@ trait DatabasesBase $moviesId = $movies['body']['$id']; // create attribute - $title = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/attributes/string', array_merge([ + $title = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'title', 'size' => 256, @@ -3236,7 +3230,7 @@ trait DatabasesBase sleep(2); // add document - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3260,20 +3254,20 @@ trait DatabasesBase $this->assertContains(Permission::delete(Role::any()), $document['body']['$permissions']); // Send only read permission - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'permissions' => [ Permission::read(Role::user(ID::custom($this->getUser()['$id']))), - ] + ], ]); $this->assertEquals(200, $document['headers']['status-code']); $this->assertCount(1, $document['body']['$permissions']); // Send only mutation permissions - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents/' . $id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3291,7 +3285,7 @@ trait DatabasesBase } // remove collection - $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $moviesId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$moviesId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3309,39 +3303,39 @@ trait DatabasesBase /** * Test for SUCCESS */ - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), - 'name' => 'Boolean' + 'name' => 'Boolean', ]); $this->assertEquals(201, $collection['headers']['status-code']); $collectionId = $collection['body']['$id']; - $true = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean', array_merge([ + $true = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'true', 'required' => false, - 'default' => true + 'default' => true, ]); $this->assertEquals(202, $true['headers']['status-code']); - $false = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean', array_merge([ + $false = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'false', 'required' => false, - 'default' => false + 'default' => false, ]); $this->assertEquals(202, $false['headers']['status-code']); @@ -3354,10 +3348,10 @@ trait DatabasesBase { $databaseId = $data['databaseId']; - $person = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $person = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => 'person', 'name' => 'person', @@ -3372,10 +3366,10 @@ trait DatabasesBase $this->assertEquals(201, $person['headers']['status-code']); - $library = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $library = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => 'library', 'name' => 'library', @@ -3389,10 +3383,10 @@ trait DatabasesBase $this->assertEquals(201, $library['headers']['status-code']); - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'fullName', 'size' => 255, @@ -3401,10 +3395,10 @@ trait DatabasesBase sleep(1); // Wait for worker - $relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/attributes/relationship', array_merge([ + $relation = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => 'library', 'type' => Database::RELATION_ONE_TO_ONE, @@ -3415,10 +3409,10 @@ trait DatabasesBase sleep(1); // Wait for worker - $libraryName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $library['body']['$id'] . '/attributes/string', array_merge([ + $libraryName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$library['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'libraryName', 'size' => 255, @@ -3433,10 +3427,10 @@ trait DatabasesBase $this->assertEquals('relationship', $relation['body']['type']); $this->assertEquals('processing', $relation['body']['status']); - $attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/attributes', array_merge([ + $attributes = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $attributes['headers']['status-code']); @@ -3451,7 +3445,7 @@ trait DatabasesBase $attribute = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$person['body']['$id']}/attributes/library", array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $attribute['headers']['status-code']); @@ -3465,7 +3459,7 @@ trait DatabasesBase $this->assertEquals('person', $attribute['body']['twoWayKey']); $this->assertEquals(Database::RELATION_MUTATE_CASCADE, $attribute['body']['onDelete']); - $person1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ + $person1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3483,13 +3477,13 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); $this->assertEquals('Library 1', $person1['body']['library']['libraryName']); // Create without nested ID - $person2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ + $person2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3503,7 +3497,7 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); $this->assertEquals('Library 2', $person2['body']['library']['libraryName']); @@ -3520,21 +3514,21 @@ trait DatabasesBase $this->assertArrayNotHasKey('$internalId', $person1['body']); $this->assertArrayNotHasKey('$internalId', $person1['body']['library']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ + $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ 'equal("library", "library1")', - 'select(["fullName","library.*"])' - ] + 'select(["fullName","library.*"])', + ], ]); $this->assertEquals(1, $documents['body']['total']); $this->assertEquals('Library 1', $documents['body']['documents'][0]['library']['libraryName']); $this->assertArrayHasKey('fullName', $documents['body']['documents'][0]); - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ + $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3546,10 +3540,10 @@ trait DatabasesBase $this->assertEquals(400, $documents['headers']['status-code']); $this->assertEquals('Invalid query: Cannot query nested attribute on: library', $documents['body']['message']); - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/attributes/library', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/attributes/library', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); sleep(2); @@ -3559,12 +3553,12 @@ trait DatabasesBase $attribute = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$person['body']['$id']}/attributes/library", array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(404, $attribute['headers']['status-code']); - $person1 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents/' . $person1['body']['$id'], array_merge([ + $person1 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents/'.$person1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3572,10 +3566,10 @@ trait DatabasesBase $this->assertArrayNotHasKey('library', $person1['body']); //Test Deletion of related twoKey - $attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $library['body']['$id'] . '/attributes', array_merge([ + $attributes = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$library['body']['$id'].'/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $attributes['headers']['status-code']); @@ -3599,10 +3593,10 @@ trait DatabasesBase $libraryCollection = $data['libraryCollection']; // One person can own several libraries - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $personCollection . '/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$personCollection.'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => 'library', 'type' => Database::RELATION_ONE_TO_MANY, @@ -3613,20 +3607,20 @@ trait DatabasesBase sleep(1); - $libraryAttributesResponse = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $libraryCollection . '/attributes', array_merge([ + $libraryAttributesResponse = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$libraryCollection.'/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertIsArray($libraryAttributesResponse['body']['attributes']); $this->assertEquals(2, $libraryAttributesResponse['body']['total']); $this->assertEquals('person_one_to_many', $libraryAttributesResponse['body']['attributes'][1]['key']); - $libraryCollectionResponse = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $libraryCollection, array_merge([ + $libraryCollectionResponse = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$libraryCollection, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertIsArray($libraryCollectionResponse['body']['attributes']); @@ -3635,7 +3629,7 @@ trait DatabasesBase $attribute = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$personCollection}/attributes/libraries", array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $attribute['headers']['status-code']); @@ -3649,7 +3643,7 @@ trait DatabasesBase $this->assertEquals('person_one_to_many', $attribute['body']['twoWayKey']); $this->assertEquals('restrict', $attribute['body']['onDelete']); - $person2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $personCollection . '/documents', array_merge([ + $person2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$personCollection.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3674,21 +3668,21 @@ trait DatabasesBase Permission::delete(Role::any()), ], 'libraryName' => 'Library 11', - ] + ], ], ], 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()), - ] + ], ]); $this->assertEquals(201, $person2['headers']['status-code']); $this->assertArrayHasKey('libraries', $person2['body']); $this->assertEquals(2, count($person2['body']['libraries'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $personCollection . '/documents/' . $person2['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$personCollection.'/documents/'.$person2['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3698,7 +3692,7 @@ trait DatabasesBase $this->assertArrayHasKey('libraries', $response['body']); $this->assertEquals(2, count($response['body']['libraries'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $libraryCollection . '/documents/library11', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$libraryCollection.'/documents/library11', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3707,10 +3701,10 @@ trait DatabasesBase $this->assertArrayHasKey('person_one_to_many', $response['body']); $this->assertEquals('person10', $response['body']['person_one_to_many']['$id']); - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $personCollection . '/attributes/libraries/relationship', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$personCollection.'/attributes/libraries/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'onDelete' => Database::RELATION_MUTATE_CASCADE, ]); @@ -3720,7 +3714,7 @@ trait DatabasesBase $attribute = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$personCollection}/attributes/libraries", array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $attribute['headers']['status-code']); @@ -3744,10 +3738,10 @@ trait DatabasesBase $databaseId = $data['databaseId']; // Create album collection - $albums = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $albums = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Albums', @@ -3759,10 +3753,10 @@ trait DatabasesBase ]); // Create album name attribute - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $albums['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$albums['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'name', 'size' => 255, @@ -3770,10 +3764,10 @@ trait DatabasesBase ]); // Create artist collection - $artists = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $artists = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Artists', @@ -3785,10 +3779,10 @@ trait DatabasesBase ]); // Create artist name attribute - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $artists['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$artists['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'name', 'size' => 255, @@ -3796,10 +3790,10 @@ trait DatabasesBase ]); // Create relationship - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $albums['body']['$id'] . '/attributes/relationship', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$albums['body']['$id'].'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $artists['body']['$id'], 'type' => Database::RELATION_MANY_TO_ONE, @@ -3826,7 +3820,7 @@ trait DatabasesBase ]; // Create album - $album = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $albums['body']['$id'] . '/documents', array_merge([ + $album = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$albums['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3848,7 +3842,7 @@ trait DatabasesBase $this->assertEquals($permissions, $album['body']['$permissions']); $this->assertEquals($permissions, $album['body']['artist']['$permissions']); - $album = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $albums['body']['$id'] . '/documents/album1', array_merge([ + $album = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$albums['body']['$id'].'/documents/album1', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3860,7 +3854,7 @@ trait DatabasesBase $this->assertEquals($permissions, $album['body']['$permissions']); $this->assertEquals($permissions, $album['body']['artist']['$permissions']); - $artist = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $artists['body']['$id'] . '/documents/' . $album['body']['artist']['$id'], array_merge([ + $artist = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$artists['body']['$id'].'/documents/'.$album['body']['artist']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3888,10 +3882,10 @@ trait DatabasesBase $databaseId = $data['databaseId']; // Create sports collection - $sports = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $sports = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Sports', @@ -3903,10 +3897,10 @@ trait DatabasesBase ]); // Create sport name attribute - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $sports['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$sports['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'name', 'size' => 255, @@ -3914,10 +3908,10 @@ trait DatabasesBase ]); // Create player collection - $players = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $players = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Players', @@ -3929,10 +3923,10 @@ trait DatabasesBase ]); // Create player name attribute - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $players['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$players['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'name', 'size' => 255, @@ -3940,10 +3934,10 @@ trait DatabasesBase ]); // Create relationship - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $sports['body']['$id'] . '/attributes/relationship', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$sports['body']['$id'].'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $players['body']['$id'], 'type' => Database::RELATION_MANY_TO_MANY, @@ -3971,7 +3965,7 @@ trait DatabasesBase ]; // Create sport - $sport = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $sports['body']['$id'] . '/documents', array_merge([ + $sport = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$sports['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3987,7 +3981,7 @@ trait DatabasesBase [ '$id' => 'player2', 'name' => 'Player 2', - ] + ], ], ], ]); @@ -4001,7 +3995,7 @@ trait DatabasesBase $this->assertEquals($permissions, $sport['body']['players'][0]['$permissions']); $this->assertEquals($permissions, $sport['body']['players'][1]['$permissions']); - $sport = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $sports['body']['$id'] . '/documents/sport1', array_merge([ + $sport = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$sports['body']['$id'].'/documents/sport1', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -4015,7 +4009,7 @@ trait DatabasesBase $this->assertEquals($permissions, $sport['body']['players'][0]['$permissions']); $this->assertEquals($permissions, $sport['body']['players'][1]['$permissions']); - $player = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $players['body']['$id'] . '/documents/' . $sport['body']['players'][0]['$id'], array_merge([ + $player = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$players['body']['$id'].'/documents/'.$sport['body']['players'][0]['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -4040,7 +4034,7 @@ trait DatabasesBase */ public function testValidateOperators(array $data): void { - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -4058,21 +4052,21 @@ trait DatabasesBase $this->assertEquals('Stevie Wonder', $response['body']['documents'][0]['fullName']); $this->assertEquals(2, count($response['body']['documents'][0]['libraries'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ 'isNotNull("$id")', 'isNull("fullName")', - 'select(["fullName"])' + 'select(["fullName"])', ], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(2, count($response['body']['documents'])); $this->assertEquals(null, $response['body']['documents'][0]['fullName']); - $this->assertArrayNotHasKey("libraries", $response['body']['documents'][0]); + $this->assertArrayNotHasKey('libraries', $response['body']['documents'][0]); } /** @@ -4080,20 +4074,20 @@ trait DatabasesBase */ public function testSelectsQueries(array $data): void { - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ 'equal("fullName", "Stevie Wonder")', - 'select(["fullName"])' + 'select(["fullName"])', ], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertArrayNotHasKey('libraries', $response['body']['documents'][0]); - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -4105,12 +4099,12 @@ trait DatabasesBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertArrayHasKey('libraries', $document); - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents/' . $document['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents/'.$document['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ - 'select(["fullName", "$id"])' + 'select(["fullName", "$id"])', ], ]); @@ -4121,18 +4115,20 @@ trait DatabasesBase /** * @depends testCreateDatabase - * @param array $data + * + * @param array $data * @return void + * * @throws \Exception */ public function testUpdateWithExistingRelationships(array $data): void { $databaseId = $data['databaseId']; - $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Collection1', @@ -4143,10 +4139,10 @@ trait DatabasesBase ], ]); - $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Collection2', @@ -4160,42 +4156,42 @@ trait DatabasesBase $collection1 = $collection1['body']['$id']; $collection2 = $collection2['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'name', 'size' => '49', 'required' => true, ]); - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2 . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection2.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'name', 'size' => '49', 'required' => true, ]); - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1.'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $collection2, 'type' => Database::RELATION_ONE_TO_MANY, 'twoWay' => true, - 'key' => 'collection2' + 'key' => 'collection2', ]); sleep(1); - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1.'/documents', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ @@ -4208,9 +4204,9 @@ trait DatabasesBase ], ]); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents/' . $document['body']['$id'], array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1.'/documents/'.$document['body']['$id'], array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => [ 'name' => 'Document 1 Updated', diff --git a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php index 17059adf88..947b0ed7fe 100644 --- a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php +++ b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php @@ -2,9 +2,9 @@ namespace Tests\E2E\Services\Databases; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -32,7 +32,7 @@ class DatabasesConsoleClientTest extends Scope /** * Test for SUCCESS */ - $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -53,7 +53,7 @@ class DatabasesConsoleClientTest extends Scope /** * Test When database is disabled but can still create collections */ - $database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, array_merge([ + $database = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -63,7 +63,7 @@ class DatabasesConsoleClientTest extends Scope $this->assertFalse($database['body']['enabled']); - $tvShows = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $tvShows = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -86,7 +86,8 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection - * @param array $data + * + * @param array $data */ public function testListCollection(array $data) { @@ -95,10 +96,10 @@ class DatabasesConsoleClientTest extends Scope */ $databaseId = $data['databaseId']; - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], $this->getHeaders())); $this->assertEquals(200, $collections['headers']['status-code']); @@ -107,7 +108,8 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection - * @param array $data + * + * @param array $data */ public function testGetCollection(array $data) { @@ -117,7 +119,7 @@ class DatabasesConsoleClientTest extends Scope /** * Test When database is disabled but can still call get collection */ - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $moviesCollectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$moviesCollectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -130,7 +132,8 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection - * @param array $data + * + * @param array $data */ public function testUpdateCollection(array $data) { @@ -140,12 +143,12 @@ class DatabasesConsoleClientTest extends Scope /** * Test When database is disabled but can still call update collection */ - $collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $moviesCollectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$moviesCollectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'name' => 'Movies Updated', - 'enabled' => false + 'enabled' => false, ]); $this->assertEquals(200, $collection['headers']['status-code']); @@ -156,7 +159,8 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection - * @param array $data + * + * @param array $data */ public function testDeleteCollection(array $data) { @@ -166,13 +170,13 @@ class DatabasesConsoleClientTest extends Scope /** * Test When database is disabled but can still call Delete collection */ - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $tvShowsId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$tvShowsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEquals($response['body'], ""); + $this->assertEquals($response['body'], ''); } /** @@ -184,12 +188,11 @@ class DatabasesConsoleClientTest extends Scope /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '32h' + 'range' => '32h', ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -197,12 +200,11 @@ class DatabasesConsoleClientTest extends Scope /** * Test for SUCCESS */ - - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '24h' + 'range' => '24h', ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -212,7 +214,6 @@ class DatabasesConsoleClientTest extends Scope $this->assertIsArray($response['body']['collectionsTotal']); } - /** * @depends testCreateCollection */ @@ -222,21 +223,20 @@ class DatabasesConsoleClientTest extends Scope /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '32h' + 'range' => '32h', ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/randomCollectionId/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/randomCollectionId/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '24h' + 'range' => '24h', ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -244,11 +244,11 @@ class DatabasesConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '24h' + 'range' => '24h', ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(count($response['body']), 2); @@ -265,7 +265,7 @@ class DatabasesConsoleClientTest extends Scope /** * Test for SUCCESS */ - $logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -274,11 +274,11 @@ class DatabasesConsoleClientTest extends Scope $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'limit' => 1 + 'limit' => 1, ]); $this->assertEquals(200, $logs['headers']['status-code']); @@ -286,23 +286,23 @@ class DatabasesConsoleClientTest extends Scope $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'offset' => 1 + 'offset' => 1, ]); $this->assertEquals(200, $logs['headers']['status-code']); $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'offset' => 1, - 'limit' => 1 + 'limit' => 1, ]); $this->assertEquals(200, $logs['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php index 743df9e53a..b5abaebfad 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Databases; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -21,23 +21,22 @@ class DatabasesCustomClientTest extends Scope /** * Test for SUCCESS */ - $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'databaseId' => ID::unique(), - 'name' => 'Test Database' + 'name' => 'Test Database', ]); $databaseId = $database['body']['$id']; // Collection aliases write to create, update, delete - $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -53,10 +52,10 @@ class DatabasesCustomClientTest extends Scope $this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']); $this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']); - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/attributes/string', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'title', 'size' => 256, @@ -68,7 +67,7 @@ class DatabasesCustomClientTest extends Scope $this->assertEquals(202, $response['headers']['status-code']); // Document aliases write to update, delete - $document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', array_merge([ + $document1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -78,7 +77,7 @@ class DatabasesCustomClientTest extends Scope ], 'permissions' => [ Permission::write(Role::user($this->getUser()['$id'])), - ] + ], ]); $this->assertNotContains(Permission::create(Role::user($this->getUser()['$id'])), $document1['body']['$permissions']); @@ -90,7 +89,7 @@ class DatabasesCustomClientTest extends Scope */ // Document does not allow create permission - $document2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', array_merge([ + $document2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -100,7 +99,7 @@ class DatabasesCustomClientTest extends Scope ], 'permissions' => [ Permission::create(Role::user($this->getUser()['$id'])), - ] + ], ]); $this->assertEquals(400, $document2['headers']['status-code']); @@ -114,7 +113,7 @@ class DatabasesCustomClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); @@ -123,7 +122,7 @@ class DatabasesCustomClientTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::custom('permissionCheckDatabase'), 'name' => 'Test Database', @@ -133,10 +132,10 @@ class DatabasesCustomClientTest extends Scope $databaseId = $database['body']['$id']; // Create collection - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('permissionCheck'), 'name' => 'permissionCheck', @@ -146,10 +145,10 @@ class DatabasesCustomClientTest extends Scope $this->assertEquals(201, $response['headers']['status-code']); // Add attribute to collection - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/permissionCheck/attributes/string', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/permissionCheck/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'name', 'size' => 255, @@ -161,10 +160,10 @@ class DatabasesCustomClientTest extends Scope sleep(2); // Creating document by server, give read permission to our user + some other user - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/permissionCheck/documents', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/permissionCheck/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'documentId' => ID::custom('permissionCheckDocument'), 'data' => [ @@ -182,44 +181,43 @@ class DatabasesCustomClientTest extends Scope // Update document // This is the point of this test. We should be allowed to do this action, and it should not fail on permission check - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/permissionCheck/documents/permissionCheckDocument', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/permissionCheck/documents/permissionCheckDocument', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => [ 'name' => 'AppwriteExpert', - ] + ], ]); $this->assertEquals(200, $response['headers']['status-code']); // Get name of the document, should be the new one - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/permissionCheck/documents/permissionCheckDocument', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/permissionCheck/documents/permissionCheckDocument', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals("AppwriteExpert", $response['body']['name']); + $this->assertEquals('AppwriteExpert', $response['body']['name']); // Cleanup to prevent collision with other tests // Delete collection - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/permissionCheck', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/permissionCheck', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(204, $response['headers']['status-code']); - // Wait for database worker to finish deleting collection sleep(2); // Make sure collection has been deleted - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/permissionCheck', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/permissionCheck', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(404, $response['headers']['status-code']); @@ -228,24 +226,22 @@ class DatabasesCustomClientTest extends Scope public function testUpdateTwoWayRelationship(): void { - $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'databaseId' => ID::unique(), - 'name' => 'Test Database' + 'name' => 'Test Database', ]); $databaseId = $database['body']['$id']; - // Creating collection 1 - $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'level1', @@ -255,14 +251,14 @@ class DatabasesCustomClientTest extends Scope Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); // Creating collection 2 - $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'level2', @@ -272,41 +268,41 @@ class DatabasesCustomClientTest extends Scope Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); \sleep(2); // Creating two way relationship between collection 1 and collection 2 from collection 1 - $relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/attributes/relationship', array_merge([ + $relation = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $collection2['body']['$id'], 'type' => 'oneToMany', 'twoWay' => true, 'onDelete' => 'cascade', 'key' => $collection2['body']['$id'], - 'twoWayKey' => $collection1['body']['$id'] + 'twoWayKey' => $collection1['body']['$id'], ]); \sleep(3); // Update relation from collection 2 to on delete restrict - $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/attributes/' . $collection1['body']['$id'] . '/relationship', array_merge([ + $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection2['body']['$id'].'/attributes/'.$collection1['body']['$id'].'/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'onDelete' => 'restrict', ]); // Fetching attributes after updating relation to compare - $collection1Attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'], [ + $collection1Attributes = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]); $collection1RelationAttribute = $collection1Attributes['body']['attributes'][0]; @@ -323,7 +319,7 @@ class DatabasesCustomClientTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'databaseId' => ID::unique(), 'name' => ID::unique(), @@ -332,10 +328,10 @@ class DatabasesCustomClientTest extends Scope $databaseId = $database['body']['$id']; // Creating collection 1 - $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('collection1'), 'name' => ID::custom('collection1'), @@ -344,27 +340,27 @@ class DatabasesCustomClientTest extends Scope Permission::create(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ] + ], ]); // Creating collection 2 - $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('collection2'), 'name' => ID::custom('collection2'), 'documentSecurity' => false, 'permissions' => [ Permission::read(Role::user($userId)), - ] + ], ]); - $collection3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection3 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('collection3'), 'name' => ID::custom('collection3'), @@ -373,26 +369,26 @@ class DatabasesCustomClientTest extends Scope Permission::create(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ] + ], ]); - $collection4 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection4 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('collection4'), 'name' => ID::custom('collection4'), 'documentSecurity' => false, 'permissions' => [ Permission::read(Role::user($userId)), - ] + ], ]); - $collection5 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection5 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('collection5'), 'name' => ID::custom('collection5'), @@ -401,115 +397,115 @@ class DatabasesCustomClientTest extends Scope Permission::create(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ] + ], ]); // Creating one to one relationship from collection 1 to colletion 2 - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $collection2['body']['$id'], 'type' => 'oneToOne', 'twoWay' => false, 'onDelete' => 'setNull', - 'key' => $collection2['body']['$id'] + 'key' => $collection2['body']['$id'], ]); // Creating one to one relationship from collection 2 to colletion 3 - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection2['body']['$id'].'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $collection3['body']['$id'], 'type' => 'oneToOne', 'twoWay' => false, 'onDelete' => 'setNull', - 'key' => $collection3['body']['$id'] + 'key' => $collection3['body']['$id'], ]); // Creating one to one relationship from collection 3 to colletion 4 - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection3['body']['$id'] . '/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection3['body']['$id'].'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $collection4['body']['$id'], 'type' => 'oneToOne', 'twoWay' => false, 'onDelete' => 'setNull', - 'key' => $collection4['body']['$id'] + 'key' => $collection4['body']['$id'], ]); // Creating one to one relationship from collection 4 to colletion 5 - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection4['body']['$id'] . '/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection4['body']['$id'].'/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'relatedCollectionId' => $collection5['body']['$id'], 'type' => 'oneToOne', 'twoWay' => false, 'onDelete' => 'setNull', - 'key' => $collection5['body']['$id'] + 'key' => $collection5['body']['$id'], ]); - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'key' => "Title", + 'key' => 'Title', 'size' => 100, 'required' => false, 'array' => false, 'default' => null, ]); - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection2['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'key' => "Rating", + 'key' => 'Rating', 'size' => 100, 'required' => false, 'array' => false, 'default' => null, ]); - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection3['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection3['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'key' => "Rating", + 'key' => 'Rating', 'size' => 100, 'required' => false, 'array' => false, 'default' => null, ]); - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection4['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection4['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'key' => "Rating", + 'key' => 'Rating', 'size' => 100, 'required' => false, 'array' => false, 'default' => null, ]); - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection5['body']['$id'] . '/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection5['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'key' => "Rating", + 'key' => 'Rating', 'size' => 100, 'required' => false, 'array' => false, @@ -518,10 +514,10 @@ class DatabasesCustomClientTest extends Scope \sleep(2); // Creating parent document with a child reference to test the permissions - $parentDocument = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents', array_merge([ + $parentDocument = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'documentId' => ID::custom($collection1['body']['$id']), 'data' => [ @@ -537,17 +533,17 @@ class DatabasesCustomClientTest extends Scope 'Rating' => '10', $collection5['body']['$id'] => [ '$id' => ID::custom($collection5['body']['$id']), - 'Rating' => '10' - ] - ] - ] - ] - ] + 'Rating' => '10', + ], + ], + ], + ], + ], ]); $this->assertEquals(201, $parentDocument['headers']['status-code']); // This is the point of the test. We should not need any authorization permission to update the document with same data. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -565,21 +561,21 @@ class DatabasesCustomClientTest extends Scope 'Rating' => '10', $collection5['body']['$id'] => [ '$id' => $collection5['body']['$id'], - 'Rating' => '10' - ] - ] - ] - ] - ] + 'Rating' => '10', + ], + ], + ], + ], + ], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($parentDocument['body'], $response['body']); // Giving update permission of collection 3 to user. - $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/collection3', array_merge([ + $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/collection3', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('collection3'), 'name' => ID::custom('collection3'), @@ -589,11 +585,11 @@ class DatabasesCustomClientTest extends Scope Permission::read(Role::user($userId)), Permission::update(Role::user($userId)), Permission::delete(Role::user($userId)), - ] + ], ]); // This is the point of this test. We should be allowed to do this action, and it should not fail on permission check - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -610,19 +606,19 @@ class DatabasesCustomClientTest extends Scope 'Rating' => '10', $collection5['body']['$id'] => [ '$id' => ID::custom($collection5['body']['$id']), - 'Rating' => '11' - ] - ] - ] - ] - ] + 'Rating' => '11', + ], + ], + ], + ], + ], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(11, $response['body'][$collection2['body']['$id']]['collection3']['Rating']); // We should not be allowed to update the document as we do not have permission for collection 2. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -632,29 +628,29 @@ class DatabasesCustomClientTest extends Scope '$id' => ID::custom($collection2['body']['$id']), 'Rating' => '11', $collection3['body']['$id'] => null, - ] - ] + ], + ], ]); $this->assertEquals(401, $response['headers']['status-code']); // We should not be allowed to update the document as we do not have permission for collection 2. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/documents/' . $collection2['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection2['body']['$id'].'/documents/'.$collection2['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => [ 'Rating' => '11', - ] + ], ]); $this->assertEquals(401, $response['headers']['status-code']); // Removing update permission from collection 3. - $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/collection3', array_merge([ + $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/collection3', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('collection3'), 'name' => ID::custom('collection3'), @@ -663,14 +659,14 @@ class DatabasesCustomClientTest extends Scope Permission::create(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ] + ], ]); // Giving update permission to collection 2. - $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/collection2', array_merge([ + $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/collection2', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('collection2'), 'name' => ID::custom('collection2'), @@ -680,25 +676,25 @@ class DatabasesCustomClientTest extends Scope Permission::update(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ] + ], ]); // Creating collection 3 new document - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection3['body']['$id'] . '/documents', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection3['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'documentId' => ID::custom('collection3Doc1'), 'data' => [ - 'Rating' => '20' - ] + 'Rating' => '20', + ], ]); $this->assertEquals(201, $response['headers']['status-code']); // We should be allowed to link a new document from collection 3 to collection 2. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -707,15 +703,14 @@ class DatabasesCustomClientTest extends Scope $collection2['body']['$id'] => [ '$id' => ID::custom($collection2['body']['$id']), $collection3['body']['$id'] => 'collection3Doc1', - ] - ] + ], + ], ]); $this->assertEquals(200, $response['headers']['status-code']); - // We should be allowed to link and create a new document from collection 3 to collection 2. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -724,10 +719,10 @@ class DatabasesCustomClientTest extends Scope $collection2['body']['$id'] => [ '$id' => ID::custom($collection2['body']['$id']), $collection3['body']['$id'] => [ - '$id' => ID::custom('collection3Doc2') + '$id' => ID::custom('collection3Doc2'), ], - ] - ] + ], + ], ]); $this->assertEquals(200, $response['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index 648a4de800..57b609c33a 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -3,10 +3,10 @@ namespace Tests\E2E\Services\Databases; use Appwrite\Extend\Exception as AppwriteException; +use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Tests\E2E\Client; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -22,7 +22,7 @@ class DatabasesCustomServerTest extends Scope $test1 = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::custom('first'), 'name' => 'Test 1', @@ -34,7 +34,7 @@ class DatabasesCustomServerTest extends Scope $test2 = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::custom('second'), 'name' => 'Test 2', @@ -124,7 +124,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("' . $base['body']['databases'][0]['$id'] . '")'], + 'queries' => ['cursorAfter("'.$base['body']['databases'][0]['$id'].'")'], ]); $this->assertCount(1, $databases['body']['databases']); @@ -134,7 +134,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("' . $base['body']['databases'][1]['$id'] . '")'], + 'queries' => ['cursorAfter("'.$base['body']['databases'][1]['$id'].'")'], ]); $this->assertCount(0, $databases['body']['databases']); @@ -152,7 +152,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("' . $base['body']['databases'][1]['$id'] . '")'], + 'queries' => ['cursorBefore("'.$base['body']['databases'][1]['$id'].'")'], ]); $this->assertCount(1, $databases['body']['databases']); @@ -162,7 +162,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("' . $base['body']['databases'][0]['$id'] . '")'], + 'queries' => ['cursorBefore("'.$base['body']['databases'][0]['$id'].'")'], ]); $this->assertCount(0, $databases['body']['databases']); @@ -175,7 +175,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'first' + 'search' => 'first', ]); $this->assertEquals(1, $databases['body']['total']); @@ -185,7 +185,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Test' + 'search' => 'Test', ]); $this->assertEquals(2, $databases['body']['total']); @@ -196,7 +196,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Nonexistent' + 'search' => 'Nonexistent', ]); $this->assertEquals(0, $databases['body']['total']); @@ -217,13 +217,14 @@ class DatabasesCustomServerTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Test 1', 'databaseId' => ID::custom('first'), ]); $this->assertEquals(409, $response['headers']['status-code']); + return ['databaseId' => $test1['body']['$id']]; } @@ -236,16 +237,17 @@ class DatabasesCustomServerTest extends Scope /** * Test for SUCCESS */ - $database = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId, [ + $database = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]); $this->assertEquals(200, $database['headers']['status-code']); $this->assertEquals($databaseId, $database['body']['$id']); $this->assertEquals('Test 1', $database['body']['name']); $this->assertEquals(true, $database['body']['enabled']); + return ['databaseId' => $database['body']['$id']]; } @@ -256,10 +258,10 @@ class DatabasesCustomServerTest extends Scope { $databaseId = $data['databaseId']; - $database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, [ + $database = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'name' => 'Test 1 Updated', 'enabled' => false, @@ -270,12 +272,12 @@ class DatabasesCustomServerTest extends Scope $this->assertFalse($database['body']['enabled']); // Now update the database without the passing the enabled parameter - $database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, [ + $database = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'name' => 'Test 1' + 'name' => 'Test 1', ]); $this->assertEquals(200, $database['headers']['status-code']); @@ -290,19 +292,19 @@ class DatabasesCustomServerTest extends Scope { $databaseId = $data['databaseId']; - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEquals("", $response['body']); + $this->assertEquals('', $response['body']); // Try to get the collection and check if it has been deleted - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId, array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $response['headers']['status-code']); @@ -313,7 +315,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -326,10 +328,10 @@ class DatabasesCustomServerTest extends Scope /** * Test for SUCCESS */ - $test1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $test1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Test 1', 'collectionId' => ID::custom('first'), @@ -342,10 +344,10 @@ class DatabasesCustomServerTest extends Scope 'documentSecurity' => true, ]); - $test2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $test2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Test 2', 'collectionId' => ID::custom('second'), @@ -358,7 +360,7 @@ class DatabasesCustomServerTest extends Scope 'documentSecurity' => true, ]); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -371,41 +373,41 @@ class DatabasesCustomServerTest extends Scope $base = array_reverse($collections['body']['collections']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(1)'] + 'queries' => ['limit(1)'], ]); $this->assertEquals(200, $collections['headers']['status-code']); $this->assertCount(1, $collections['body']['collections']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(1)'] + 'queries' => ['offset(1)'], ]); $this->assertEquals(200, $collections['headers']['status-code']); $this->assertCount(1, $collections['body']['collections']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("enabled", true)'] + 'queries' => ['equal("enabled", true)'], ]); $this->assertEquals(200, $collections['headers']['status-code']); $this->assertCount(2, $collections['body']['collections']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("enabled", false)'] + 'queries' => ['equal("enabled", false)'], ]); $this->assertEquals(200, $collections['headers']['status-code']); @@ -414,7 +416,7 @@ class DatabasesCustomServerTest extends Scope /** * Test for Order */ - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -428,26 +430,26 @@ class DatabasesCustomServerTest extends Scope /** * Test for After */ - $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("' . $base['body']['collections'][0]['$id'] . '")'], + 'queries' => ['cursorAfter("'.$base['body']['collections'][0]['$id'].'")'], ]); $this->assertCount(1, $collections['body']['collections']); $this->assertEquals($base['body']['collections'][1]['$id'], $collections['body']['collections'][0]['$id']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("' . $base['body']['collections'][1]['$id'] . '")'], + 'queries' => ['cursorAfter("'.$base['body']['collections'][1]['$id'].'")'], ]); $this->assertCount(0, $collections['body']['collections']); @@ -456,26 +458,26 @@ class DatabasesCustomServerTest extends Scope /** * Test for Before */ - $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("' . $base['body']['collections'][1]['$id'] . '")'], + 'queries' => ['cursorBefore("'.$base['body']['collections'][1]['$id'].'")'], ]); $this->assertCount(1, $collections['body']['collections']); $this->assertEquals($base['body']['collections'][0]['$id'], $collections['body']['collections'][0]['$id']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("' . $base['body']['collections'][0]['$id'] . '")'], + 'queries' => ['cursorBefore("'.$base['body']['collections'][0]['$id'].'")'], ]); $this->assertCount(0, $collections['body']['collections']); @@ -484,32 +486,32 @@ class DatabasesCustomServerTest extends Scope /** * Test for Search */ - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'first' + 'search' => 'first', ]); $this->assertEquals(1, $collections['body']['total']); $this->assertEquals('first', $collections['body']['collections'][0]['$id']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Test' + 'search' => 'Test', ]); $this->assertEquals(2, $collections['body']['total']); $this->assertEquals('Test 1', $collections['body']['collections'][0]['name']); $this->assertEquals('Test 2', $collections['body']['collections'][1]['name']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Nonexistent' + 'search' => 'Nonexistent', ]); $this->assertEquals(0, $collections['body']['total']); @@ -517,7 +519,7 @@ class DatabasesCustomServerTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -527,10 +529,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); // This collection already exists - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Test 1', 'collectionId' => ID::custom('first'), @@ -544,6 +546,7 @@ class DatabasesCustomServerTest extends Scope ]); $this->assertEquals(409, $response['headers']['status-code']); + return [ 'databaseId' => $databaseId, 'collectionId' => $test1['body']['$id'], @@ -558,10 +561,10 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], $this->getHeaders())); $this->assertEquals(200, $collection['headers']['status-code']); @@ -578,13 +581,13 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Test 1 Updated', - 'enabled' => false + 'enabled' => false, ]); $this->assertEquals(200, $collection['headers']['status-code']); @@ -594,11 +597,10 @@ class DatabasesCustomServerTest extends Scope } /** - * @depends testListCollections + * @depends testListCollections */ public function testCreateEncryptedAttribute(array $data): void { - $databaseId = $data['databaseId']; /** @@ -606,10 +608,10 @@ class DatabasesCustomServerTest extends Scope */ // Create collection - $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Encrypted Actors Data', @@ -628,23 +630,22 @@ class DatabasesCustomServerTest extends Scope /** * Test for creating encrypted attributes */ + $attributesPath = '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes'; - $attributesPath = '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes'; - - $firstName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ + $firstName = $this->client->call(Client::METHOD_POST, $attributesPath.'/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'firstName', 'size' => 256, 'required' => true, ]); - $lastName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ + $lastName = $this->client->call(Client::METHOD_POST, $attributesPath.'/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'lastName', 'size' => 256, @@ -652,7 +653,6 @@ class DatabasesCustomServerTest extends Scope 'encrypt' => true, ]); - /** * Check status of every attribute */ @@ -668,10 +668,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Creating document to ensure cache is purged on schema change - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'documentId' => ID::unique(), 'data' => [ @@ -686,10 +686,10 @@ class DatabasesCustomServerTest extends Scope ]); // Check document to ensure cache is purged on schema change - $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents/' . $document['body']['$id'], array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/documents/'.$document['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $document['headers']['status-code']); @@ -702,7 +702,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -716,10 +716,10 @@ class DatabasesCustomServerTest extends Scope */ // Create collection - $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -735,30 +735,30 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(201, $actors['headers']['status-code']); $this->assertEquals($actors['body']['name'], 'Actors'); - $firstName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes/string', array_merge([ + $firstName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'firstName', 'size' => 256, 'required' => true, ]); - $lastName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes/string', array_merge([ + $lastName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'lastName', 'size' => 256, 'required' => true, ]); - $unneeded = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes/string', array_merge([ + $unneeded = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'unneeded', 'size' => 256, @@ -769,16 +769,16 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Creating document to ensure cache is purged on schema change - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'documentId' => ID::unique(), 'data' => [ 'firstName' => 'lorem', 'lastName' => 'ipsum', - 'unneeded' => 'dolor' + 'unneeded' => 'dolor', ], 'permissions' => [ Permission::read(Role::any()), @@ -787,10 +787,10 @@ class DatabasesCustomServerTest extends Scope ], ]); - $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'key_lastName', 'type' => 'key', @@ -802,10 +802,10 @@ class DatabasesCustomServerTest extends Scope // Wait for database worker to finish creating index sleep(2); - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), []); $unneededId = $unneeded['body']['key']; @@ -820,10 +820,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals($collection['body']['indexes'][0]['key'], $index['body']['key']); // Delete attribute - $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actors ['body']['$id'] . '/attributes/' . $unneededId, array_merge([ + $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes/'.$unneededId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(204, $attribute['headers']['status-code']); @@ -831,18 +831,18 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Check document to ensure cache is purged on schema change - $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents/' . $document['body']['$id'], array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/documents/'.$document['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertNotContains($unneededId, $document['body']); - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), []); $this->assertEquals(200, $collection['headers']['status-code']); @@ -854,7 +854,7 @@ class DatabasesCustomServerTest extends Scope return [ 'collectionId' => $actors['body']['$id'], 'key' => $index['body']['key'], - 'databaseId' => $databaseId + 'databaseId' => $databaseId, ]; } @@ -864,10 +864,10 @@ class DatabasesCustomServerTest extends Scope public function testDeleteIndex($data): array { $databaseId = $data['databaseId']; - $index = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/indexes/' . $data['key'], array_merge([ + $index = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/indexes/'.$data['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(204, $index['headers']['status-code']); @@ -875,10 +875,10 @@ class DatabasesCustomServerTest extends Scope // Wait for database worker to finish deleting index sleep(2); - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['collectionId'], array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['collectionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), []); $this->assertCount(0, $collection['body']['indexes']); @@ -892,20 +892,20 @@ class DatabasesCustomServerTest extends Scope public function testDeleteIndexOnDeleteAttribute($data) { $databaseId = $data['databaseId']; - $attribute1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/attributes/string', array_merge([ + $attribute1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'attribute1', 'size' => 16, 'required' => true, ]); - $attribute2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/attributes/string', array_merge([ + $attribute2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'attribute2', 'size' => 16, @@ -919,10 +919,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); - $index1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/indexes', array_merge([ + $index1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'index1', 'type' => 'key', @@ -930,10 +930,10 @@ class DatabasesCustomServerTest extends Scope 'orders' => ['ASC', 'ASC'], ]); - $index2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/indexes', array_merge([ + $index2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'index2', 'type' => 'key', @@ -948,10 +948,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Expected behavior: deleting attribute2 will cause index2 to be dropped, and index1 rebuilt with a single key - $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/attributes/' . $attribute2['body']['key'], array_merge([ + $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/attributes/'.$attribute2['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(204, $deleted['headers']['status-code']); @@ -959,10 +959,10 @@ class DatabasesCustomServerTest extends Scope // wait for database worker to complete sleep(2); - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['collectionId'], array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['collectionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -974,10 +974,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals($attribute1['body']['key'], $collection['body']['indexes'][0]['attributes'][0]); // Delete attribute - $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/attributes/' . $attribute1['body']['key'], array_merge([ + $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/attributes/'.$attribute1['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(204, $deleted['headers']['status-code']); @@ -990,7 +990,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -999,10 +999,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals('invalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'TestCleanupDuplicateIndexOnDeleteAttribute', @@ -1020,20 +1020,20 @@ class DatabasesCustomServerTest extends Scope $collectionId = $collection['body']['$id']; - $attribute1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ + $attribute1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'attribute1', 'size' => 16, 'required' => true, ]); - $attribute2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ + $attribute2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'attribute2', 'size' => 16, @@ -1047,10 +1047,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); - $index1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ + $index1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'index1', 'type' => 'key', @@ -1058,10 +1058,10 @@ class DatabasesCustomServerTest extends Scope 'orders' => ['ASC', 'ASC'], ]); - $index2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ + $index2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'index2', 'type' => 'key', @@ -1076,10 +1076,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Expected behavior: deleting attribute1 would cause index1 to be a duplicate of index2 and automatically removed - $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $attribute1['body']['key'], array_merge([ + $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$attribute1['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(204, $deleted['headers']['status-code']); @@ -1087,10 +1087,10 @@ class DatabasesCustomServerTest extends Scope // wait for database worker to complete sleep(2); - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -1102,10 +1102,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals($attribute2['body']['key'], $collection['body']['indexes'][0]['attributes'][0]); // Delete attribute - $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $attribute2['body']['key'], array_merge([ + $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$attribute2['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(204, $deleted['headers']['status-code']); @@ -1120,7 +1120,7 @@ class DatabasesCustomServerTest extends Scope $collectionId = $data['collectionId']; // Add Documents to the collection - $document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $document1 = $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()), [ @@ -1136,7 +1136,7 @@ class DatabasesCustomServerTest extends Scope ], ]); - $document2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + $document2 = $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()), [ @@ -1165,19 +1165,19 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals($document2['body']['lastName'], 'Jackson'); // Delete the actors collection - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEquals($response['body'], ""); + $this->assertEquals($response['body'], ''); // Try to get the collection and check if it has been deleted - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $response['headers']['status-code']); @@ -1242,7 +1242,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -1251,10 +1251,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals('invalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('attributeRowWidthLimit'), 'name' => 'attributeRowWidthLimit', @@ -1274,10 +1274,10 @@ class DatabasesCustomServerTest extends Scope // Add wide string attributes to approach row width limit for ($i = 0; $i < 15; $i++) { - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => "attribute{$i}", 'size' => 1024, @@ -1289,10 +1289,10 @@ class DatabasesCustomServerTest extends Scope sleep(5); - $tooWide = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ + $tooWide = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'tooWide', 'size' => 1024, @@ -1308,7 +1308,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -1317,10 +1317,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals('invalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('testLimitException'), 'name' => 'testLimitException', @@ -1341,10 +1341,10 @@ class DatabasesCustomServerTest extends Scope // add unique attributes for indexing for ($i = 0; $i < 64; $i++) { // $this->assertEquals(true, static::getDatabase()->createAttribute('indexLimit', "test{$i}", Database::VAR_STRING, 16, true)); - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => "attribute{$i}", 'size' => 64, @@ -1356,10 +1356,10 @@ class DatabasesCustomServerTest extends Scope sleep(10); - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -1370,7 +1370,7 @@ class DatabasesCustomServerTest extends Scope $this->assertCount(0, $collection['body']['indexes']); foreach ($collection['body']['attributes'] as $attribute) { - $this->assertEquals('available', $attribute['status'], 'attribute: ' . $attribute['key']); + $this->assertEquals('available', $attribute['status'], 'attribute: '.$attribute['key']); } // Test indexLimit = 64 @@ -1378,10 +1378,10 @@ class DatabasesCustomServerTest extends Scope // Add up to the limit, then check if the next index throws IndexLimitException for ($i = 0; $i < 59; $i++) { // $this->assertEquals(true, static::getDatabase()->createIndex('indexLimit', "index{$i}", Database::INDEX_KEY, ["test{$i}"], [16])); - $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => "key_attribute{$i}", 'type' => 'key', @@ -1394,10 +1394,10 @@ class DatabasesCustomServerTest extends Scope sleep(5); - $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -1407,10 +1407,10 @@ class DatabasesCustomServerTest extends Scope $this->assertCount(64, $collection['body']['attributes']); $this->assertCount(59, $collection['body']['indexes']); - $tooMany = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ + $tooMany = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'tooMany', 'type' => 'key', @@ -1420,10 +1420,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $tooMany['headers']['status-code']); $this->assertEquals('Index limit exceeded', $tooMany['body']['message']); - $collection = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(204, $collection['headers']['status-code']); @@ -1434,7 +1434,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'updateAttributes', @@ -1442,13 +1442,13 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(201, $database['headers']['status-code']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::custom('updateAttributes'), - 'name' => 'updateAttributes' + 'name' => 'updateAttributes', ]); $this->assertEquals(201, $collection['headers']['status-code']); @@ -1458,14 +1458,14 @@ class DatabasesCustomServerTest extends Scope /** * Create String Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'string', 'size' => 1024, - 'required' => false + 'required' => false, ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1473,13 +1473,13 @@ class DatabasesCustomServerTest extends Scope /** * Create Email Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'email', - 'required' => false + 'required' => false, ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1487,13 +1487,13 @@ class DatabasesCustomServerTest extends Scope /** * Create IP Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'ip', - 'required' => false + 'required' => false, ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1501,13 +1501,13 @@ class DatabasesCustomServerTest extends Scope /** * Create URL Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'url', - 'required' => false + 'required' => false, ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1515,13 +1515,13 @@ class DatabasesCustomServerTest extends Scope /** * Create Integer Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'integer', - 'required' => false + 'required' => false, ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1529,50 +1529,50 @@ class DatabasesCustomServerTest extends Scope /** * Create Float Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'float', - 'required' => false + 'required' => false, ]); /** * Create Boolean Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'boolean', - 'required' => false + 'required' => false, ]); /** * Create Datetime Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'datetime', - 'required' => false + 'required' => false, ]); /** * Create Enum Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'enum', 'required' => false, - 'elements' => ['lorem', 'ipsum'] + 'elements' => ['lorem', 'ipsum'], ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1581,11 +1581,10 @@ class DatabasesCustomServerTest extends Scope return [ 'databaseId' => $databaseId, - 'collectionId' => $collectionId + 'collectionId' => $collectionId, ]; } - /** * @depends testAttributeUpdate */ @@ -1595,72 +1594,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'lorem' + 'default' => 'lorem', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertEquals('lorem', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('lorem', $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => null + 'default' => null, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'ipsum' + 'default' => 'ipsum', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -1669,34 +1668,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => 'i am no boolean', - 'default' => 'dolor' + 'default' => 'dolor', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 123 + 'default' => 123, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, ]); @@ -1704,24 +1703,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'default' => 'ipsum' + 'default' => 'ipsum', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, - 'default' => 'ipsum' + 'default' => 'ipsum', ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -1737,73 +1736,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'torsten@appwrite.io' + 'default' => 'torsten@appwrite.io', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertEquals('torsten@appwrite.io', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('torsten@appwrite.io', $attribute['default']); - - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => null + 'default' => null, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'eldad@appwrite.io' + 'default' => 'eldad@appwrite.io', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -1812,34 +1810,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => 'no boolean', - 'default' => 'torsten@appwrite.io' + 'default' => 'torsten@appwrite.io', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'i am no email' + 'default' => 'i am no email', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, ]); @@ -1847,24 +1845,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'default' => 'ipsum' + 'default' => 'ipsum', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, - 'default' => 'torsten@appwrite.io' + 'default' => 'torsten@appwrite.io', ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -1880,72 +1878,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => '127.0.0.1' + 'default' => '127.0.0.1', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertEquals('127.0.0.1', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('127.0.0.1', $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => null + 'default' => null, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => '192.168.0.1' + 'default' => '192.168.0.1', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -1954,34 +1952,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => 'no boolean', - 'default' => '127.0.0.1' + 'default' => '127.0.0.1', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'i am no ip' + 'default' => 'i am no ip', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, ]); @@ -1989,24 +1987,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'default' => '127.0.0.1' + 'default' => '127.0.0.1', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, - 'default' => '127.0.0.1' + 'default' => '127.0.0.1', ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2022,72 +2020,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'http://appwrite.io' + 'default' => 'http://appwrite.io', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertEquals('http://appwrite.io', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('http://appwrite.io', $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => null + 'default' => null, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'https://appwrite.io' + 'default' => 'https://appwrite.io', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2096,34 +2094,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => 'no boolean', - 'default' => 'https://appwrite.io' + 'default' => 'https://appwrite.io', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'i am no url' + 'default' => 'i am no url', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, ]); @@ -2131,24 +2129,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'default' => 'https://appwrite.io' + 'default' => 'https://appwrite.io', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, - 'default' => 'https://appwrite.io' + 'default' => 'https://appwrite.io', ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2164,23 +2162,23 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 123, 'min' => 0, - 'max' => 1000 + 'max' => 1000, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2188,36 +2186,36 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(0, $new['body']['min']); $this->assertEquals(1000, $new['body']['max']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals(123, $attribute['default']); $this->assertEquals(0, $attribute['min']); $this->assertEquals(1000, $attribute['max']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => null, 'min' => 0, - 'max' => 1000 + 'max' => 1000, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2225,23 +2223,23 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(0, $new['body']['min']); $this->assertEquals(1000, $new['body']['max']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 456, 'min' => 100, - 'max' => 2000 + 'max' => 2000, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2252,66 +2250,66 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => 'no boolean', 'default' => 123, 'min' => 0, - 'max' => 500 + 'max' => 500, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 'i am no integer', 'min' => 0, - 'max' => 500 + 'max' => 500, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 100, 'min' => 'i am no integer', - 'max' => 500 + 'max' => 500, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 100, 'min' => 0, - 'max' => 'i am no integer' + 'max' => 'i am no integer', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 100, @@ -2321,10 +2319,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 100, @@ -2334,10 +2332,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'min' => 0, @@ -2347,10 +2345,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'default' => 50, 'min' => 0, @@ -2360,58 +2358,57 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, 'default' => 50, 'min' => 0, - 'max' => 100 + 'max' => 100, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_DEFAULT_UNSUPPORTED, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 50, 'min' => 55, - 'max' => 100 + 'max' => 100, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 105, 'min' => 50, - 'max' => 100 + 'max' => 100, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 50, 'min' => 200, - 'max' => 100 + 'max' => 100, ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2427,23 +2424,23 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 123.456, 'min' => 0.0, - 'max' => 1000.0 + 'max' => 1000.0, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2451,36 +2448,36 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(0, $new['body']['min']); $this->assertEquals(1000, $new['body']['max']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals(123.456, $attribute['default']); $this->assertEquals(0, $attribute['min']); $this->assertEquals(1000, $attribute['max']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => null, 'min' => 0.0, - 'max' => 1000.0 + 'max' => 1000.0, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2488,23 +2485,23 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(0, $new['body']['min']); $this->assertEquals(1000, $new['body']['max']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 456.789, 'min' => 123.456, - 'max' => 2000.0 + 'max' => 2000.0, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2515,66 +2512,66 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => 'no boolean', 'default' => 123.456, 'min' => 0.0, - 'max' => 1000.0 + 'max' => 1000.0, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 'i am no integer', 'min' => 0.0, - 'max' => 500.0 + 'max' => 500.0, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 123.456, 'min' => 'i am no integer', - 'max' => 500.0 + 'max' => 500.0, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 123.456, 'min' => 0.0, - 'max' => 'i am no integer' + 'max' => 'i am no integer', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 123.456, @@ -2584,10 +2581,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 123.456, @@ -2597,10 +2594,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'min' => 0.0, @@ -2610,10 +2607,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'default' => 123.456, 'min' => 0.0, @@ -2623,58 +2620,57 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, 'default' => 123.456, 'min' => 0.0, - 'max' => 100.0 + 'max' => 100.0, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_DEFAULT_UNSUPPORTED, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 123.456, 'min' => 200.0, - 'max' => 300.0 + 'max' => 300.0, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 123.456, 'min' => 0.0, - 'max' => 100.0 + 'max' => 100.0, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 50.0, 'min' => 200.0, - 'max' => 100.0 + 'max' => 100.0, ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2690,72 +2686,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => true + 'default' => true, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertEquals(true, $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals(true, $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => null + 'default' => null, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => false + 'default' => false, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2764,34 +2760,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => 'no boolean', - 'default' => true + 'default' => true, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'i am no boolean' + 'default' => 'i am no boolean', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, ]); @@ -2799,24 +2795,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'default' => false + 'default' => false, ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, - 'default' => true + 'default' => true, ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2832,72 +2828,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => '1975-06-12 14:12:55+02:00' + 'default' => '1975-06-12 14:12:55+02:00', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertEquals('1975-06-12 14:12:55+02:00', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('1975-06-12 14:12:55+02:00', $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => null + 'default' => null, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => '1965-06-12 14:12:55+02:00' + 'default' => '1965-06-12 14:12:55+02:00', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2906,34 +2902,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => 'no boolean', - 'default' => '1975-06-12 14:12:55+02:00' + 'default' => '1975-06-12 14:12:55+02:00', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, - 'default' => 'i am no datetime' + 'default' => 'i am no datetime', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, ]); @@ -2941,24 +2937,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'default' => '1975-06-12 14:12:55+02:00' + 'default' => '1975-06-12 14:12:55+02:00', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, - 'default' => '1975-06-12 14:12:55+02:00' + 'default' => '1975-06-12 14:12:55+02:00', ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2974,22 +2970,22 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'elements' => ['lorem', 'ipsum', 'dolor'], 'required' => false, - 'default' => 'lorem' + 'default' => 'lorem', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -2999,13 +2995,13 @@ class DatabasesCustomServerTest extends Scope $this->assertContains('ipsum', $new['body']['elements']); $this->assertContains('dolor', $new['body']['elements']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('lorem', $attribute['default']); @@ -3014,22 +3010,22 @@ class DatabasesCustomServerTest extends Scope $this->assertContains('ipsum', $attribute['elements']); $this->assertContains('dolor', $attribute['elements']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'elements' => ['lorem', 'ipsum', 'dolor'], 'required' => false, - 'default' => null + 'default' => null, ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -3039,22 +3035,22 @@ class DatabasesCustomServerTest extends Scope $this->assertContains('ipsum', $new['body']['elements']); $this->assertContains('dolor', $new['body']['elements']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'elements' => ['ipsum', 'dolor'], 'required' => false, - 'default' => 'dolor' + 'default' => 'dolor', ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertFalse($new['body']['required']); @@ -3066,36 +3062,36 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'elements' => [], 'required' => false, - 'default' => 'lorem' + 'default' => 'lorem', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'elements' => ['ipsum', 'dolor'], 'required' => false, - 'default' => 'lorem' + 'default' => 'lorem', ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => 'no boolean', 'default' => 'lorem', @@ -3105,10 +3101,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 123, @@ -3118,10 +3114,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 'lorem', @@ -3131,10 +3127,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => false, 'default' => 'lorem', @@ -3143,10 +3139,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, 'elements' => ['lorem', 'ipsum', 'dolor'], @@ -3155,10 +3151,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'default' => 'lorem', 'elements' => ['lorem', 'ipsum', 'dolor'], @@ -3167,10 +3163,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'required' => true, 'default' => 'lorem', @@ -3192,51 +3188,51 @@ class DatabasesCustomServerTest extends Scope $attributes = [ 'string' => [ 'required' => false, - 'default' => 'ipsum' + 'default' => 'ipsum', ], 'email' => [ 'required' => false, - 'default' => 'eldad@appwrite.io' + 'default' => 'eldad@appwrite.io', ], 'ip' => [ 'required' => false, - 'default' => '127.0.0.1' + 'default' => '127.0.0.1', ], 'url' => [ 'required' => false, - 'default' => 'https://appwrite.io' + 'default' => 'https://appwrite.io', ], 'integer' => [ 'required' => false, 'default' => 5, 'min' => 0, - 'max' => 10 + 'max' => 10, ], 'float' => [ 'required' => false, 'default' => 5.5, 'min' => 0.0, - 'max' => 10.0 + 'max' => 10.0, ], 'datetime' => [ 'required' => false, - 'default' => '1975-06-12 14:12:55+02:00' + 'default' => '1975-06-12 14:12:55+02:00', ], 'enum' => [ 'elements' => ['lorem', 'ipsum', 'dolor'], 'required' => false, - 'default' => 'lorem' - ] + 'default' => 'lorem', + ], ]; foreach ($attributes as $key => $payload) { /** * Check if Database exists */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/i_dont_exist/collections/' . $collectionId . '/attributes/' . $key . '/unknown_' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/i_dont_exist/collections/'.$collectionId.'/attributes/'.$key.'/unknown_'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), $payload); $this->assertEquals(404, $update['headers']['status-code']); @@ -3245,10 +3241,10 @@ class DatabasesCustomServerTest extends Scope /** * Check if Collection exists */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/i_dont_exist/attributes/' . $key . '/unknown_' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/i_dont_exist/attributes/'.$key.'/unknown_'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), $payload); $this->assertEquals(404, $update['headers']['status-code']); @@ -3257,10 +3253,10 @@ class DatabasesCustomServerTest extends Scope /** * Check if Attribute exists */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key . '/unknown_' . $key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key.'/unknown_'.$key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), $payload); $this->assertEquals(404, $update['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php index b1d197f010..7f28097e70 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Databases; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -22,7 +22,7 @@ class DatabasesPermissionsGuestTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'InvalidDocumentDatabase', @@ -31,7 +31,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals('InvalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $publicMovies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ + $publicMovies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Movies', 'permissions' => [ @@ -41,7 +41,7 @@ class DatabasesPermissionsGuestTest extends Scope Permission::delete(Role::any()), ], ]); - $privateMovies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ + $privateMovies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Movies', 'permissions' => [], @@ -51,12 +51,12 @@ class DatabasesPermissionsGuestTest extends Scope $publicCollection = ['id' => $publicMovies['body']['$id']]; $privateCollection = ['id' => $privateMovies['body']['$id']]; - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $publicCollection['id'] . '/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$publicCollection['id'].'/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $privateCollection['id'] . '/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$privateCollection['id'].'/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, @@ -93,14 +93,14 @@ class DatabasesPermissionsGuestTest extends Scope $privateCollectionId = $data['privateCollectionId']; $databaseId = $data['databaseId']; - $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', $this->getServerHeader(), [ + $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', ], 'permissions' => $permissions, ]); - $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents', $this->getServerHeader(), [ + $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', @@ -114,11 +114,11 @@ class DatabasesPermissionsGuestTest extends Scope $roles = Authorization::getRoles(); Authorization::cleanRoles(); - $publicDocuments = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', [ + $publicDocuments = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); - $privateDocuments = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents', [ + $privateDocuments = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -148,20 +148,20 @@ class DatabasesPermissionsGuestTest extends Scope $roles = Authorization::getRoles(); Authorization::cleanRoles(); - $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', [ + $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', - ] + ], ]); $publicDocumentId = $publicResponse['body']['$id']; $this->assertEquals(201, $publicResponse['headers']['status-code']); - $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents', [ + $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -174,7 +174,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(401, $privateResponse['headers']['status-code']); // Create a document in private collection with API key so we can test that update and delete are also not allowed - $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents', $this->getServerHeader(), [ + $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', @@ -184,7 +184,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(201, $privateResponse['headers']['status-code']); $privateDocumentId = $privateResponse['body']['$id']; - $publicDocument = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents/' . $publicDocumentId, [ + $publicDocument = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents/'.$publicDocumentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -196,7 +196,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(200, $publicDocument['headers']['status-code']); $this->assertEquals('Thor: Ragnarok', $publicDocument['body']['title']); - $privateDocument = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents/' . $privateDocumentId, [ + $privateDocument = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents/'.$privateDocumentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -207,14 +207,14 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(401, $privateDocument['headers']['status-code']); - $publicDocument = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents/' . $publicDocumentId, [ + $publicDocument = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents/'.$publicDocumentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(204, $publicDocument['headers']['status-code']); - $privateDocument = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents/' . $privateDocumentId, [ + $privateDocument = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents/'.$privateDocumentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -231,7 +231,7 @@ class DatabasesPermissionsGuestTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'GuestPermissionsWrite', @@ -240,18 +240,18 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals('GuestPermissionsWrite', $database['body']['name']); $databaseId = $database['body']['$id']; - $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ + $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Movies', 'permissions' => [ Permission::create(Role::any()), ], - 'documentSecurity' => true + 'documentSecurity' => true, ]); $moviesId = $movies['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, @@ -259,7 +259,7 @@ class DatabasesPermissionsGuestTest extends Scope sleep(1); - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', [ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -269,7 +269,7 @@ class DatabasesPermissionsGuestTest extends Scope ], 'permissions' => [ Permission::read(Role::any()), - ] + ], ]); $this->assertEquals(201, $document['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsMemberTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsMemberTest.php index 860fb7fb12..73393b7efa 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsMemberTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsMemberTest.php @@ -110,6 +110,7 @@ class DatabasesPermissionsMemberTest extends Scope * Data providers lose object state so explicitly pass [$users, $collections] to each iteration * * @return array + * * @throws \Exception */ public function testSetupDatabase(): array @@ -124,7 +125,7 @@ class DatabasesPermissionsMemberTest extends Scope $databaseId = $db['body']['$id']; - $public = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ + $public = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Movies', 'permissions' => [ @@ -138,14 +139,14 @@ class DatabasesPermissionsMemberTest extends Scope $this->assertEquals(201, $public['headers']['status-code']); $this->collections = ['public' => $public['body']['$id']]; - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $this->collections['public'] . '/attributes/string', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$this->collections['public'].'/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); $this->assertEquals(202, $response['headers']['status-code']); - $private = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ + $private = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Private Movies', 'permissions' => [ @@ -159,14 +160,14 @@ class DatabasesPermissionsMemberTest extends Scope $this->assertEquals(201, $private['headers']['status-code']); $this->collections['private'] = $private['body']['$id']; - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $this->collections['private'] . '/attributes/string', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$this->collections['private'].'/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); $this->assertEquals(202, $response['headers']['status-code']); - $doconly = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ + $doconly = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Document Only Movies', 'permissions' => [], @@ -175,7 +176,7 @@ class DatabasesPermissionsMemberTest extends Scope $this->assertEquals(201, $private['headers']['status-code']); $this->collections['doconly'] = $doconly['body']['$id']; - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $this->collections['doconly'] . '/attributes/string', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$this->collections['doconly'].'/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, @@ -187,12 +188,13 @@ class DatabasesPermissionsMemberTest extends Scope return [ 'users' => $this->users, 'collections' => $this->collections, - 'databaseId' => $databaseId + 'databaseId' => $databaseId, ]; } /** * Data provider params are passed before test dependencies + * * @dataProvider permissionsProvider * @depends testSetupDatabase */ @@ -202,41 +204,41 @@ class DatabasesPermissionsMemberTest extends Scope $collections = $data['collections']; $databaseId = $data['databaseId']; - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collections['public'] . '/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collections['public'].'/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', ], - 'permissions' => $permissions + 'permissions' => $permissions, ]); $this->assertEquals(201, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collections['private'] . '/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collections['private'].'/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', ], - 'permissions' => $permissions + 'permissions' => $permissions, ]); $this->assertEquals(201, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collections['doconly'] . '/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collections['doconly'].'/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', ], - 'permissions' => $permissions + 'permissions' => $permissions, ]); $this->assertEquals(201, $response['headers']['status-code']); /** * Check "any" permission collection */ - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collections['public'] . '/documents', [ + $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collections['public'].'/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users['user1']['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users['user1']['session'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -245,11 +247,11 @@ class DatabasesPermissionsMemberTest extends Scope /** * Check "users" permission collection */ - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collections['private'] . '/documents', [ + $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collections['private'].'/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users['user1']['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users['user1']['session'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -258,11 +260,11 @@ class DatabasesPermissionsMemberTest extends Scope /** * Check "user:user1" document only permission collection */ - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collections['doconly'] . '/documents', [ + $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collections['doconly'].'/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users['user1']['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users['user1']['session'], ]); $this->assertEquals(200, $documents['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsScope.php b/tests/e2e/Services/Databases/DatabasesPermissionsScope.php index 181231adc5..a78153cf7d 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsScope.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsScope.php @@ -7,6 +7,7 @@ use Tests\E2E\Client; trait DatabasesPermissionsScope { public array $users = []; + public array $teams = []; public function createUser(string $id, string $email, string $password = 'test123!'): array @@ -18,7 +19,7 @@ trait DatabasesPermissionsScope ], [ 'userId' => $id, 'email' => $email, - 'password' => $password + 'password' => $password, ]); $this->assertEquals(201, $user['headers']['status-code']); @@ -32,7 +33,7 @@ trait DatabasesPermissionsScope 'password' => $password, ]); - $session = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $user = [ '$id' => $user['body']['$id'], @@ -53,7 +54,7 @@ trait DatabasesPermissionsScope { $team = $this->client->call(Client::METHOD_POST, '/teams', $this->getServerHeader(), [ 'teamId' => $id, - 'name' => $name + 'name' => $name, ]); $this->teams[$id] = $team['body']; @@ -62,16 +63,16 @@ trait DatabasesPermissionsScope public function addToTeam(string $user, string $team, array $roles = []): array { - $membership = $this->client->call(Client::METHOD_POST, '/teams/' . $team . '/memberships', $this->getServerHeader(), [ + $membership = $this->client->call(Client::METHOD_POST, '/teams/'.$team.'/memberships', $this->getServerHeader(), [ 'teamId' => $team, 'email' => $this->getCreatedUser($user)['email'], 'roles' => $roles, - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); return [ 'user' => $membership['body']['userId'], - 'membership' => $membership['body']['$id'] + 'membership' => $membership['body']['$id'], ]; } @@ -80,7 +81,7 @@ trait DatabasesPermissionsScope return [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]; } } diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php index dcbf3e4bff..e592902ab8 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Databases; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -17,6 +17,7 @@ class DatabasesPermissionsTeamTest extends Scope use DatabasesPermissionsScope; public array $collections = []; + public string $databaseId = 'testpermissiondb'; public function createTeams(): array @@ -44,7 +45,7 @@ class DatabasesPermissionsTeamTest extends Scope ]); $this->assertEquals(201, $db['headers']['status-code']); - $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections', $this->getServerHeader(), [ + $collection1 = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections', $this->getServerHeader(), [ 'collectionId' => ID::custom('collection1'), 'name' => 'Collection 1', 'permissions' => [ @@ -57,13 +58,13 @@ class DatabasesPermissionsTeamTest extends Scope $this->collections['collection1'] = $collection1['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $this->collections['collection1'] . '/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$this->collections['collection1'].'/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); - $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections', $this->getServerHeader(), [ + $collection2 = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections', $this->getServerHeader(), [ 'collectionId' => ID::custom('collection2'), 'name' => 'Collection 2', 'permissions' => [ @@ -71,12 +72,12 @@ class DatabasesPermissionsTeamTest extends Scope Permission::create(Role::team($teams['team2']['$id'], 'owner')), Permission::update(Role::team($teams['team2']['$id'], 'owner')), Permission::delete(Role::team($teams['team2']['$id'], 'owner')), - ] + ], ]); $this->collections['collection2'] = $collection2['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $this->collections['collection2'] . '/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$this->collections['collection2'].'/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, @@ -124,6 +125,7 @@ class DatabasesPermissionsTeamTest extends Scope * * Data providers lose object state * so explicitly pass $users to each iteration + * * @return array $users */ public function testSetupDatabase(): array @@ -140,7 +142,7 @@ class DatabasesPermissionsTeamTest extends Scope $this->createCollections($this->teams); - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $this->collections['collection1'] . '/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$this->collections['collection1'].'/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', @@ -148,7 +150,7 @@ class DatabasesPermissionsTeamTest extends Scope ]); $this->assertEquals(201, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $this->collections['collection2'] . '/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$this->collections['collection2'].'/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Ipsum', @@ -161,16 +163,17 @@ class DatabasesPermissionsTeamTest extends Scope /** * Data provider params are passed before test dependencies + * * @depends testSetupDatabase * @dataProvider readDocumentsProvider */ public function testReadDocuments($user, $collection, $success, $users) { - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $this->databaseId . '/collections/' . $collection . '/documents', [ + $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$this->databaseId.'/collections/'.$collection.'/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users[$user]['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users[$user]['session'], ]); if ($success) { @@ -186,11 +189,11 @@ class DatabasesPermissionsTeamTest extends Scope */ public function testWriteDocuments($user, $collection, $success, $users) { - $documents = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $collection . '/documents', [ + $documents = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$collection.'/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users[$user]['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users[$user]['session'], ], [ 'documentId' => ID::unique(), 'data' => [ diff --git a/tests/e2e/Services/Functions/FunctionsBase.php b/tests/e2e/Services/Functions/FunctionsBase.php index c45ebbe068..ad41ab7e47 100644 --- a/tests/e2e/Services/Functions/FunctionsBase.php +++ b/tests/e2e/Services/Functions/FunctionsBase.php @@ -8,11 +8,12 @@ use Utopia\CLI\Console; trait FunctionsBase { protected string $stdout = ''; + protected string $stderr = ''; protected function packageCode($folder) { - Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr); + Console::execute('cd '.realpath(__DIR__.'/../../../resources/functions')."/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr); } // /** diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php index e28bdd233f..fec65fd3b9 100644 --- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php @@ -2,9 +2,9 @@ namespace Tests\E2E\Services\Functions; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; @@ -41,13 +41,13 @@ class FunctionsConsoleClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test Failure', 'execute' => ['some-random-string'], - 'runtime' => 'php-8.0' + 'runtime' => 'php-8.0', ]); $this->assertEquals(400, $response['headers']['status-code']); return [ - 'functionId' => $function['body']['$id'] + 'functionId' => $function['body']['$id'], ]; } @@ -59,21 +59,20 @@ class FunctionsConsoleClientTest extends Scope /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '232h' + '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'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '24h' + 'range' => '24h', ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -81,12 +80,11 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '24h' + 'range' => '24h', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -109,13 +107,12 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - - $response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([ + $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' + 'value' => 'TESTINGVALUE', ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -124,13 +121,12 @@ class FunctionsConsoleClientTest extends Scope /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([ + $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' + 'value' => 'ANOTHER_TESTINGVALUE', ]); $this->assertEquals(409, $response['headers']['status-code']); @@ -138,28 +134,28 @@ class FunctionsConsoleClientTest extends Scope return array_merge( $data, [ - 'variableId' => $variableId + 'variableId' => $variableId, ] ); - $longKey = str_repeat("A", 256); - $response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([ + $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' + '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([ + $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 + 'value' => $longValue, ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -173,17 +169,16 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(1, sizeof($response['body']['variables'])); + $this->assertEquals(1, count($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']); + $this->assertEquals('APP_TEST', $response['body']['variables'][0]['key']); + $this->assertEquals('TESTINGVALUE', $response['body']['variables'][0]['value']); /** * Test for FAILURE @@ -200,21 +195,19 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals("APP_TEST", $response['body']['key']); - $this->assertEquals("TESTINGVALUE", $response['body']['value']); + $this->assertEquals('APP_TEST', $response['body']['key']); + $this->assertEquals('TESTINGVALUE', $response['body']['value']); /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/NON_EXISTING_VARIABLE', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables/NON_EXISTING_VARIABLE', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -232,29 +225,28 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - - $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'key' => 'APP_TEST_UPDATE', - 'value' => 'TESTINGVALUEUPDATED' + 'value' => 'TESTINGVALUEUPDATED', ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals("APP_TEST_UPDATE", $response['body']['key']); - $this->assertEquals("TESTINGVALUEUPDATED", $response['body']['value']); + $this->assertEquals('APP_TEST_UPDATE', $response['body']['key']); + $this->assertEquals('TESTINGVALUEUPDATED', $response['body']['value']); - $variable = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $variable = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $variable['headers']['status-code']); - $this->assertEquals("APP_TEST_UPDATE", $variable['body']['key']); - $this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']); + $this->assertEquals('APP_TEST_UPDATE', $variable['body']['key']); + $this->assertEquals('TESTINGVALUEUPDATED', $variable['body']['value']); - $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -262,56 +254,55 @@ class FunctionsConsoleClientTest extends Scope ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals("APP_TEST_UPDATE_2", $response['body']['key']); - $this->assertEquals("TESTINGVALUEUPDATED", $response['body']['value']); + $this->assertEquals('APP_TEST_UPDATE_2', $response['body']['key']); + $this->assertEquals('TESTINGVALUEUPDATED', $response['body']['value']); - $variable = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $variable = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $variable['headers']['status-code']); - $this->assertEquals("APP_TEST_UPDATE_2", $variable['body']['key']); - $this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']); + $this->assertEquals('APP_TEST_UPDATE_2', $variable['body']['key']); + $this->assertEquals('TESTINGVALUEUPDATED', $variable['body']['value']); /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'value' => 'TESTINGVALUEUPDATED_2' + 'value' => 'TESTINGVALUEUPDATED_2', ]); $this->assertEquals(400, $response['headers']['status-code']); - $longKey = str_repeat("A", 256); - $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $longKey = str_repeat('A', 256); + $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'key' => $longKey, - 'value' => 'TESTINGVALUEUPDATED' + 'value' => 'TESTINGVALUEUPDATED', ]); $this->assertEquals(400, $response['headers']['status-code']); - $longValue = str_repeat("#", 8193); - $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $longValue = str_repeat('#', 8193); + $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'key' => 'APP_TEST_UPDATE', - 'value' => $longValue + 'value' => $longValue, ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -327,28 +318,26 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(0, sizeof($response['body']['variables'])); + $this->assertEquals(0, count($response['body']['variables'])); $this->assertEquals(0, $response['body']['total']); /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/variables/NON_EXISTING_VARIABLE', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'].'/variables/NON_EXISTING_VARIABLE', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php index 713814e17f..b92308d348 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php @@ -65,7 +65,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/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'], @@ -74,7 +74,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/variables', [ + $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'], @@ -83,7 +83,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/variables', [ + $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'], @@ -97,17 +97,17 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $variable3['headers']['status-code']); $folder = 'php'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $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/'.$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 + 'activate' => true, ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -117,7 +117,7 @@ class FunctionsCustomClientTest extends Scope // Wait for deployment to be built. sleep(20); - $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $function['body']['$id'] . '/deployments/' . $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'], @@ -125,7 +125,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(200, $function['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', [ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -134,7 +134,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(401, $execution['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([ + $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()), [ @@ -144,7 +144,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(202, $execution['headers']['status-code']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $function['body']['$id'], [ + $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'], @@ -180,7 +180,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ + $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -189,7 +189,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ + $variable2 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -198,7 +198,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ + $variable3 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -212,17 +212,17 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $variable3['headers']['status-code']); $folder = 'php-fn'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [ + $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional - 'activate' => true + 'activate' => true, ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -232,7 +232,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); - $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [ + $function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -240,12 +240,12 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(200, $function['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true + 'async' => true, ]); $this->assertEquals(202, $execution['headers']['status-code']); @@ -254,7 +254,7 @@ class FunctionsCustomClientTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -277,7 +277,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals($projectId, $output['APPWRITE_FUNCTION_PROJECT_ID']); return [ - 'functionId' => $functionId + 'functionId' => $functionId, ]; } @@ -311,17 +311,17 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); $folder = 'php-fn'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [ + $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional - 'activate' => true + 'activate' => true, ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -332,7 +332,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); // Why do we have to do this? - $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [ + $function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -340,7 +340,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(200, $function['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', [ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], [ @@ -365,7 +365,7 @@ class FunctionsCustomClientTest extends Scope 'timeout' => 10, ]); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', [ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -386,19 +386,19 @@ class FunctionsCustomClientTest extends Scope $projectId = $this->getProject()['$id']; $apikey = $this->getProject()['apiKey']; - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true + 'async' => true, ]); $this->assertEquals(202, $execution['headers']['status-code']); sleep(20); - $base = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ + $base = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -409,71 +409,71 @@ class FunctionsCustomClientTest extends Scope $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', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => [ 'limit(1)' ] + 'queries' => ['limit(1)'], ]); $this->assertEquals(200, $executions['headers']['status-code']); $this->assertCount(1, $executions['body']['executions']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => [ 'offset(1)' ] + 'queries' => ['offset(1)'], ]); $this->assertEquals(200, $executions['headers']['status-code']); $this->assertCount(1, $executions['body']['executions']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => [ 'equal("status", ["completed"])' ] + 'queries' => ['equal("status", ["completed"])'], ]); $this->assertEquals(200, $executions['headers']['status-code']); $this->assertCount(2, $executions['body']['executions']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => [ 'equal("status", ["failed"])' ] + 'queries' => ['equal("status", ["failed"])'], ]); $this->assertEquals(200, $executions['headers']['status-code']); $this->assertCount(0, $executions['body']['executions']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => [ 'cursorAfter("' . $base['body']['executions'][0]['$id'] . '")' ], + 'queries' => ['cursorAfter("'.$base['body']['executions'][0]['$id'].'")'], ]); $this->assertCount(1, $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', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => [ 'cursorBefore("' . $base['body']['executions'][1]['$id'] . '")' ], + 'queries' => ['cursorBefore("'.$base['body']['executions'][1]['$id'].'")'], ]); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ + $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'], @@ -487,7 +487,6 @@ class FunctionsCustomClientTest extends Scope /** * Test for SUCCESS */ - $projectId = $this->getProject()['$id']; $apikey = $this->getProject()['apiKey']; @@ -508,7 +507,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ + $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -517,7 +516,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ + $variable2 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -526,7 +525,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ + $variable3 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -540,17 +539,17 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $variable3['headers']['status-code']); $folder = 'php-fn'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [ + $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional - 'activate' => true + 'activate' => true, ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -560,7 +559,7 @@ class FunctionsCustomClientTest extends Scope // Wait for deployment to be built. sleep(20); - $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [ + $function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -568,7 +567,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(200, $function['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ @@ -596,7 +595,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEmpty($execution['body']['stderr']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ + $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'], diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index ab931f14e4..6ad1e578cb 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -8,7 +8,6 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -56,7 +55,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(10, $response1['body']['timeout']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -64,7 +63,7 @@ class FunctionsCustomServerTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ + $variable2 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -72,7 +71,7 @@ class FunctionsCustomServerTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ + $variable3 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -109,7 +108,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => $data['functionId'] + 'search' => $data['functionId'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -120,7 +119,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'limit(1)' ] + 'queries' => ['limit(1)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -130,7 +129,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'offset(1)' ] + 'queries' => ['offset(1)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -140,7 +139,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("enabled", true)' ] + 'queries' => ['equal("enabled", true)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -150,7 +149,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("enabled", false)' ] + 'queries' => ['equal("enabled", false)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -160,7 +159,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Test' + 'search' => 'Test', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -171,7 +170,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'php-8.0' + 'search' => 'php-8.0', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -198,7 +197,7 @@ class FunctionsCustomServerTest extends Scope $this->assertNotEmpty($response['body']['$id']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $response['body']['$id'] . '/variables', array_merge([ + $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()), [ @@ -206,7 +205,7 @@ class FunctionsCustomServerTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $response['body']['$id'] . '/variables', array_merge([ + $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()), [ @@ -214,7 +213,7 @@ class FunctionsCustomServerTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $response['body']['$id'] . '/variables', array_merge([ + $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()), [ @@ -242,7 +241,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'cursorAfter("' . $functions['body']['functions'][0]['$id'] . '")' ], + 'queries' => ['cursorAfter("'.$functions['body']['functions'][0]['$id'].'")'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -253,7 +252,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'cursorBefore("' . $functions['body']['functions'][1]['$id'] . '")' ], + 'queries' => ['cursorBefore("'.$functions['body']['functions'][1]['$id'].'")'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -267,7 +266,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'cursorAfter("unknown")' ], + 'queries' => ['cursorAfter("unknown")'], ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -283,7 +282,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'], array_merge([ + $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -312,7 +311,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $response1 = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([ + $response1 = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -355,16 +354,16 @@ class FunctionsCustomServerTest extends Scope * Test for SUCCESS */ $folder = 'php'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge([ + $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()), [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), - 'activate' => true + 'activate' => true, ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -388,31 +387,30 @@ class FunctionsCustomServerTest extends Scope /** * Test for Large Code File SUCCESS */ - $folder = 'php-large'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); $chunkSize = 5 * 1024 * 1024; - $handle = @fopen($code, "rb"); + $handle = @fopen($code, 'rb'); $mimeType = 'application/x-gzip'; $counter = 0; $size = filesize($code); $headers = [ 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ]; $id = ''; - while (!feof($handle)) { - $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'php-large-fx.tar.gz'); - $headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size; - if (!empty($id)) { + while (! feof($handle)) { + $curlFile = new \CURLFile('data://'.$mimeType.';base64,'.base64_encode(@fread($handle, $chunkSize)), $mimeType, 'php-large-fx.tar.gz'); + $headers['content-range'] = 'bytes '.($counter * $chunkSize).'-'.min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1).'/'.$size; + 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/'.$data['functionId'].'/deployments', array_merge($headers, $this->getHeaders()), [ 'entrypoint' => 'index.php', 'code' => $curlFile, - 'activate' => true + 'activate' => true, ]); $counter++; $id = $largeTag['body']['$id']; @@ -436,7 +434,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([ + $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'], ], $this->getHeaders()), []); @@ -463,7 +461,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([ + $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())); @@ -476,11 +474,11 @@ class FunctionsCustomServerTest extends Scope /** * Test search queries */ - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([ + $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'] + 'search' => $data['functionId'], ])); $this->assertEquals($function['headers']['status-code'], 200); @@ -489,51 +487,51 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(2, $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([ + $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()), [ - 'queries' => [ 'limit(1)' ] + 'queries' => ['limit(1)'], ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertCount(1, $function['body']['deployments']); - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([ + $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()), [ - 'queries' => [ 'offset(1)' ] + 'queries' => ['offset(1)'], ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertCount(1, $function['body']['deployments']); - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([ + $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()), [ - 'queries' => [ 'equal("entrypoint", "index.php")' ] + 'queries' => ['equal("entrypoint", "index.php")'], ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertCount(2, $function['body']['deployments']); - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([ + $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()), [ - 'queries' => [ 'equal("entrypoint", "index.js")' ] + 'queries' => ['equal("entrypoint", "index.js")'], ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertCount(0, $function['body']['deployments']); - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([ + $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' + 'search' => 'Test', ])); $this->assertEquals($function['headers']['status-code'], 200); @@ -542,11 +540,11 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(2, $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([ + $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' + 'search' => 'php-8.0', ])); $this->assertEquals($function['headers']['status-code'], 200); @@ -566,7 +564,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([ + $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())); @@ -580,7 +578,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for FAILURE */ - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/x', array_merge([ + $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())); @@ -598,7 +596,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([ + $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()), [ @@ -620,7 +618,7 @@ class FunctionsCustomServerTest extends Scope sleep(10); - $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/' . $executionId, array_merge([ + $execution = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions/'.$executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -644,7 +642,6 @@ class FunctionsCustomServerTest extends Scope /** * Test for FAILURE */ - sleep(20); return array_merge($data, ['executionId' => $executionId]); @@ -658,7 +655,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([ + $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())); @@ -669,31 +666,31 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(1, $function['body']['executions']); $this->assertEquals($function['body']['executions'][0]['$id'], $data['executionId']); - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([ + $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()), [ - 'queries' => [ 'limit(1)' ] + 'queries' => ['limit(1)'], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']['executions']); - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([ + $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()), [ - 'queries' => [ 'offset(1)' ] + 'queries' => ['offset(1)'], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(0, $response['body']['executions']); - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([ + $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()), [ - 'queries' => [ 'equal("trigger", "http")' ] + 'queries' => ['equal("trigger", "http")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -702,8 +699,7 @@ class FunctionsCustomServerTest extends Scope /** * Test search queries */ - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([ + $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()), [ @@ -716,7 +712,7 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(1, $response['body']['executions']); $this->assertEquals($data['functionId'], $response['body']['executions'][0]['functionId']); - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([ + $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()), [ @@ -741,7 +737,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([ + $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()), [ @@ -769,7 +765,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/' . $data['executionId'], array_merge([ + $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())); @@ -780,7 +776,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for FAILURE */ - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/x', array_merge([ + $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())); @@ -798,7 +794,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([ + $function = $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())); @@ -806,7 +802,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(204, $function['headers']['status-code']); $this->assertEmpty($function['body']); - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([ + $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())); @@ -828,7 +824,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'], array_merge([ + $function = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -836,7 +832,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(204, $function['headers']['status-code']); $this->assertEmpty($function['body']); - $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'], array_merge([ + $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -856,7 +852,7 @@ class FunctionsCustomServerTest extends Scope $entrypoint = 'index.php'; $timeout = 2; $folder = 'timeout'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ @@ -864,7 +860,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test ' . $name, + 'name' => 'Test '.$name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -874,7 +870,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([ + $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()), [ @@ -888,7 +884,7 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(40); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -901,7 +897,7 @@ class FunctionsCustomServerTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -920,7 +916,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals($executions['body']['executions'][0]['stderr'], 'An internal curl error has occurred within the executor! Error Msg: Operation timed out'); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ + $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'], @@ -938,7 +934,7 @@ class FunctionsCustomServerTest extends Scope $entrypoint = 'index.php'; $timeout = 2; $folder = 'php-fn'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ @@ -946,7 +942,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test ' . $name, + 'name' => 'Test '.$name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -956,13 +952,13 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([ + $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)), - 'activate' => true + 'activate' => true, ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -971,19 +967,19 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(20); - $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([ + $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([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true + 'async' => true, ]); $executionId = $execution['body']['$id'] ?? ''; @@ -994,7 +990,7 @@ class FunctionsCustomServerTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1004,7 +1000,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $executions['headers']['status-code']); $this->assertEquals('completed', $executions['body']['status']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); + $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); $this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); @@ -1017,7 +1013,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); $this->assertStringContainsString('Amazing Function Log', $executions['body']['stdout']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1031,7 +1027,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ + $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'], @@ -1040,12 +1036,11 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } - public function testCreateCustomNodeExecution() { $name = 'node-18.0'; $folder = 'node'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); $entrypoint = 'index.js'; @@ -1056,7 +1051,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test ' . $name, + 'name' => 'Test '.$name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -1067,7 +1062,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); // Create variable - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1077,7 +1072,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $variable['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([ + $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()), [ @@ -1092,12 +1087,12 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(20); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true + 'async' => true, ]); $executionId = $execution['body']['$id'] ?? ''; @@ -1108,7 +1103,7 @@ class FunctionsCustomServerTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1118,7 +1113,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $executions['headers']['status-code']); $this->assertEquals('completed', $executions['body']['status']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); + $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); $this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); @@ -1130,7 +1125,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1144,7 +1139,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ + $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'], @@ -1157,7 +1152,7 @@ class FunctionsCustomServerTest extends Scope { $name = 'python-3.9'; $folder = 'python'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); $entrypoint = 'main.py'; @@ -1168,7 +1163,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test ' . $name, + 'name' => 'Test '.$name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -1179,7 +1174,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1189,7 +1184,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $variable['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([ + $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()), [ @@ -1204,12 +1199,12 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(60); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true + 'async' => true, ]); $executionId = $execution['body']['$id'] ?? ''; @@ -1220,7 +1215,7 @@ class FunctionsCustomServerTest extends Scope sleep(60); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1230,7 +1225,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $executions['headers']['status-code']); $this->assertEquals('completed', $executions['body']['status']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); + $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); $this->assertEquals('Python', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); @@ -1243,7 +1238,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1257,7 +1252,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ + $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'], @@ -1383,7 +1378,7 @@ class FunctionsCustomServerTest extends Scope { $name = 'ruby-3.1'; $folder = 'ruby'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); $entrypoint = 'main.rb'; @@ -1394,7 +1389,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test ' . $name, + 'name' => 'Test '.$name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -1405,7 +1400,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1415,7 +1410,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $variable['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([ + $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()), [ @@ -1430,12 +1425,12 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(60); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true + 'async' => true, ]); $executionId = $execution['body']['$id'] ?? ''; @@ -1446,7 +1441,7 @@ class FunctionsCustomServerTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1456,7 +1451,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $executions['headers']['status-code']); $this->assertEquals('completed', $executions['body']['status']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); + $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); $this->assertEquals('Ruby', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); @@ -1468,7 +1463,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1482,7 +1477,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ + $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'], diff --git a/tests/e2e/Services/GraphQL/AbuseTest.php b/tests/e2e/Services/GraphQL/AbuseTest.php index 48ee64d141..163f695811 100644 --- a/tests/e2e/Services/GraphQL/AbuseTest.php +++ b/tests/e2e/Services/GraphQL/AbuseTest.php @@ -92,7 +92,7 @@ class AbuseTest extends Scope $max = App::getEnv('_APP_GRAPHQL_MAX_QUERY_COMPLEXITY', 250); - $this->assertEquals('Max query complexity should be ' . $max . ' but got 259.', $response['body']['errors'][0]['message']); + $this->assertEquals('Max query complexity should be '.$max.' but got 259.', $response['body']['errors'][0]['message']); } public function testTooManyQueriesBlocked() @@ -122,7 +122,7 @@ class AbuseTest extends Scope 'variables' => [ 'databaseId' => 'actors', 'name' => 'AbuseDatabase', - ] + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -145,7 +145,7 @@ class AbuseTest extends Scope Permission::read(Role::any()), Permission::write(Role::any()), ], - ] + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -165,7 +165,7 @@ class AbuseTest extends Scope 'key' => 'name', 'size' => 256, 'required' => true, - ] + ], ]; $this->client->call(Client::METHOD_POST, '/graphql', [ diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 7fd70b5015..c77773cba9 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -18,7 +18,7 @@ class AccountTest extends Scope { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_ACCOUNT); - $email = 'test' . \rand() . '@test.com'; + $email = 'test'.\rand().'@test.com'; $graphQLPayload = [ 'query' => $query, 'variables' => [ @@ -51,7 +51,7 @@ class AccountTest extends Scope 'variables' => [ 'email' => $this->getUser()['email'], 'password' => 'password', - ] + ], ]; $session = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -63,7 +63,7 @@ class AccountTest extends Scope $this->assertIsArray($session['body']['data']); $this->assertIsArray($session['body']['data']['accountCreateEmailSession']); - $cookie = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $cookie = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $this->assertNotEmpty($cookie); } @@ -71,13 +71,13 @@ class AccountTest extends Scope { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_MAGIC_URL); - $email = 'test' . \rand() . '@test.com'; + $email = 'test'.\rand().'@test.com'; $graphQLPayload = [ 'query' => $query, 'variables' => [ 'userId' => ID::unique(), 'email' => $email, - ] + ], ]; $session = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -99,7 +99,7 @@ class AccountTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'url' => 'http://localhost/verification' + 'url' => 'http://localhost/verification', ], ]; @@ -117,7 +117,9 @@ class AccountTest extends Scope /** * @depends testUpdateAccountPhone + * * @return array + * * @throws \Exception */ public function testCreatePhoneVerification(): array @@ -274,7 +276,7 @@ class AccountTest extends Scope 'query' => $query, 'variables' => [ 'sessionId' => 'current', - ] + ], ]; $session = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -317,8 +319,8 @@ class AccountTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'name' => 'Tester Updated' - ] + 'name' => 'Tester Updated', + ], ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -343,7 +345,7 @@ class AccountTest extends Scope 'variables' => [ 'email' => 'newemail@appwrite.io', 'password' => 'password', - ] + ], ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -368,7 +370,7 @@ class AccountTest extends Scope 'variables' => [ 'oldPassword' => 'password', 'password' => 'password', - ] + ], ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -392,7 +394,7 @@ class AccountTest extends Scope 'variables' => [ 'phone' => '+123456789', 'password' => 'password', - ] + ], ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -440,9 +442,9 @@ class AccountTest extends Scope 'query' => $query, 'variables' => [ 'prefs' => [ - 'key' => 'value' - ] - ] + 'key' => 'value', + ], + ], ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -463,7 +465,7 @@ class AccountTest extends Scope $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$DELETE_ACCOUNT_SESSIONS); $graphQLPayload = [ - 'query' => $query + 'query' => $query, ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -488,7 +490,7 @@ class AccountTest extends Scope 'query' => $query, 'variables' => [ 'sessionId' => 'current', - ] + ], ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/AuthTest.php b/tests/e2e/Services/GraphQL/AuthTest.php index c331fb8437..63177ee3bc 100644 --- a/tests/e2e/Services/GraphQL/AuthTest.php +++ b/tests/e2e/Services/GraphQL/AuthTest.php @@ -7,8 +7,8 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; -use Utopia\Database\Helpers\Role; use Utopia\Database\Helpers\Permission; +use Utopia\Database\Helpers\Role; class AuthTest extends Scope { @@ -17,12 +17,15 @@ class AuthTest extends Scope use Base; private array $account1; + private array $account2; private string $token1; + private string $token2; private array $database; + private array $collection; public function setUp(): void @@ -32,8 +35,8 @@ class AuthTest extends Scope $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_ACCOUNT); - $email1 = 'test' . \rand() . '@test.com'; - $email2 = 'test' . \rand() . '@test.com'; + $email1 = 'test'.\rand().'@test.com'; + $email2 = 'test'.\rand().'@test.com'; // Create account 1 $graphQLPayload = [ @@ -66,7 +69,7 @@ class AuthTest extends Scope 'variables' => [ 'email' => $email1, 'password' => 'password', - ] + ], ]; $session1 = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', @@ -74,8 +77,8 @@ class AuthTest extends Scope ], $graphQLPayload); $this->token1 = $this->client->parseCookie( - (string)$session1['headers']['set-cookie'] - )['a_session_' . $projectId]; + (string) $session1['headers']['set-cookie'] + )['a_session_'.$projectId]; // Create session 2 $graphQLPayload['variables']['email'] = $email2; @@ -86,8 +89,8 @@ class AuthTest extends Scope ], $graphQLPayload); $this->token2 = $this->client->parseCookie( - (string)$session2['headers']['set-cookie'] - )['a_session_' . $projectId]; + (string) $session2['headers']['set-cookie'] + )['a_session_'.$projectId]; // Create database $query = $this->getQuery(self::$CREATE_DATABASE); @@ -96,7 +99,7 @@ class AuthTest extends Scope 'variables' => [ 'databaseId' => ID::unique(), 'name' => 'Actors', - ] + ], ]; $this->database = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', @@ -115,9 +118,9 @@ class AuthTest extends Scope 'name' => 'Actors', 'documentSecurity' => true, 'permissions' => [ - Permission::create(Role::user($userId)) - ] - ] + Permission::create(Role::user($userId)), + ], + ], ]; $this->collection = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', @@ -135,7 +138,7 @@ class AuthTest extends Scope 'key' => 'name', 'size' => 256, 'required' => true, - ] + ], ]; $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', @@ -166,13 +169,13 @@ class AuthTest extends Scope Permission::read(Role::user($userId)), Permission::update(Role::user($userId)), Permission::delete(Role::user($userId)), - ] - ] + ], + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $this->token1, + 'cookie' => 'a_session_'.$projectId.'='.$this->token1, ], $gqlPayload); // Try to read as account 1 @@ -183,12 +186,12 @@ class AuthTest extends Scope 'databaseId' => $this->database['body']['data']['databasesCreate']['_id'], 'collectionId' => $this->collection['body']['data']['databasesCreateCollection']['_id'], 'documentId' => $document['body']['data']['databasesCreateDocument']['_id'], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $this->token1, + 'cookie' => 'a_session_'.$projectId.'='.$this->token1, ], $gqlPayload); $this->assertIsArray($document['body']['data']['databasesGetDocument']); @@ -198,7 +201,7 @@ class AuthTest extends Scope $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $this->token2, + 'cookie' => 'a_session_'.$projectId.'='.$this->token2, ], $gqlPayload); $this->assertArrayHasKey('errors', $document['body']); @@ -226,12 +229,12 @@ class AuthTest extends Scope Permission::update(Role::user($userId)), Permission::delete(Role::user($userId)), ], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $this->token1, + 'cookie' => 'a_session_'.$projectId.'='.$this->token1, ], $gqlPayload); // Try to delete as account 1 @@ -242,12 +245,12 @@ class AuthTest extends Scope 'databaseId' => $this->database['body']['data']['databasesCreate']['_id'], 'collectionId' => $this->collection['body']['data']['databasesCreateCollection']['_id'], 'documentId' => $document['body']['data']['databasesCreateDocument']['_id'], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $this->token1, + 'cookie' => 'a_session_'.$projectId.'='.$this->token1, ], $gqlPayload); $this->assertIsNotArray($document['body']); diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 67d09bb4ac..8f16222f1e 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -6,195 +6,342 @@ trait Base { // Databases public static string $CREATE_DATABASE = 'create_database'; + public static string $GET_DATABASES = 'get_databases'; + public static string $GET_DATABASE = 'get_database'; + public static string $UPDATE_DATABASE = 'update_database'; + public static string $DELETE_DATABASE = 'delete_database'; + // Collections public static string $CREATE_COLLECTION = 'create_collection'; + public static string $GET_COLLECTION = 'get_collection'; + public static string $GET_COLLECTIONS = 'list_collections'; + public static string $UPDATE_COLLECTION = 'update_collection'; + public static string $DELETE_COLLECTION = 'delete_collection'; + // Attributes public static string $CREATE_STRING_ATTRIBUTE = 'create_string_attribute'; + public static string $CREATE_INTEGER_ATTRIBUTE = 'create_integer_attribute'; + public static string $CREATE_FLOAT_ATTRIBUTE = 'create_float_attribute'; + public static string $CREATE_BOOLEAN_ATTRIBUTE = 'create_boolean_attribute'; + public static string $CREATE_URL_ATTRIBUTE = 'create_url_attribute'; + public static string $CREATE_EMAIL_ATTRIBUTE = 'create_email_attribute'; + public static string $CREATE_IP_ATTRIBUTE = 'create_ip_attribute'; + public static string $CREATE_ENUM_ATTRIBUTE = 'create_enum_attribute'; + public static string $CREATE_DATETIME_ATTRIBUTE = 'create_datetime_attribute'; public static string $CREATE_RELATIONSHIP_ATTRIBUTE = 'create_relationship_attribute'; + public static string $UPDATE_STRING_ATTRIBUTE = 'update_string_attribute'; + public static string $UPDATE_INTEGER_ATTRIBUTE = 'update_integer_attribute'; + public static string $UPDATE_FLOAT_ATTRIBUTE = 'update_float_attribute'; + public static string $UPDATE_BOOLEAN_ATTRIBUTE = 'update_boolean_attribute'; + public static string $UPDATE_URL_ATTRIBUTE = 'update_url_attribute'; + public static string $UPDATE_EMAIL_ATTRIBUTE = 'update_email_attribute'; + public static string $UPDATE_IP_ATTRIBUTE = 'update_ip_attribute'; + public static string $UPDATE_ENUM_ATTRIBUTE = 'update_enum_attribute'; + public static string $UPDATE_DATETIME_ATTRIBUTE = 'update_datetime_attribute'; public static string $UPDATE_RELATIONSHIP_ATTRIBUTE = 'update_relationship_attribute'; + public static string $GET_ATTRIBUTES = 'get_attributes'; + public static string $GET_ATTRIBUTE = 'get_attribute'; + public static string $DELETE_ATTRIBUTE = 'delete_attribute'; + // Indexes public static string $CREATE_INDEX = 'create_index'; + public static string $GET_INDEXES = 'get_indexes'; + public static string $GET_INDEX = 'get_index'; + public static string $DELETE_INDEX = 'delete_index'; + // Documents public static string $CREATE_DOCUMENT = 'create_document_rest'; + public static string $GET_DOCUMENTS = 'list_documents'; + public static string $GET_DOCUMENT = 'get_document'; + public static string $UPDATE_DOCUMENT = 'update_document'; + public static string $DELETE_DOCUMENT = 'delete_document'; // Custom Entities public static string $CREATE_CUSTOM_ENTITY = 'create_custom_entity'; + public static string $GET_CUSTOM_ENTITIES = 'get_custom_entities'; + public static string $GET_CUSTOM_ENTITY = 'get_custom_entity'; + public static string $UPDATE_CUSTOM_ENTITY = 'update_custom_entity'; + public static string $DELETE_CUSTOM_ENTITY = 'delete_custom_entity'; // Account public static string $CREATE_ACCOUNT = 'create_account'; + public static string $CREATE_ACCOUNT_SESSION = 'create_account_session'; + public static string $CREATE_ANONYMOUS_SESSION = 'create_anonymous_session'; + public static string $CREATE_ACCOUNT_JWT = 'create_account_jwt'; + public static string $CREATE_MAGIC_URL = 'create_magic_url'; + public static string $CREATE_PASSWORD_RECOVERY = 'create_password_recovery'; + public static string $CREATE_EMAIL_VERIFICATION = 'create_email_verification'; + public static string $CREATE_PHONE_VERIFICATION = 'create_phone_verification'; + public static string $GET_ACCOUNT = 'get_account'; + public static string $GET_ACCOUNT_SESSION = 'get_account_session'; + public static string $GET_ACCOUNT_SESSIONS = 'get_account_sessions'; + public static string $GET_ACCOUNT_PREFS = 'get_account_preferences'; + public static string $GET_ACCOUNT_LOGS = 'get_account_logs'; + public static string $UPDATE_ACCOUNT_NAME = 'update_account_name'; + public static string $UPDATE_ACCOUNT_EMAIL = 'update_account_email'; + public static string $UPDATE_ACCOUNT_PASSWORD = 'update_account_password'; + public static string $UPDATE_ACCOUNT_PREFS = 'update_account_prefs'; + public static string $UPDATE_ACCOUNT_PHONE = 'update_account_phone'; + public static string $UPDATE_ACCOUNT_STATUS = 'update_account_status'; + public static string $UPDATE_MAGIC_URL = 'confirm_magic_url'; + public static string $UPDATE_PASSWORD_RECOVERY = 'confirm_password_recovery'; + public static string $UPDATE_EMAIL_VERIFICATION = 'confirm_email_verification'; + public static string $UPDATE_PHONE_VERIFICATION = 'confirm_phone_verification'; + public static string $DELETE_ACCOUNT_SESSION = 'delete_account_session'; + public static string $DELETE_ACCOUNT_SESSIONS = 'delete_account_sessions'; // Users public static string $CREATE_USER = 'create_user'; + public static string $GET_USER = 'get_user'; + public static string $GET_USERS = 'list_user'; + public static string $GET_USER_PREFERENCES = 'get_user_preferences'; + public static string $GET_USER_SESSIONS = 'get_user_sessions'; + public static string $GET_USER_MEMBERSHIPS = 'get_user_memberships'; + public static string $GET_USER_LOGS = 'get_user_logs'; + public static string $UPDATE_USER_STATUS = 'update_user_status'; + public static string $UPDATE_USER_NAME = 'update_user_name'; + public static string $UPDATE_USER_EMAIL = 'update_user_email'; + public static string $UPDATE_USER_EMAIL_VERIFICATION = 'update_email_verification'; + public static string $UPDATE_USER_PHONE_VERIFICATION = 'update_phone_verification'; + public static string $UPDATE_USER_PASSWORD = 'update_user_password'; + public static string $UPDATE_USER_PHONE = 'update_user_phone'; + public static string $UPDATE_USER_PREFS = 'update_user_prefs'; + public static string $DELETE_USER_SESSIONS = 'delete_user_sessions'; + public static string $DELETE_USER_SESSION = 'delete_user_session'; + public static string $DELETE_USER = 'delete_user'; // Teams public static string $GET_TEAM = 'get_team'; + public static string $GET_TEAM_PREFERENCES = 'get_team_preferences'; + public static string $GET_TEAMS = 'list_teams'; + public static string $CREATE_TEAM = 'create_team'; + public static string $UPDATE_TEAM_NAME = 'update_team_name'; + public static string $UPDATE_TEAM_PREFERENCES = 'update_team_preferences'; public static string $DELETE_TEAM = 'delete_team'; + public static string $GET_TEAM_MEMBERSHIP = 'get_team_membership'; + public static string $GET_TEAM_MEMBERSHIPS = 'list_team_memberships'; + public static string $CREATE_TEAM_MEMBERSHIP = 'create_team_membership'; + public static string $UPDATE_TEAM_MEMBERSHIP = 'update_team_membership'; + public static string $UPDATE_TEAM_MEMBERSHIP_STATUS = 'update_membership_status'; + public static string $DELETE_TEAM_MEMBERSHIP = 'delete_team_membership'; // Functions public static string $CREATE_FUNCTION = 'create_function'; + public static string $GET_FUNCTIONS = 'list_functions'; + public static string $GET_FUNCTION = 'get_function'; + public static string $GET_RUNTIMES = 'list_runtimes'; + public static string $UPDATE_FUNCTION = 'update_function'; + public static string $DELETE_FUNCTION = 'delete_function'; + // Variables public static string $CREATE_VARIABLE = 'create_variable'; + public static string $GET_VARIABLES = 'list_variables'; + public static string $GET_VARIABLE = 'get_variable'; + public static string $UPDATE_VARIABLE = 'update_variable'; + public static string $DELETE_VARIABLE = 'delete_variable'; //Deployments public static string $CREATE_DEPLOYMENT = 'create_deployment'; + public static string $GET_DEPLOYMENTS = 'list_deployments'; + public static string $GET_DEPLOYMENT = 'get_deployment'; + public static string $UPDATE_DEPLOYMENT = 'update_deployment'; + public static string $DELETE_DEPLOYMENT = 'delete_deployment'; + // Executions public static string $GET_EXECUTIONS = 'list_executions'; + public static string $GET_EXECUTION = 'get_execution'; + public static string $CREATE_EXECUTION = 'create_execution'; + public static string $DELETE_EXECUTION = 'delete_execution'; + public static string $RETRY_BUILD = 'retry_build'; // Buckets public static string $CREATE_BUCKET = 'create_bucket'; + public static string $GET_BUCKETS = 'list_buckets'; + public static string $GET_BUCKET = 'get_bucket'; + public static string $UPDATE_BUCKET = 'update_bucket'; + public static string $DELETE_BUCKET = 'delete_bucket'; + // Files public static string $CREATE_FILE = 'create_file'; + public static string $GET_FILES = 'list_files'; + public static string $GET_FILE = 'get_file'; + public static string $GET_FILE_PREVIEW = 'get_file_preview'; + public static string $GET_FILE_DOWNLOAD = 'get_file_download'; + public static string $GET_FILE_VIEW = 'get_file_view'; + public static string $UPDATE_FILE = 'update_file'; + public static string $DELETE_FILE = 'delete_file'; // Health public static string $GET_HTTP_HEALTH = 'get_http_health'; + public static string $GET_DB_HEALTH = 'get_db_health'; + public static string $GET_CACHE_HEALTH = 'get_cache_health'; + public static string $GET_TIME_HEALTH = 'get_time_health'; + public static string $GET_WEBHOOKS_QUEUE_HEALTH = 'get_webhooks_queue_health'; + public static string $GET_LOGS_QUEUE_HEALTH = 'get_logs_queue_health'; + public static string $GET_CERTIFICATES_QUEUE_HEALTH = 'get_certificates_queue_health'; + public static string $GET_FUNCTION_QUEUE_HEALTH = 'get_functions_queue_health'; + public static string $GET_LOCAL_STORAGE_HEALTH = 'get_local_storage_health'; + public static string $GET_ANITVIRUS_HEALTH = 'get_antivirus_health'; // Localization public static string $GET_LOCALE = 'get_locale'; + public static string $LIST_COUNTRIES = 'list_countries'; + public static string $LIST_EU_COUNTRIES = 'list_eu_countries'; + public static string $LIST_COUNTRY_PHONE_CODES = 'list_country_phone_codes'; + public static string $LIST_CONTINENTS = 'list_continents'; + public static string $LIST_CURRENCIES = 'list_currencies'; + public static string $LIST_LANGUAGES = 'list_languages'; // Avatars public static string $GET_CREDIT_CARD_ICON = 'get_credit_card_icon'; + public static string $GET_BROWSER_ICON = 'get_browser_icon'; + public static string $GET_COUNTRY_FLAG = 'get_country_flag'; + public static string $GET_IMAGE_FROM_URL = 'get_image_from_url'; + public static string $GET_FAVICON = 'get_favicon'; + public static string $GET_QRCODE = 'get_qrcode'; + public static string $GET_USER_INITIALS = 'get_user_initials'; // Complex queries @@ -598,13 +745,13 @@ trait Base ...attributeProperties } } - }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; + }'.PHP_EOL.self::$FRAGMENT_ATTRIBUTES; case self::$GET_ATTRIBUTE: return 'query getAttribute($databaseId: String!, $collectionId: String!, $key: String!) { databasesGetAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key) { ...attributeProperties } - }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; + }'.PHP_EOL.self::$FRAGMENT_ATTRIBUTES; case self::$DELETE_ATTRIBUTE: return 'mutation deleteAttribute($databaseId: String!, $collectionId: String!, $key: String!) { databasesDeleteAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key) { @@ -728,7 +875,7 @@ trait Base ...options } } - }' . PHP_EOL . self::$FRAGMENT_HASH_OPTIONS; + }'.PHP_EOL.self::$FRAGMENT_HASH_OPTIONS; case self::$GET_USER_PREFERENCES: return 'query getUserPreferences($userId : String!) { usersGetPrefs(userId : $userId) { @@ -1923,7 +2070,7 @@ trait Base data } } - }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; + }'.PHP_EOL.self::$FRAGMENT_ATTRIBUTES; } throw new \InvalidArgumentException('Invalid query type'); diff --git a/tests/e2e/Services/GraphQL/BatchTest.php b/tests/e2e/Services/GraphQL/BatchTest.php index 7082d23677..a6f1da2908 100644 --- a/tests/e2e/Services/GraphQL/BatchTest.php +++ b/tests/e2e/Services/GraphQL/BatchTest.php @@ -63,7 +63,7 @@ class BatchTest extends Scope public function testArrayBatchedMutations() { $projectId = $this->getProject()['$id']; - $email = 'tester' . \uniqid() . '@example.com'; + $email = 'tester'.\uniqid().'@example.com'; $graphQLPayload = [[ 'query' => 'mutation CreateAccount($userId: String!, $email: String!, $password: String!, $name: String) { accountCreate(userId: $userId, email: $email, password: $password, name: $name) { @@ -77,17 +77,17 @@ class BatchTest extends Scope 'name' => 'Tester 1', ], ], - [ - 'query' => 'mutation CreateTeam($teamId: String! $name: String!) { + [ + 'query' => 'mutation CreateTeam($teamId: String! $name: String!) { teamsCreate(teamId: $teamId, name: $name) { name } }', - 'variables' => [ - 'teamId' => ID::unique(), - 'name' => 'Team 1', - ], - ]]; + 'variables' => [ + 'teamId' => ID::unique(), + 'name' => 'Team 1', + ], + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -107,8 +107,8 @@ class BatchTest extends Scope public function testArrayBatchedMutationsOfSameType() { $projectId = $this->getProject()['$id']; - $email1 = 'tester' . \uniqid() . '@example.com'; - $email2 = 'tester' . \uniqid() . '@example.com'; + $email1 = 'tester'.\uniqid().'@example.com'; + $email2 = 'tester'.\uniqid().'@example.com'; $query = 'mutation CreateAccount($userId: String!, $email: String!, $password: String!, $name: String) { accountCreate(userId: $userId, email: $email, password: $password, name: $name) { _id @@ -152,7 +152,7 @@ class BatchTest extends Scope public function testArrayBatchedMixed() { $projectId = $this->getProject()['$id']; - $email = 'tester' . \uniqid() . '@example.com'; + $email = 'tester'.\uniqid().'@example.com'; $graphQLPayload = [ ['query' => 'query { localeListCountries { total countries { code } } }'], ['query' => 'query { localeListContinents { total continents { code } } }'], @@ -167,7 +167,7 @@ class BatchTest extends Scope 'email' => $email, 'password' => 'password', 'name' => 'Tester 1', - ] + ], ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -192,7 +192,7 @@ class BatchTest extends Scope public function testArrayBatchedMixedOfSameType() { $projectId = $this->getProject()['$id']; - $email = 'tester' . \uniqid() . '@example.com'; + $email = 'tester'.\uniqid().'@example.com'; $query = 'query { localeListCountries { total countries { code } } }'; $graphQLPayload = [ ['query' => $query], @@ -208,7 +208,7 @@ class BatchTest extends Scope 'email' => $email, 'password' => 'password', 'name' => 'Tester 1', - ] + ], ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -281,7 +281,7 @@ class BatchTest extends Scope public function testQueryBatchedMutations() { $projectId = $this->getProject()['$id']; - $email = 'tester' . \uniqid() . '@example.com'; + $email = 'tester'.\uniqid().'@example.com'; $graphQLPayload = [ 'query' => 'mutation CreateAndLogin($userId: String!, $email: String!, $password: String!, $name: String) { accountCreate(userId: $userId, email: $email, password: $password, name: $name) { @@ -304,7 +304,6 @@ class BatchTest extends Scope 'x-appwrite-project' => $projectId, ], $this->getHeaders()), $graphQLPayload); - $this->assertIsArray($response['body']['data']); $this->assertArrayNotHasKey('errors', $response['body']); $this->assertArrayHasKey('accountCreate', $response['body']['data']); @@ -315,8 +314,8 @@ class BatchTest extends Scope public function testQueryBatchedMutationsOfSameType() { $projectId = $this->getProject()['$id']; - $email1 = 'tester' . \uniqid() . '@example.com'; - $email2 = 'tester' . \uniqid() . '@example.com'; + $email1 = 'tester'.\uniqid().'@example.com'; + $email2 = 'tester'.\uniqid().'@example.com'; $graphQLPayload = [ 'query' => 'mutation CreateAndLogin($email1: String!, $email2: String!, $password: String!, $name1: String, $name2: String) { accountCreate(userId: "unique()", email: $email1, password: $password, name: $name1) { @@ -347,8 +346,8 @@ class BatchTest extends Scope public function testQueryBatchedMutationsOfSameTypeWithAlias() { $projectId = $this->getProject()['$id']; - $email1 = 'tester' . \uniqid() . '@example.com'; - $email2 = 'tester' . \uniqid() . '@example.com'; + $email1 = 'tester'.\uniqid().'@example.com'; + $email2 = 'tester'.\uniqid().'@example.com'; $graphQLPayload = [ 'query' => 'mutation CreateAndLogin($email1: String!, $email2: String!, $password: String!, $name1: String, $name2: String) { account1: accountCreate(userId: "unique()", email: $email1, password: $password, name: $name1) { diff --git a/tests/e2e/Services/GraphQL/ContentTypeTest.php b/tests/e2e/Services/GraphQL/ContentTypeTest.php index da885a2a83..5ab950d893 100644 --- a/tests/e2e/Services/GraphQL/ContentTypeTest.php +++ b/tests/e2e/Services/GraphQL/ContentTypeTest.php @@ -115,7 +115,7 @@ class ContentTypeTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -138,12 +138,12 @@ class ContentTypeTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]), 'map' => \json_encode([ - 'file' => ["variables.file"] + 'file' => ['variables.file'], ]), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/DatabaseClientTest.php b/tests/e2e/Services/GraphQL/DatabaseClientTest.php index 3853a3fc17..ae3b908330 100644 --- a/tests/e2e/Services/GraphQL/DatabaseClientTest.php +++ b/tests/e2e/Services/GraphQL/DatabaseClientTest.php @@ -25,7 +25,7 @@ class DatabaseClientTest extends Scope 'variables' => [ 'databaseId' => ID::unique(), 'name' => 'Actors', - ] + ], ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -62,7 +62,7 @@ class DatabaseClientTest extends Scope Permission::update(Role::users()), Permission::delete(Role::users()), ], - ] + ], ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -97,7 +97,7 @@ class DatabaseClientTest extends Scope 'key' => 'name', 'size' => 256, 'required' => true, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -129,7 +129,7 @@ class DatabaseClientTest extends Scope 'min' => 18, 'max' => 150, 'required' => true, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -170,7 +170,7 @@ class DatabaseClientTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -193,6 +193,7 @@ class DatabaseClientTest extends Scope /** * @depends testCreateCollection + * * @throws \Exception */ public function testGetDocuments($data): void @@ -204,7 +205,7 @@ class DatabaseClientTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ] + ], ]; $documents = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -219,6 +220,7 @@ class DatabaseClientTest extends Scope /** * @depends testCreateDocument + * * @throws \Exception */ public function testGetDocument($data): void @@ -231,7 +233,7 @@ class DatabaseClientTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'documentId' => $data['document']['_id'], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -246,6 +248,7 @@ class DatabaseClientTest extends Scope /** * @depends testCreateDocument + * * @throws \Exception */ public function testUpdateDocument($data): void @@ -261,7 +264,7 @@ class DatabaseClientTest extends Scope 'data' => [ 'name' => 'New Document Name', ], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -279,6 +282,7 @@ class DatabaseClientTest extends Scope /** * @depends testCreateDocument + * * @throws \Exception */ public function testDeleteDocument($data): void @@ -291,7 +295,7 @@ class DatabaseClientTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'documentId' => $data['document']['_id'], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ diff --git a/tests/e2e/Services/GraphQL/DatabaseServerTest.php b/tests/e2e/Services/GraphQL/DatabaseServerTest.php index 87006a1bea..f17159c174 100644 --- a/tests/e2e/Services/GraphQL/DatabaseServerTest.php +++ b/tests/e2e/Services/GraphQL/DatabaseServerTest.php @@ -27,7 +27,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => 'actors', 'name' => 'Actors', - ] + ], ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -63,7 +63,7 @@ class DatabaseServerTest extends Scope Permission::update(Role::users()), Permission::delete(Role::users()), ], - ] + ], ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -89,7 +89,7 @@ class DatabaseServerTest extends Scope Permission::update(Role::users()), Permission::delete(Role::users()), ], - ] + ], ]; $collection2 = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -111,6 +111,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testCreateStringAttribute($data): array @@ -125,7 +126,7 @@ class DatabaseServerTest extends Scope 'key' => 'name', 'size' => 256, 'required' => true, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -142,6 +143,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateStringAttribute + * * @throws Exception */ public function testUpdateStringAttribute($data): array @@ -159,7 +161,7 @@ class DatabaseServerTest extends Scope 'key' => 'name', 'required' => false, 'default' => 'Default Value', - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -178,6 +180,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testCreateIntegerAttribute($data): array @@ -193,7 +196,7 @@ class DatabaseServerTest extends Scope 'min' => 18, 'max' => 150, 'required' => true, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -210,6 +213,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateIntegerAttribute + * * @throws Exception */ public function testUpdateIntegerAttribute($data): array @@ -228,8 +232,8 @@ class DatabaseServerTest extends Scope 'required' => false, 'min' => 12, 'max' => 160, - 'default' => 50 - ] + 'default' => 50, + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -250,6 +254,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testCreateBooleanAttribute($data): array @@ -263,7 +268,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'alive', 'required' => true, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -280,6 +285,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateBooleanAttribute + * * @throws Exception */ public function testUpdateBooleanAttribute($data): array @@ -296,8 +302,8 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'alive', 'required' => false, - 'default' => true - ] + 'default' => true, + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -316,6 +322,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testCreateFloatAttribute($data): array @@ -332,7 +339,7 @@ class DatabaseServerTest extends Scope 'max' => 999999.99, 'default' => 1000.0, 'required' => false, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -349,6 +356,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateFloatAttribute + * * @throws Exception */ public function testUpdateFloatAttribute($data): array @@ -367,8 +375,8 @@ class DatabaseServerTest extends Scope 'required' => false, 'min' => 100.0, 'max' => 1000000.0, - 'default' => 2500.0 - ] + 'default' => 2500.0, + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -389,6 +397,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testCreateEmailAttribute($data): array @@ -402,7 +411,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'email', 'required' => true, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -419,6 +428,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateEmailAttribute + * * @throws Exception */ public function testUpdateEmailAttribute($data): array @@ -436,7 +446,7 @@ class DatabaseServerTest extends Scope 'key' => 'email', 'required' => false, 'default' => 'torsten@appwrite.io', - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -455,6 +465,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testCreateEnumAttribute($data): array @@ -473,7 +484,7 @@ class DatabaseServerTest extends Scope 'guest', ], 'required' => true, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -488,9 +499,9 @@ class DatabaseServerTest extends Scope return $data; } - /** * @depends testCreateEnumAttribute + * * @throws Exception */ public function testUpdateEnumAttribute($data): array @@ -510,10 +521,10 @@ class DatabaseServerTest extends Scope 'elements' => [ 'crew', 'tech', - 'actor' + 'actor', ], - 'default' => 'tech' - ] + 'default' => 'tech', + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -534,6 +545,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testCreateDatetimeAttribute($data): array @@ -547,7 +559,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'dob', 'required' => true, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -564,6 +576,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDatetimeAttribute + * * @throws Exception */ public function testUpdateDatetimeAttribute($data): array @@ -580,8 +593,8 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'dob', 'required' => false, - 'default' => '2000-01-01T00:00:00Z' - ] + 'default' => '2000-01-01T00:00:00Z', + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -614,8 +627,8 @@ class DatabaseServerTest extends Scope 'type' => Database::RELATION_ONE_TO_MANY, 'twoWay' => true, 'key' => 'actors', - 'twoWayKey' => 'movie' - ] + 'twoWayKey' => 'movie', + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -646,7 +659,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection2']['_id'], 'key' => 'actors', 'onDelete' => Database::RELATION_MUTATE_CASCADE, - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -663,6 +676,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testCreateIPAttribute($data): array @@ -677,7 +691,7 @@ class DatabaseServerTest extends Scope 'key' => 'ip', 'required' => false, 'default' => '::1', - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -694,6 +708,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateIPAttribute + * * @throws Exception */ public function testUpdateIPAttribute($data): array @@ -710,8 +725,8 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'ip', 'required' => false, - 'default' => '127.0.0.1' - ] + 'default' => '127.0.0.1', + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -730,6 +745,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testCreateURLAttribute($data): array @@ -744,7 +760,7 @@ class DatabaseServerTest extends Scope 'key' => 'url', 'required' => false, 'default' => 'https://appwrite.io', - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -761,6 +777,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateURLAttribute + * * @throws Exception */ public function testUpdateURLAttribute($data): void @@ -777,8 +794,8 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'url', 'required' => false, - 'default' => 'https://cloud.appwrite.io' - ] + 'default' => 'https://cloud.appwrite.io', + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -796,6 +813,7 @@ class DatabaseServerTest extends Scope /** * @depends testUpdateStringAttribute * @depends testUpdateIntegerAttribute + * * @throws Exception */ public function testCreateIndex($data): array @@ -813,7 +831,7 @@ class DatabaseServerTest extends Scope 'name', 'age', ], - ] + ], ]; $index = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -837,6 +855,7 @@ class DatabaseServerTest extends Scope * @depends testUpdateIntegerAttribute * @depends testUpdateBooleanAttribute * @depends testUpdateEnumAttribute + * * @throws Exception */ public function testCreateDocument($data): array @@ -863,7 +882,7 @@ class DatabaseServerTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -944,6 +963,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDatabase + * * @throws Exception */ public function testGetDatabase($database): void @@ -954,7 +974,7 @@ class DatabaseServerTest extends Scope 'query' => $query, 'variables' => [ 'databaseId' => $database['_id'], - ] + ], ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -969,6 +989,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testGetCollections($data): void @@ -979,7 +1000,7 @@ class DatabaseServerTest extends Scope 'query' => $query, 'variables' => [ 'databaseId' => $data['database']['_id'], - ] + ], ]; $collections = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -994,6 +1015,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testGetCollection($data): void @@ -1005,7 +1027,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ] + ], ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1021,6 +1043,7 @@ class DatabaseServerTest extends Scope /** * @depends testUpdateStringAttribute * @depends testUpdateIntegerAttribute + * * @throws Exception */ public function testGetAttributes($data): void @@ -1032,7 +1055,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ] + ], ]; $attributes = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1047,6 +1070,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testGetAttribute($data): void @@ -1059,7 +1083,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'key' => 'name', - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1074,6 +1098,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateIndex + * * @throws Exception */ public function testGetIndexes($data): void @@ -1085,7 +1110,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ] + ], ]; $indices = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1100,6 +1125,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateIndex + * * @throws Exception */ public function testGetIndex($data): void @@ -1112,7 +1138,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'key' => $data['index']['key'], - ] + ], ]; $index = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1127,6 +1153,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testGetDocuments($data): void @@ -1138,7 +1165,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ] + ], ]; $documents = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1153,6 +1180,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDocument + * * @throws Exception */ public function testGetDocument($data): void @@ -1165,7 +1193,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'documentId' => $data['document']['_id'], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1227,6 +1255,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDatabase + * * @throws Exception */ public function testUpdateDatabase($database) @@ -1238,7 +1267,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $database['_id'], 'name' => 'New Database Name', - ] + ], ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1253,6 +1282,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testUpdateCollection($data) @@ -1266,7 +1296,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'name' => 'New Collection Name', 'documentSecurity' => false, - ] + ], ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1281,6 +1311,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDocument + * * @throws Exception */ public function testUpdateDocument($data): void @@ -1296,7 +1327,7 @@ class DatabaseServerTest extends Scope 'data' => [ 'name' => 'New Document Name', ], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1341,6 +1372,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDocument + * * @throws Exception */ public function testDeleteDocument($data): void @@ -1353,7 +1385,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'documentId' => $data['document']['_id'], - ] + ], ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1391,6 +1423,7 @@ class DatabaseServerTest extends Scope /** * @depends testUpdateStringAttribute + * * @throws Exception */ public function testDeleteAttribute($data): void @@ -1403,7 +1436,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'key' => 'name', - ] + ], ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1417,6 +1450,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection + * * @throws Exception */ public function testDeleteCollection($data) @@ -1428,7 +1462,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ] + ], ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1442,6 +1476,7 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDatabase + * * @throws Exception */ public function testDeleteDatabase($database) @@ -1452,7 +1487,7 @@ class DatabaseServerTest extends Scope 'query' => $query, 'variables' => [ 'databaseId' => $database['_id'], - ] + ], ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ diff --git a/tests/e2e/Services/GraphQL/FunctionsClientTest.php b/tests/e2e/Services/GraphQL/FunctionsClientTest.php index d5b50250d4..97cbfa9206 100644 --- a/tests/e2e/Services/GraphQL/FunctionsClientTest.php +++ b/tests/e2e/Services/GraphQL/FunctionsClientTest.php @@ -27,7 +27,7 @@ class FunctionsClientTest extends Scope 'name' => 'Test Function', 'runtime' => 'php-8.0', 'execute' => [Role::any()->toString()], - ] + ], ]; $function = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -36,7 +36,6 @@ class FunctionsClientTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'], ], $gqlPayload); - $this->assertIsArray($function['body']['data']); $this->assertArrayNotHasKey('errors', $function['body']); @@ -57,7 +56,7 @@ class FunctionsClientTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $functionId, - ] + ], ]; $variables = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -74,15 +73,17 @@ class FunctionsClientTest extends Scope /** * @depends testCreateFunction + * * @param $function * @return array + * * @throws \Exception */ public function testCreateDeployment($function): array { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_DEPLOYMENT); - $code = realpath(__DIR__ . '/../../../resources/functions') . "/php/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions').'/php/code.tar.gz'; $gqlPayload = [ 'operations' => \json_encode([ 'query' => $query, @@ -91,10 +92,10 @@ class FunctionsClientTest extends Scope 'entrypoint' => 'index.php', 'activate' => true, 'code' => null, - ] + ], ]), 'map' => \json_encode([ - 'code' => ["variables.code"] + 'code' => ['variables.code'], ]), 'code' => new CURLFile($code, 'application/gzip', 'code.tar.gz'), ]; @@ -116,9 +117,11 @@ class FunctionsClientTest extends Scope /** * @depends testCreateFunction * @depends testCreateDeployment + * * @param $function * @param $deployment * @return array + * * @throws \Exception */ public function testCreateExecution($function, $deployment): array @@ -129,7 +132,7 @@ class FunctionsClientTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ] + ], ]; $execution = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -139,13 +142,16 @@ class FunctionsClientTest extends Scope $this->assertIsArray($execution['body']['data']); $this->assertArrayNotHasKey('errors', $execution['body']); + return $execution['body']['data']['functionsCreateExecution']; } /** * @depends testCreateFunction + * * @param $function * @return array + * * @throws \Exception */ public function testGetExecutions($function): array @@ -156,7 +162,7 @@ class FunctionsClientTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ] + ], ]; $executions = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -175,9 +181,11 @@ class FunctionsClientTest extends Scope /** * @depends testCreateFunction * @depends testCreateExecution + * * @param $function * @param $execution * @return array + * * @throws \Exception */ public function testGetExecution($function, $execution): array @@ -189,7 +197,7 @@ class FunctionsClientTest extends Scope 'variables' => [ 'functionId' => $function['_id'], 'executionId' => $execution['_id'], - ] + ], ]; $execution = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/FunctionsServerTest.php b/tests/e2e/Services/GraphQL/FunctionsServerTest.php index 75aa0d5d04..2771505ba7 100644 --- a/tests/e2e/Services/GraphQL/FunctionsServerTest.php +++ b/tests/e2e/Services/GraphQL/FunctionsServerTest.php @@ -27,7 +27,7 @@ class FunctionsServerTest extends Scope 'name' => 'Test Function', 'runtime' => 'php-8.0', 'execute' => [Role::any()->toString()], - ] + ], ]; $function = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -55,7 +55,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $functionId, - ] + ], ]; $variables = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -72,15 +72,17 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction + * * @param $function * @return array + * * @throws \Exception */ public function testCreateDeployment($function): array { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_DEPLOYMENT); - $code = realpath(__DIR__ . '/../../../resources/functions') . "/php/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions').'/php/code.tar.gz'; $gqlPayload = [ 'operations' => \json_encode([ 'query' => $query, @@ -89,10 +91,10 @@ class FunctionsServerTest extends Scope 'entrypoint' => 'index.php', 'activate' => true, 'code' => null, - ] + ], ]), 'map' => \json_encode([ - 'code' => ["variables.code"] + 'code' => ['variables.code'], ]), 'code' => new CURLFile($code, 'application/gzip', 'code.tar.gz'), ]; @@ -113,8 +115,10 @@ class FunctionsServerTest extends Scope /** * * @depends testCreateFunction * @depends testCreateDeployment + * * @param $function * @return array + * * @throws \Exception */ public function testCreateExecution($function): array @@ -125,7 +129,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ] + ], ]; $execution = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -142,9 +146,11 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testGetDeployment + * * @param $function * @param $deployment * @return array + * * @throws \Exception */ public function testCreateRetryBuild($function, $deployment): void @@ -157,7 +163,7 @@ class FunctionsServerTest extends Scope 'functionId' => $function['_id'], 'deploymentId' => $deployment['_id'], 'buildId' => $deployment['buildId'], - ] + ], ]; $retryBuild = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -166,7 +172,7 @@ class FunctionsServerTest extends Scope ], $this->getHeaders()), $gqlPayload); $this->assertIsArray($retryBuild['body']['errors']); - $this->assertEquals("Build not failed", $retryBuild['body']['errors'][0]['message']); + $this->assertEquals('Build not failed', $retryBuild['body']['errors'][0]['message']); } public function testGetFunctions(): array @@ -192,8 +198,10 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction + * * @param $function * @return array + * * @throws \Exception */ public function testGetFunction($function): array @@ -204,7 +212,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ] + ], ]; $function = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -243,8 +251,10 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction + * * @param $function * @return array + * * @throws \Exception */ public function testGetDeployments($function) @@ -255,7 +265,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ] + ], ]; $deployments = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -274,8 +284,10 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testCreateDeployment + * * @param $function * @return array + * * @throws \Exception */ public function testGetDeployment($function, $deployment) @@ -287,7 +299,7 @@ class FunctionsServerTest extends Scope 'variables' => [ 'functionId' => $function['_id'], 'deploymentId' => $deployment['_id'], - ] + ], ]; $deployment = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -305,8 +317,10 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction + * * @param $function * @return array + * * @throws \Exception */ public function testGetExecutions($function): array @@ -317,7 +331,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ] + ], ]; $executions = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -336,9 +350,11 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testCreateExecution + * * @param $function * @param $execution * @return array + * * @throws \Exception */ public function testGetExecution($function, $execution): array @@ -350,7 +366,7 @@ class FunctionsServerTest extends Scope 'variables' => [ 'functionId' => $function['_id'], 'executionId' => $execution['_id'], - ] + ], ]; $execution = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -368,8 +384,10 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction + * * @param $function * @return array + * * @throws \Exception */ public function testUpdateFunction($function): array @@ -386,7 +404,7 @@ class FunctionsServerTest extends Scope 'name' => 'John Doe', 'age' => 42, ], - ] + ], ]; $function = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -405,8 +423,10 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testCreateDeployment + * * @param $function * @param $deployment + * * @throws \Exception */ public function testDeleteDeployment($function, $deployment): void @@ -418,7 +438,7 @@ class FunctionsServerTest extends Scope 'variables' => [ 'functionId' => $function['_id'], 'deploymentId' => $deployment['_id'], - ] + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -433,7 +453,9 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testDeleteDeployment + * * @param $function + * * @throws \Exception */ public function testDeleteFunction($function): void @@ -444,7 +466,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ] + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/LocalizationTest.php b/tests/e2e/Services/GraphQL/LocalizationTest.php index 38200911c8..2fe76a6f06 100644 --- a/tests/e2e/Services/GraphQL/LocalizationTest.php +++ b/tests/e2e/Services/GraphQL/LocalizationTest.php @@ -18,7 +18,7 @@ class LocalizationTest extends Scope $projectId = $this->getProject()['$id']; $query = \urlencode($this->getQuery(self::$GET_LOCALE)); - $locale = $this->client->call(Client::METHOD_GET, '/graphql?query=' . $query, \array_merge([ + $locale = $this->client->call(Client::METHOD_GET, '/graphql?query='.$query, \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders())); diff --git a/tests/e2e/Services/GraphQL/ScopeTest.php b/tests/e2e/Services/GraphQL/ScopeTest.php index a8b5b7cea4..44122887da 100644 --- a/tests/e2e/Services/GraphQL/ScopeTest.php +++ b/tests/e2e/Services/GraphQL/ScopeTest.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\GraphQL; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\SideClient; use Tests\E2E\Scopes\SideServer; use Utopia\Database\Helpers\ID; @@ -25,7 +24,7 @@ class ScopeTest extends Scope 'variables' => [ 'databaseId' => ID::unique(), 'name' => 'Actors', - ] + ], ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -49,7 +48,7 @@ class ScopeTest extends Scope 'variables' => [ 'databaseId' => ID::unique(), 'name' => 'Actors', - ] + ], ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', [ diff --git a/tests/e2e/Services/GraphQL/StorageClientTest.php b/tests/e2e/Services/GraphQL/StorageClientTest.php index 9896598c2d..90cfaef7d5 100644 --- a/tests/e2e/Services/GraphQL/StorageClientTest.php +++ b/tests/e2e/Services/GraphQL/StorageClientTest.php @@ -33,7 +33,7 @@ class StorageClientTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -70,12 +70,12 @@ class StorageClientTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]), 'map' => \json_encode([ - '0' => ["variables.file"] + '0' => ['variables.file'], ]), - '0' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + '0' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -91,8 +91,10 @@ class StorageClientTest extends Scope /** * @depends testCreateBucket + * * @param $bucket * @return array + * * @throws \Exception */ public function testGetFiles($bucket): array @@ -103,7 +105,7 @@ class StorageClientTest extends Scope 'query' => $query, 'variables' => [ 'bucketId' => $bucket['_id'], - ] + ], ]; $files = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -122,9 +124,11 @@ class StorageClientTest extends Scope /** * @depends testCreateBucket * @depends testCreateFile + * * @param $bucket * @param $file * @return array + * * @throws \Exception */ public function testGetFile($bucket, $file) @@ -136,7 +140,7 @@ class StorageClientTest extends Scope 'variables' => [ 'bucketId' => $bucket['_id'], 'fileId' => $file['_id'], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -152,8 +156,10 @@ class StorageClientTest extends Scope /** * @depends testCreateFile + * * @param $file * @return array + * * @throws \Exception */ public function testGetFilePreview($file) @@ -167,7 +173,7 @@ class StorageClientTest extends Scope 'fileId' => $file['_id'], 'width' => 100, 'height' => 100, - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -182,8 +188,10 @@ class StorageClientTest extends Scope /** * @depends testCreateFile + * * @param $file * @return array + * * @throws \Exception */ public function testGetFileDownload($file) @@ -195,7 +203,7 @@ class StorageClientTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -208,8 +216,10 @@ class StorageClientTest extends Scope /** * @depends testCreateFile + * * @param $file * @return array + * * @throws \Exception */ public function testGetFileView($file): void @@ -221,7 +231,7 @@ class StorageClientTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -234,8 +244,10 @@ class StorageClientTest extends Scope /** * @depends testCreateFile + * * @param $file * @return array + * * @throws \Exception */ public function testUpdateFile($file): array @@ -252,7 +264,7 @@ class StorageClientTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -270,7 +282,9 @@ class StorageClientTest extends Scope /** * @depends testCreateFile + * * @param $file + * * @throws \Exception */ public function testDeleteFile($file): void @@ -282,7 +296,7 @@ class StorageClientTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/StorageServerTest.php b/tests/e2e/Services/GraphQL/StorageServerTest.php index 7fea895b1c..c4c12e400c 100644 --- a/tests/e2e/Services/GraphQL/StorageServerTest.php +++ b/tests/e2e/Services/GraphQL/StorageServerTest.php @@ -33,7 +33,7 @@ class StorageServerTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -69,12 +69,12 @@ class StorageServerTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]), 'map' => \json_encode([ - 'file' => ["variables.file"] + 'file' => ['variables.file'], ]), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -84,6 +84,7 @@ class StorageServerTest extends Scope $this->assertIsArray($file['body']['data']); $this->assertArrayNotHasKey('errors', $file['body']); + return $file['body']['data']['storageCreateFile']; } @@ -110,8 +111,10 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket + * * @param $bucket * @return array + * * @throws \Exception */ public function testGetBucket($bucket): array @@ -122,7 +125,7 @@ class StorageServerTest extends Scope 'query' => $query, 'variables' => [ 'bucketId' => $bucket['_id'], - ] + ], ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -140,8 +143,10 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket + * * @param $bucket * @return array + * * @throws \Exception */ public function testGetFiles($bucket): array @@ -152,7 +157,7 @@ class StorageServerTest extends Scope 'query' => $query, 'variables' => [ 'bucketId' => $bucket['_id'], - ] + ], ]; $files = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -171,9 +176,11 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket * @depends testCreateFile + * * @param $bucket * @param $file * @return array + * * @throws \Exception */ public function testGetFile($bucket, $file) @@ -185,7 +192,7 @@ class StorageServerTest extends Scope 'variables' => [ 'bucketId' => $bucket['_id'], 'fileId' => $file['_id'], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -201,8 +208,10 @@ class StorageServerTest extends Scope /** * @depends testCreateFile + * * @param $file * @return array + * * @throws \Exception */ public function testGetFilePreview($file) @@ -216,7 +225,7 @@ class StorageServerTest extends Scope 'fileId' => $file['_id'], 'width' => 100, 'height' => 100, - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -231,8 +240,10 @@ class StorageServerTest extends Scope /** * @depends testCreateFile + * * @param $file * @return array + * * @throws \Exception */ public function testGetFileDownload($file) @@ -244,7 +255,7 @@ class StorageServerTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -257,8 +268,10 @@ class StorageServerTest extends Scope /** * @depends testCreateFile + * * @param $file * @return array + * * @throws \Exception */ public function testGetFileView($file): void @@ -270,7 +283,7 @@ class StorageServerTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -283,8 +296,10 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket + * * @param $bucket * @return array + * * @throws \Exception */ public function testUpdateBucket($bucket): array @@ -297,7 +312,7 @@ class StorageServerTest extends Scope 'bucketId' => $bucket['_id'], 'name' => 'Actors Updated', 'fileSecurity' => false, - ] + ], ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -315,8 +330,10 @@ class StorageServerTest extends Scope /** * @depends testCreateFile + * * @param $file * @return array + * * @throws \Exception */ public function testUpdateFile($file): array @@ -333,7 +350,7 @@ class StorageServerTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -351,7 +368,9 @@ class StorageServerTest extends Scope /** * @depends testCreateFile + * * @param $file + * * @throws \Exception */ public function testDeleteFile($file): void @@ -363,7 +382,7 @@ class StorageServerTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ] + ], ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -377,8 +396,10 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket + * * @param $bucket * @return array + * * @throws \Exception */ public function testDeleteBucket($bucket): void @@ -389,7 +410,7 @@ class StorageServerTest extends Scope 'query' => $query, 'variables' => [ 'bucketId' => $bucket['_id'], - ] + ], ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/TeamsServerTest.php b/tests/e2e/Services/GraphQL/TeamsServerTest.php index 33c7847113..a8d8f64ac6 100644 --- a/tests/e2e/Services/GraphQL/TeamsServerTest.php +++ b/tests/e2e/Services/GraphQL/TeamsServerTest.php @@ -125,10 +125,10 @@ class TeamsServerTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'teamId' => $team['_id'], + 'teamId' => $team['_id'], 'prefs' => [ - 'key' => 'value' - ] + 'key' => 'value', + ], ], ]; @@ -156,7 +156,7 @@ class TeamsServerTest extends Scope 'query' => $query, 'variables' => [ 'teamId' => $team['_id'], - ] + ], ]; $prefs = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/UsersTest.php b/tests/e2e/Services/GraphQL/UsersTest.php index 9bd503df0f..e965fc5899 100644 --- a/tests/e2e/Services/GraphQL/UsersTest.php +++ b/tests/e2e/Services/GraphQL/UsersTest.php @@ -7,7 +7,6 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; use Utopia\Database\Helpers\ID; -use Utopia\Database\Query; class UsersTest extends Scope { @@ -27,7 +26,7 @@ class UsersTest extends Scope 'email' => $email, 'password' => 'password', 'name' => 'Project User', - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -56,7 +55,7 @@ class UsersTest extends Scope 'limit(100)', 'offset(0)', ], - ] + ], ]; $users = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -78,7 +77,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -100,7 +99,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -121,7 +120,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -142,7 +141,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -163,7 +162,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -185,7 +184,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'status' => true, - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -208,7 +207,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'emailVerification' => true, - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -230,7 +229,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'phoneVerification' => true, - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -253,7 +252,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'name' => 'Updated Name', - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -275,7 +274,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - 'email' => 'newemail@appwrite.io' + 'email' => 'newemail@appwrite.io', ], ]; @@ -298,7 +297,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - 'password' => 'newpassword' + 'password' => 'newpassword', ], ]; @@ -320,7 +319,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - 'number' => '+123456789' + 'number' => '+123456789', ], ]; @@ -344,8 +343,8 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'prefs' => [ - 'key' => 'value' - ] + 'key' => 'value', + ], ], ]; @@ -368,7 +367,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -392,7 +391,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'sessionId' => $this->getUser()['sessionId'], - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -415,7 +414,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ] + ], ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/Health/HealthBase.php b/tests/e2e/Services/Health/HealthBase.php index cbd0f97668..545cbc893f 100644 --- a/tests/e2e/Services/Health/HealthBase.php +++ b/tests/e2e/Services/Health/HealthBase.php @@ -2,8 +2,6 @@ namespace Tests\E2E\Services\Health; -use Tests\E2E\Client; - trait HealthBase { } diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php index 96c9bde5c7..23b9833c96 100644 --- a/tests/e2e/Services/Health/HealthCustomServerTest.php +++ b/tests/e2e/Services/Health/HealthCustomServerTest.php @@ -3,9 +3,8 @@ namespace Tests\E2E\Services\Health; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; -use Tests\E2E\Scopes\SideClient; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; class HealthCustomServerTest extends Scope diff --git a/tests/e2e/Services/Locale/LocaleBase.php b/tests/e2e/Services/Locale/LocaleBase.php index 17b5c66d67..38d6a61fd5 100644 --- a/tests/e2e/Services/Locale/LocaleBase.php +++ b/tests/e2e/Services/Locale/LocaleBase.php @@ -100,7 +100,6 @@ trait LocaleBase $this->assertEquals($response['body']['countries'][0]['name'], 'Alemania'); $this->assertEquals($response['body']['countries'][0]['code'], 'DE'); - /** * Test for FAILURE */ @@ -162,7 +161,6 @@ trait LocaleBase $this->assertEquals($response['body']['continents'][0]['code'], 'NA'); $this->assertEquals($response['body']['continents'][0]['name'], 'América del Norte'); - /** * Test for FAILURE */ @@ -227,9 +225,9 @@ trait LocaleBase /** * Test for SUCCESS */ - $languages = require('app/config/locale/codes.php'); - $defaultCountries = require('app/config/locale/countries.php'); - $defaultContinents = require('app/config/locale/continents.php'); + $languages = require 'app/config/locale/codes.php'; + $defaultCountries = require 'app/config/locale/countries.php'; + $defaultContinents = require 'app/config/locale/continents.php'; foreach ($languages as $lang) { $response = $this->client->call(Client::METHOD_GET, '/locale/countries', [ @@ -238,12 +236,12 @@ trait LocaleBase 'x-appwrite-locale' => $lang['code'], ]); - if (!\is_array($response['body']['countries'])) { - throw new Exception('Failed to iterate locale: ' . $lang); + if (! \is_array($response['body']['countries'])) { + throw new Exception('Failed to iterate locale: '.$lang); } foreach ($response['body']['countries'] as $i => $code) { - $this->assertContains($code['code'], $defaultCountries, $code['code'] . ' country should be removed from ' . $lang['code']); + $this->assertContains($code['code'], $defaultCountries, $code['code'].' country should be removed from '.$lang['code']); } $this->assertEquals($response['headers']['status-code'], 200); @@ -256,7 +254,7 @@ trait LocaleBase ]); foreach ($response['body']['continents'] as $i => $code) { - $this->assertContains($code['code'], $defaultContinents, $code['code'] . ' continent should be removed from ' . $lang['code']); + $this->assertContains($code['code'], $defaultContinents, $code['code'].' continent should be removed from '.$lang['code']); } $this->assertEquals($response['headers']['status-code'], 200); diff --git a/tests/e2e/Services/Locale/LocaleConsoleClientTest.php b/tests/e2e/Services/Locale/LocaleConsoleClientTest.php index 29b3150fed..c72e554df7 100644 --- a/tests/e2e/Services/Locale/LocaleConsoleClientTest.php +++ b/tests/e2e/Services/Locale/LocaleConsoleClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Locale; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class LocaleConsoleClientTest extends Scope diff --git a/tests/e2e/Services/Locale/LocaleCustomClientTest.php b/tests/e2e/Services/Locale/LocaleCustomClientTest.php index b28584280e..6d6108dec1 100644 --- a/tests/e2e/Services/Locale/LocaleCustomClientTest.php +++ b/tests/e2e/Services/Locale/LocaleCustomClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Locale; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class LocaleCustomClientTest extends Scope diff --git a/tests/e2e/Services/Locale/LocaleCustomServerTest.php b/tests/e2e/Services/Locale/LocaleCustomServerTest.php index 62d4e76802..1513f9b342 100644 --- a/tests/e2e/Services/Locale/LocaleCustomServerTest.php +++ b/tests/e2e/Services/Locale/LocaleCustomServerTest.php @@ -2,7 +2,6 @@ namespace Tests\E2E\Services\Locale; -use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; diff --git a/tests/e2e/Services/Messaging/MessagingServerTest.php b/tests/e2e/Services/Messaging/MessagingServerTest.php index 9bc9f93caf..8f477173eb 100644 --- a/tests/e2e/Services/Messaging/MessagingServerTest.php +++ b/tests/e2e/Services/Messaging/MessagingServerTest.php @@ -65,7 +65,7 @@ class MessagingServerTest extends Scope $providers = []; foreach (\array_keys($providersParams) as $key) { - $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/' . $key, [ + $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/'.$key, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -132,7 +132,7 @@ class MessagingServerTest extends Scope ], ]; foreach (\array_keys($providersParams) as $index => $key) { - $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/' . $providers[$index]['$id'] . '/' . $key, [ + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/'.$providers[$index]['$id'].'/'.$key, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -164,7 +164,7 @@ class MessagingServerTest extends Scope */ public function testGetProvider(array $providers) { - $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'], [ + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/'.$providers[0]['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -179,7 +179,7 @@ class MessagingServerTest extends Scope public function testDeleteProvider(array $providers) { foreach ($providers as $provider) { - $response = $this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $provider['$id'], [ + $response = $this->client->call(Client::METHOD_DELETE, '/messaging/providers/'.$provider['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -187,5 +187,4 @@ class MessagingServerTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } } - } diff --git a/tests/e2e/Services/Projects/ProjectsBase.php b/tests/e2e/Services/Projects/ProjectsBase.php index a9ccd73900..53d9626252 100644 --- a/tests/e2e/Services/Projects/ProjectsBase.php +++ b/tests/e2e/Services/Projects/ProjectsBase.php @@ -2,8 +2,6 @@ namespace Tests\E2E\Services\Projects; -use Tests\E2E\Client; - trait ProjectsBase { } diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 31c8c72a14..5006ab224a 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -4,10 +4,10 @@ namespace Tests\E2E\Services\Projects; use Appwrite\Auth\Auth; use Appwrite\Extend\Exception; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectConsole; -use Tests\E2E\Scopes\SideClient; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\SideClient; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; @@ -84,7 +84,7 @@ class ProjectsConsoleClientTest extends Scope 'projectId' => ID::unique(), 'name' => '', 'teamId' => $team['body']['$id'], - 'region' => 'default' + 'region' => 'default', ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -95,14 +95,14 @@ class ProjectsConsoleClientTest extends Scope ], $this->getHeaders()), [ 'projectId' => ID::unique(), 'name' => 'Project Test', - 'region' => 'default' + 'region' => 'default', ]); $this->assertEquals(400, $response['headers']['status-code']); return [ 'projectId' => $projectId, - 'teamId' => $team['body']['$id'] + 'teamId' => $team['body']['$id'], ]; } @@ -124,7 +124,7 @@ class ProjectsConsoleClientTest extends Scope 'projectId' => $projectId, 'name' => 'Project Duplicate', 'teamId' => $teamId, - 'region' => 'default' + 'region' => 'default', ]); $this->assertEquals(409, $response['headers']['status-code']); @@ -187,7 +187,7 @@ class ProjectsConsoleClientTest extends Scope $projectId = $response['body']['$id']; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $projectId . '/team', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$projectId.'/team', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -211,7 +211,6 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -229,7 +228,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders(), [ - 'search' => $id + 'search' => $id, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -242,7 +241,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders(), [ - 'search' => 'Project Test' + 'search' => 'Project Test', ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -273,7 +272,7 @@ class ProjectsConsoleClientTest extends Scope 'projectId' => ID::unique(), 'name' => 'Project Test 2', 'teamId' => $team['body']['$id'], - 'region' => 'default' + 'region' => 'default', ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -288,7 +287,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("teamId", "' . $team['body']['$id'] . '")' ], + 'queries' => ['equal("teamId", "'.$team['body']['$id'].'")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -300,7 +299,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'limit(1)' ], + 'queries' => ['limit(1)'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -312,7 +311,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'offset(3)' ], + 'queries' => ['offset(3)'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -324,7 +323,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("name", "Project Test 2")' ], + 'queries' => ['equal("name", "Project Test 2")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -336,7 +335,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'orderDesc("")' ], + 'queries' => ['orderDesc("")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -360,7 +359,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'cursorAfter("' . $response['body']['projects'][0]['$id'] . '")' ], + 'queries' => ['cursorAfter("'.$response['body']['projects'][0]['$id'].'")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -372,7 +371,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'cursorBefore("' . $response['body']['projects'][0]['$id'] . '")' ], + 'queries' => ['cursorBefore("'.$response['body']['projects'][0]['$id'].'")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -387,7 +386,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'cursorAfter("unknown")' ], + 'queries' => ['cursorAfter("unknown")'], ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -405,7 +404,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -418,7 +417,6 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/empty', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -467,7 +465,6 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/empty', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -495,7 +492,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -515,7 +512,6 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -536,7 +532,7 @@ class ProjectsConsoleClientTest extends Scope public function testUpdateProjectSMTP($data): array { $id = $data['projectId']; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/smtp', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/smtp', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -558,7 +554,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('', $response['body']['smtpSecure']); /** Test Reading Project */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -573,7 +569,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('', $response['body']['smtpSecure']); /** Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/smtp', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/smtp', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -584,6 +580,7 @@ class ProjectsConsoleClientTest extends Scope 'username' => 'user', 'password' => 'password', ]); + return $data; } @@ -595,7 +592,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId']; /** Get Default Email Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/email/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/templates/email/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -609,7 +606,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertMatchesRegularExpression('//', $response['body']['message']); /** Update Email template */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/templates/email/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/templates/email/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -628,7 +625,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('Please verify your email {{url}}', $response['body']['message']); /** Get Updated Email Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/email/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/templates/email/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -642,7 +639,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('Please verify your email {{url}}', $response['body']['message']); /** Get Default SMS Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/templates/sms/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -653,7 +650,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('{{token}}', $response['body']['message']); /** Update SMS template */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/templates/sms/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -666,7 +663,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('Please verify your email {{token}}', $response['body']['message']); /** Get Updated SMS Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/templates/sms/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -685,7 +682,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId']; // Check defaults - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', ], $this->getHeaders())); @@ -696,8 +693,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/duration', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/duration', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -720,7 +716,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'userId' => 'unique()', - 'email' => 'test' . rand(0, 9999) . '@example.com', + 'email' => 'test'.rand(0, 9999).'@example.com', 'password' => 'password', 'name' => 'Test User', ]); @@ -777,7 +773,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(401, $response['headers']['status-code']); // Return project back to normal - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/duration', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/duration', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -788,7 +784,7 @@ class ProjectsConsoleClientTest extends Scope $projectId = $response['body']['$id']; // Check project is back to normal - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $projectId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$projectId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', ], $this->getHeaders())); @@ -805,27 +801,26 @@ class ProjectsConsoleClientTest extends Scope public function testUpdateProjectOAuth($data): array { $id = $data['projectId'] ?? ''; - $providers = require('app/config/authProviders.php'); + $providers = require 'app/config/authProviders.php'; /** * Test for SUCCESS */ - foreach ($providers as $key => $provider) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/oauth2', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'provider' => $key, - 'appId' => 'AppId-' . ucfirst($key), - 'secret' => 'Secret-' . ucfirst($key), + 'appId' => 'AppId-'.ucfirst($key), + 'secret' => 'Secret-'.ucfirst($key), ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); } - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -838,8 +833,8 @@ class ProjectsConsoleClientTest extends Scope $asserted = false; foreach ($response['body']['providers'] as $responseProvider) { if ($responseProvider['key'] === $key) { - $this->assertEquals('AppId-' . ucfirst($key), $responseProvider['appId']); - $this->assertEquals('Secret-' . ucfirst($key), $responseProvider['secret']); + $this->assertEquals('AppId-'.ucfirst($key), $responseProvider['appId']); + $this->assertEquals('Secret-'.ucfirst($key), $responseProvider['secret']); $this->assertFalse($responseProvider['enabled']); $asserted = true; break; @@ -852,12 +847,12 @@ class ProjectsConsoleClientTest extends Scope // Enable providers $i = 0; foreach ($providers as $key => $provider) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/oauth2', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'provider' => $key, - 'enabled' => $i === 0 ? false : true // On first provider, test enabled=false + 'enabled' => $i === 0 ? false : true, // On first provider, test enabled=false ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -866,7 +861,7 @@ class ProjectsConsoleClientTest extends Scope $i++; } - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -895,8 +890,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/oauth2', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -916,9 +910,9 @@ class ProjectsConsoleClientTest extends Scope public function testUpdateProjectAuthStatus($data): array { $id = $data['projectId'] ?? ''; - $auth = require('app/config/auth.php'); + $auth = require 'app/config/auth.php'; - $originalEmail = uniqid() . 'user@localhost.test'; + $originalEmail = uniqid().'user@localhost.test'; $originalPassword = 'password'; $originalName = 'User Name'; @@ -942,13 +936,13 @@ class ProjectsConsoleClientTest extends Scope 'password' => $originalPassword, ]); - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $id]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$id]; /** * Test for SUCCESS */ foreach ($auth as $index => $method) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/' . $index, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/'.$index, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -958,17 +952,17 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(false, $response['body']['auth' . ucfirst($method['key'])]); + $this->assertEquals(false, $response['body']['auth'.ucfirst($method['key'])]); } - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -991,25 +985,25 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/teams', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'cookie' => 'a_session_' . $id . '=' . $session, + 'cookie' => 'a_session_'.$id.'='.$session, ]), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal' + 'name' => 'Arsenal', ]); $this->assertEquals(201, $response['headers']['status-code']); $teamUid = $response['body']['$id']; - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'cookie' => 'a_session_' . $id . '=' . $session, + 'cookie' => 'a_session_'.$id.'='.$session, ]), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals($response['headers']['status-code'], 501); @@ -1017,7 +1011,7 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/account/jwt', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'cookie' => 'a_session_' . $id . '=' . $session, + 'cookie' => 'a_session_'.$id.'='.$session, ])); $this->assertEquals($response['headers']['status-code'], 501); @@ -1044,7 +1038,7 @@ class ProjectsConsoleClientTest extends Scope // Cleanup foreach ($auth as $index => $method) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/' . $index, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/'.$index, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1065,7 +1059,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/limit', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/limit', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1075,7 +1069,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -1093,7 +1087,7 @@ class ProjectsConsoleClientTest extends Scope 'name' => $name, ]); - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ 'origin' => 'http://localhost', @@ -1111,7 +1105,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/limit', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/limit', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1121,7 +1115,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ 'origin' => 'http://localhost', @@ -1149,7 +1143,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for failure */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/max-sessions', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/max-sessions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1161,7 +1155,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/max-sessions', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/max-sessions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1172,7 +1166,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertNotEmpty($response['body']['$id']); $this->assertEquals(1, $response['body']['authSessionsLimit']); - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -1204,7 +1198,6 @@ class ProjectsConsoleClientTest extends Scope 'password' => $password, ]); - $this->assertEquals(201, $response['headers']['status-code']); $sessionId1 = $response['body']['$id']; @@ -1220,7 +1213,6 @@ class ProjectsConsoleClientTest extends Scope 'password' => $password, ]); - $this->assertEquals(201, $response['headers']['status-code']); $sessionCookie = $response['headers']['set-cookie']; $sessionId2 = $response['body']['$id']; @@ -1247,7 +1239,7 @@ class ProjectsConsoleClientTest extends Scope /** * Reset Limit */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/max-sessions', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/max-sessions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1257,7 +1249,6 @@ class ProjectsConsoleClientTest extends Scope return $data; } - /** * @depends testUpdateProjectAuthLimit */ @@ -1268,7 +1259,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for Failure */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1277,11 +1268,10 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - /** * Test for Success */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1291,8 +1281,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['authPasswordHistory']); - - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -1324,13 +1313,13 @@ class ProjectsConsoleClientTest extends Scope 'password' => $password, ]); $this->assertEquals(201, $session['headers']['status-code']); - $session = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $id]; + $session = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$id]; $response = $this->client->call(Client::METHOD_PATCH, '/account/password', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'cookie' => 'a_session_' . $id . '=' . $session, + 'cookie' => 'a_session_'.$id.'='.$session, ]), [ 'oldPassword' => $password, 'password' => $password, @@ -1344,17 +1333,16 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]); - $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $userId . '/password', $headers, [ + $response = $this->client->call(Client::METHOD_PATCH, '/users/'.$userId.'/password', $headers, [ 'password' => $password, ]); $this->assertEquals(400, $response['headers']['status-code']); - - /** + /** * Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1363,6 +1351,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(0, $response['body']['authPasswordHistory']); + return $data; } @@ -1389,7 +1378,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]), [ 'userId' => ID::unique(), - 'email' => uniqid() . 'user@localhost.test', + 'email' => uniqid().'user@localhost.test', 'password' => $password, 'name' => $name, ]); @@ -1405,7 +1394,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-mode' => 'admin', ]), [ 'userId' => ID::unique(), - 'email' => uniqid() . 'user@localhost.test', + 'email' => uniqid().'user@localhost.test', 'password' => 'password', 'name' => 'Cristiano Ronaldo', ]); @@ -1414,7 +1403,7 @@ class ProjectsConsoleClientTest extends Scope /** * Enable Disctionary */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-dictionary', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-dictionary', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1433,7 +1422,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]), [ 'userId' => ID::unique(), - 'email' => uniqid() . 'user@localhost.test', + 'email' => uniqid().'user@localhost.test', 'password' => $password, 'name' => $name, ]); @@ -1449,7 +1438,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-mode' => 'admin', ]), [ 'userId' => ID::unique(), - 'email' => uniqid() . 'user@localhost.test', + 'email' => uniqid().'user@localhost.test', 'password' => 'password', 'name' => 'Cristiano Ronaldo', ]); @@ -1461,17 +1450,16 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]); - $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $userId . '/password', $headers, [ + $response = $this->client->call(Client::METHOD_PATCH, '/users/'.$userId.'/password', $headers, [ 'password' => $password, ]); $this->assertEquals(400, $response['headers']['status-code']); - - /** + /** * Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1484,7 +1472,7 @@ class ProjectsConsoleClientTest extends Scope /** * Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-dictionary', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-dictionary', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1507,7 +1495,7 @@ class ProjectsConsoleClientTest extends Scope /** * Enable Disallowing of Personal Data */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/personal-data', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/personal-data', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1520,7 +1508,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for failure */ - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'username'; $userId = ID::unique(); @@ -1533,7 +1521,7 @@ class ProjectsConsoleClientTest extends Scope 'email' => $email, 'password' => $email, 'name' => $name, - 'userId' => $userId + 'userId' => $userId, ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -1548,7 +1536,7 @@ class ProjectsConsoleClientTest extends Scope 'email' => $email, 'password' => $name, 'name' => $name, - 'userId' => $userId + 'userId' => $userId, ]); $phone = '+123456789'; @@ -1561,7 +1549,7 @@ class ProjectsConsoleClientTest extends Scope 'password' => $phone, 'name' => $name, 'userId' => $userId, - 'phone' => $phone + 'phone' => $phone, ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -1569,7 +1557,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(Exception::USER_PASSWORD_PERSONAL_DATA, $response['body']['type']); /** Test for success */ - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'username'; $userId = ID::unique(); @@ -1581,12 +1569,12 @@ class ProjectsConsoleClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'userId' => $userId + 'userId' => $userId, ]); $this->assertEquals(201, $response['headers']['status-code']); - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $userId = ID::unique(); $response = $this->client->call(Client::METHOD_POST, '/users', array_merge($this->getHeaders(), [ 'content-type' => 'application/json', @@ -1597,16 +1585,15 @@ class ProjectsConsoleClientTest extends Scope 'password' => $password, 'name' => $name, 'userId' => $userId, - 'phone' => $phone + 'phone' => $phone, ]); $this->assertEquals(201, $response['headers']['status-code']); - /** * Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/personal-data', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/personal-data', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1617,13 +1604,12 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(false, $response['body']['authPersonalDataCheck']); } - public function testUpdateProjectServiceStatusAdmin(): array { $team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), [ 'teamId' => ID::unique(), 'name' => 'Project Test', @@ -1634,34 +1620,34 @@ class ProjectsConsoleClientTest extends Scope $project = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), [ 'projectId' => ID::unique(), 'name' => 'Project Test', 'teamId' => $team['body']['$id'], - 'region' => 'default' + 'region' => 'default', ]); $this->assertEquals(201, $project['headers']['status-code']); $this->assertNotEmpty($project['body']['$id']); $id = $project['body']['$id']; - $services = require('app/config/services.php'); + $services = require 'app/config/services.php'; /** * Test for Disabled */ foreach ($services as $service) { - if (!$service['optional']) { + if (! $service['optional']) { continue; } $key = $service['key'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), [ 'service' => $key, 'status' => false, @@ -1670,40 +1656,39 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(false, $response['body']['serviceStatusFor' . ucfirst($key)]); + $this->assertEquals(false, $response['body']['serviceStatusFor'.ucfirst($key)]); } /** * Admin request must succeed */ - $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', // 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $id, - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], - 'x-appwrite-mode' => 'admin' + 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'x-appwrite-mode' => 'admin', ])); $this->assertEquals(200, $response['headers']['status-code']); foreach ($services as $service) { - if (!$service['optional']) { + if (! $service['optional']) { continue; } $key = $service['key'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service/', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1720,22 +1705,22 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId']; - $services = require('app/config/services.php'); + $services = require 'app/config/services.php'; /** * Test for Disabled */ foreach ($services as $service) { - if (!$service['optional']) { + if (! $service['optional']) { continue; } $key = $service['key'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), [ 'service' => $key, 'status' => false, @@ -1744,15 +1729,15 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(false, $response['body']['serviceStatusFor' . ucfirst($key)]); + $this->assertEquals(false, $response['body']['serviceStatusFor'.ucfirst($key)]); } /** @@ -1771,7 +1756,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal' + 'name' => 'Arsenal', ]); $this->assertEquals(503, $response['headers']['status-code']); @@ -1779,7 +1764,7 @@ class ProjectsConsoleClientTest extends Scope // Cleanup foreach ($services as $service) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service/', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1794,22 +1779,22 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId']; - $services = require('app/config/services.php'); + $services = require 'app/config/services.php'; /** * Test for Disabled */ foreach ($services as $service) { - if (!$service['optional']) { + if (! $service['optional']) { continue; } $key = $service['key'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), [ 'service' => $key, 'status' => false, @@ -1818,22 +1803,22 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(false, $response['body']['serviceStatusFor' . ucfirst($key)]); + $this->assertEquals(false, $response['body']['serviceStatusFor'.ucfirst($key)]); } // Create API Key - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), [ 'name' => 'Key Test', 'scopes' => ['functions.read', 'teams.write'], @@ -1851,7 +1836,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $id, 'x-appwrite-key' => $keySecret, - 'x-sdk-name' => 'python' + 'x-sdk-name' => 'python', ])); $this->assertEquals(200, $response['headers']['status-code']); @@ -1860,19 +1845,19 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $id, 'x-appwrite-key' => $keySecret, - 'x-sdk-name' => 'php' + 'x-sdk-name' => 'php', ]), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal' + 'name' => 'Arsenal', ]); $this->assertEquals(201, $response['headers']['status-code']); /** Check that the API key has been updated */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), []); $this->assertEquals(200, $response['headers']['status-code']); @@ -1885,16 +1870,16 @@ class ProjectsConsoleClientTest extends Scope // Cleanup - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/keys/' . $keyId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/keys/'.$keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ]), []); $this->assertEquals(204, $response['headers']['status-code']); foreach ($services as $service) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service/', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1911,7 +1896,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1938,7 +1923,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1952,7 +1937,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1973,7 +1958,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -1996,7 +1981,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $webhookId = $data['webhookId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2014,7 +1999,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/error', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2032,7 +2017,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $webhookId = $data['webhookId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2056,7 +2041,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('', $response['body']['httpUser']); $this->assertEquals('', $response['body']['httpPass']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2078,7 +2063,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2090,7 +2075,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2102,7 +2087,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2125,7 +2110,7 @@ class ProjectsConsoleClientTest extends Scope $webhookId = $data['webhookId'] ?? ''; $signatureKey = $data['signatureKey'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/webhooks/' . $webhookId . '/signature', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/webhooks/'.$webhookId.'/signature', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2143,7 +2128,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $webhookId = $data['webhookId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2151,7 +2136,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2161,7 +2146,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/error', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2180,7 +2165,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2201,13 +2186,13 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, [ 'keyId' => $response['body']['$id'], - 'secret' => $response['body']['secret'] + 'secret' => $response['body']['secret'], ]); /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2220,7 +2205,6 @@ class ProjectsConsoleClientTest extends Scope return $data; } - /** * @depends testCreateProjectKey */ @@ -2228,12 +2212,11 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); - $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); @@ -2244,7 +2227,6 @@ class ProjectsConsoleClientTest extends Scope return $data; } - /** * @depends testCreateProjectKey */ @@ -2253,10 +2235,10 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $keyId = $data['keyId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $keyId + 'x-appwrite-key' => $keyId, ], $this->getHeaders()), []); $this->assertEquals(200, $response['headers']['status-code']); @@ -2275,7 +2257,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/error', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2295,7 +2277,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2307,7 +2289,7 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/health', [ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'x-appwrite-key' => $response['body']['secret'] + 'x-appwrite-key' => $response['body']['secret'], ], []); $this->assertEquals(200, $response['headers']['status-code']); @@ -2315,7 +2297,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2327,7 +2309,7 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/health', [ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'x-appwrite-key' => $response['body']['secret'] + 'x-appwrite-key' => $response['body']['secret'], ], []); $this->assertEquals(200, $response['headers']['status-code']); @@ -2335,7 +2317,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2347,13 +2329,12 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/health', [ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'x-appwrite-key' => $response['body']['secret'] + 'x-appwrite-key' => $response['body']['secret'], ], []); $this->assertEquals(401, $response['headers']['status-code']); } - /** * @depends testCreateProjectKey */ @@ -2362,7 +2343,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $keyId = $data['keyId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/keys/' . $keyId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/keys/'.$keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2384,7 +2365,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertArrayHasKey('accessedAt', $response['body']); $this->assertEmpty($response['body']['accessedAt']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2405,7 +2386,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/keys/' . $keyId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/keys/'.$keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2426,7 +2407,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $keyId = $data['keyId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/keys/' . $keyId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/keys/'.$keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2434,7 +2415,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2444,7 +2425,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/keys/error', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/keys/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2463,7 +2444,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2482,7 +2463,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformWebId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2501,7 +2482,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformFultteriOSId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2520,7 +2501,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformFultterAndroidId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2539,7 +2520,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformFultterWebId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2558,7 +2539,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformAppleIosId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2577,7 +2558,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformAppleMacOsId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2596,7 +2577,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformAppleWatchOsId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2618,7 +2599,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2641,7 +2622,7 @@ class ProjectsConsoleClientTest extends Scope sleep(1); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2665,7 +2646,7 @@ class ProjectsConsoleClientTest extends Scope $platformWebId = $data['platformWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2681,7 +2662,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultteriOSId = $data['platformFultteriOSId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2697,7 +2678,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterAndroidId = $data['platformFultterAndroidId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2713,7 +2694,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterWebId = $data['platformFultterWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterWebId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2729,7 +2710,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleIosId = $data['platformAppleIosId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2745,7 +2726,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleMacOsId = $data['platformAppleMacOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2761,7 +2742,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleWatchOsId = $data['platformAppleWatchOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2777,7 +2758,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleTvOsId = $data['platformAppleTvOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2794,7 +2775,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/error', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2813,7 +2794,7 @@ class ProjectsConsoleClientTest extends Scope $platformWebId = $data['platformWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2832,7 +2813,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultteriOSId = $data['platformFultteriOSId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2851,7 +2832,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterAndroidId = $data['platformFultterAndroidId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2870,7 +2851,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterWebId = $data['platformFultterWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformFultterWebId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformFultterWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2889,7 +2870,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleIosId = $data['platformAppleIosId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2908,7 +2889,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleMacOsId = $data['platformAppleMacOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2927,7 +2908,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleWatchOsId = $data['platformAppleWatchOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2946,7 +2927,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleTvOsId = $data['platformAppleTvOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2966,7 +2947,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/error', array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2988,7 +2969,7 @@ class ProjectsConsoleClientTest extends Scope $platformWebId = $data['platformWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2996,7 +2977,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3005,7 +2986,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultteriOSId = $data['platformFultteriOSId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3013,7 +2994,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3022,7 +3003,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterAndroidId = $data['platformFultterAndroidId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3030,7 +3011,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3039,7 +3020,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterWebId = $data['platformFultterWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformFultterWebId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformFultterWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3047,7 +3028,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterWebId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3056,7 +3037,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleIosId = $data['platformAppleIosId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3064,7 +3045,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3073,7 +3054,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleMacOsId = $data['platformAppleMacOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3081,7 +3062,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3090,7 +3071,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleWatchOsId = $data['platformAppleWatchOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3098,7 +3079,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3107,7 +3088,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleTvOsId = $data['platformAppleTvOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3115,7 +3096,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3125,7 +3106,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/error', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3144,7 +3125,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/domains', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/domains', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3164,7 +3145,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3173,13 +3154,13 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'type' => 'web', 'name' => 'Too Long Hostname', - 'hostname' => \str_repeat("bestdomain", 25) . '.com' // 250 + 4 chars total (exactly above limit) + 'hostname' => \str_repeat('bestdomain', 25).'.com', // 250 + 4 chars total (exactly above limit) ]); return $data; @@ -3192,7 +3173,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3215,7 +3196,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $domainId = $data['domainId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/' . $domainId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains/'.$domainId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3232,7 +3213,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/error', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3250,7 +3231,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $domainId = $data['domainId'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/domains/' . $domainId . '/verification', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/domains/'.$domainId.'/verification', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3272,7 +3253,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $domainId = $data['domainId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/domains/' . $domainId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/domains/'.$domainId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3280,7 +3261,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/' . $domainId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains/'.$domainId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3290,7 +3271,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/domains/error', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/domains/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3326,7 +3307,7 @@ class ProjectsConsoleClientTest extends Scope 'projectId' => ID::unique(), 'name' => 'Amazing Project', 'teamId' => $teamId, - 'region' => 'default' + 'region' => 'default', ]); $this->assertEquals(201, $project['headers']['status-code']); @@ -3337,14 +3318,14 @@ class ProjectsConsoleClientTest extends Scope $projectId = $project['body']['$id']; // Ensure I can get both team and project - $team = $this->client->call(Client::METHOD_GET, '/teams/' . $teamId, array_merge([ + $team = $this->client->call(Client::METHOD_GET, '/teams/'.$teamId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $team['headers']['status-code']); - $project = $this->client->call(Client::METHOD_GET, '/projects/' . $projectId, array_merge([ + $project = $this->client->call(Client::METHOD_GET, '/projects/'.$projectId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3352,7 +3333,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $project['headers']['status-code']); // Delete Project - $project = $this->client->call(Client::METHOD_DELETE, '/projects/' . $projectId, array_merge([ + $project = $this->client->call(Client::METHOD_DELETE, '/projects/'.$projectId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3360,14 +3341,14 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $project['headers']['status-code']); // Ensure I can get team but not a project - $team = $this->client->call(Client::METHOD_GET, '/teams/' . $teamId, array_merge([ + $team = $this->client->call(Client::METHOD_GET, '/teams/'.$teamId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $team['headers']['status-code']); - $project = $this->client->call(Client::METHOD_GET, '/projects/' . $projectId, array_merge([ + $project = $this->client->call(Client::METHOD_GET, '/projects/'.$projectId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/e2e/Services/Projects/ProjectsCustomClientTest.php b/tests/e2e/Services/Projects/ProjectsCustomClientTest.php index 9dfd48ce50..25140309af 100644 --- a/tests/e2e/Services/Projects/ProjectsCustomClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsCustomClientTest.php @@ -2,10 +2,9 @@ namespace Tests\E2E\Services\Projects; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; -use Tests\E2E\Client; class ProjectsCustomClientTest extends Scope { diff --git a/tests/e2e/Services/Projects/ProjectsCustomServerTest.php b/tests/e2e/Services/Projects/ProjectsCustomServerTest.php index 1c5b48f146..436d1df611 100644 --- a/tests/e2e/Services/Projects/ProjectsCustomServerTest.php +++ b/tests/e2e/Services/Projects/ProjectsCustomServerTest.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\Projects; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Tests\E2E\Client; class ProjectsCustomServerTest extends Scope { diff --git a/tests/e2e/Services/Realtime/RealtimeBase.php b/tests/e2e/Services/Realtime/RealtimeBase.php index 62bb7f5d3b..baf27e78ea 100644 --- a/tests/e2e/Services/Realtime/RealtimeBase.php +++ b/tests/e2e/Services/Realtime/RealtimeBase.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Realtime; -use WebSocket\ConnectionException; use WebSocket\Client as WebSocketClient; +use WebSocket\ConnectionException; trait RealtimeBase { @@ -14,15 +14,15 @@ trait RealtimeBase } $headers = array_merge([ - 'Origin' => 'appwrite.test' + 'Origin' => 'appwrite.test', ], $headers); $query = [ 'project' => $projectId, - 'channels' => $channels + 'channels' => $channels, ]; - return new WebSocketClient('ws://appwrite-traefik/v1/realtime?' . http_build_query($query), [ + return new WebSocketClient('ws://appwrite-traefik/v1/realtime?'.http_build_query($query), [ 'headers' => $headers, 'timeout' => 30, ]); @@ -57,8 +57,8 @@ trait RealtimeBase { $client = new WebSocketClient('ws://appwrite-traefik/v1/realtime?project=123', [ 'headers' => [ - 'Origin' => 'appwrite.test' - ] + 'Origin' => 'appwrite.test', + ], ]); $payload = json_decode($client->receive(), true); diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php index 3ef258885c..363da4d611 100644 --- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php @@ -4,8 +4,8 @@ namespace Tests\E2E\Services\Realtime; use CURLFile; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Tests\E2E\Services\Functions\FunctionsBase; use Utopia\Database\Helpers\ID; @@ -29,7 +29,7 @@ class RealtimeConsoleClientTest extends Scope * Test for SUCCESS */ $client = $this->getWebsocket(['account'], [ - 'origin' => 'http://localhost' + 'origin' => 'http://localhost', ]); $response = json_decode($client->receive(), true); @@ -43,8 +43,8 @@ class RealtimeConsoleClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', 'data' => [ - 'session' => $session - ] + 'session' => $session, + ], ])); $response = json_decode($client->receive(), true); @@ -64,8 +64,8 @@ class RealtimeConsoleClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', 'data' => [ - 'session' => 'invalid_session' - ] + 'session' => 'invalid_session', + ], ])); $response = json_decode($client->receive(), true); @@ -79,7 +79,7 @@ class RealtimeConsoleClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', - 'data' => [] + 'data' => [], ])); $response = json_decode($client->receive(), true); @@ -94,8 +94,8 @@ class RealtimeConsoleClientTest extends Scope $client->send(\json_encode([ 'type' => 'unknown', 'data' => [ - 'session' => 'invalid_session' - ] + 'session' => 'invalid_session', + ], ])); $response = json_decode($client->receive(), true); @@ -120,7 +120,6 @@ class RealtimeConsoleClientTest extends Scope $this->assertEquals(1003, $response['data']['code']); $this->assertEquals('Message format is not valid.', $response['data']['message']); - $client->close(); } @@ -131,7 +130,7 @@ class RealtimeConsoleClientTest extends Scope $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -159,7 +158,7 @@ class RealtimeConsoleClientTest extends Scope /** * Test Attributes */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -175,7 +174,7 @@ class RealtimeConsoleClientTest extends Scope $actorsId = $actors['body']['$id']; - $name = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ + $name = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -207,7 +206,7 @@ class RealtimeConsoleClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.attributes.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains("databases.*", $response['data']['events']); + $this->assertContains('databases.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals('processing', $response['data']['payload']['status']); @@ -227,7 +226,7 @@ class RealtimeConsoleClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.attributes.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains("databases.*", $response['data']['events']); + $this->assertContains('databases.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals('available', $response['data']['payload']['status']); @@ -248,7 +247,7 @@ class RealtimeConsoleClientTest extends Scope $databaseId = $data['databaseId']; $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -264,7 +263,7 @@ class RealtimeConsoleClientTest extends Scope /** * Test Indexes */ - $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -330,7 +329,7 @@ class RealtimeConsoleClientTest extends Scope $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -346,7 +345,7 @@ class RealtimeConsoleClientTest extends Scope /** * Test Delete Index */ - $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actorsId . '/indexes/key_name', array_merge([ + $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actorsId.'/indexes/key_name', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -386,7 +385,7 @@ class RealtimeConsoleClientTest extends Scope $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -402,7 +401,7 @@ class RealtimeConsoleClientTest extends Scope /** * Test Delete Attribute */ - $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/attributes/name', array_merge([ + $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['actorsId'].'/attributes/name', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -443,19 +442,18 @@ class RealtimeConsoleClientTest extends Scope 'users.*.delete', ], 'schedule' => '0 0 1 1 *', - 'timeout' => 10 + 'timeout' => 10, ]); $functionId = $response1['body']['$id'] ?? ''; $this->assertEquals(201, $response1['headers']['status-code']); - $projectId = 'console'; $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'cookie' => 'a_session_console='.$this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -471,18 +469,17 @@ class RealtimeConsoleClientTest extends Scope /** * Test Create Deployment */ - $folder = 'php'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([ + $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' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), - 'activate' => true + 'activate' => true, ]); $deploymentId = $deployment['body']['$id'] ?? ''; diff --git a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php index 4f880338a4..456bb7d333 100644 --- a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php @@ -4,8 +4,8 @@ namespace Tests\E2E\Services\Realtime; use CURLFile; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\CLI\Console; use Utopia\Database\Helpers\ID; @@ -25,9 +25,9 @@ class RealtimeCustomClientTest extends Scope $userId = $user['$id'] ?? ''; $session = $user['session'] ?? ''; - $headers = [ + $headers = [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]; $client = $this->getWebsocket(['documents'], $headers); @@ -54,7 +54,7 @@ class RealtimeCustomClientTest extends Scope $this->assertNotEmpty($response['data']['user']); $this->assertCount(2, $response['data']['channels']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertEquals($userId, $response['data']['user']['$id']); $client->close(); @@ -70,7 +70,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(3, $response['data']['channels']); $this->assertContains('documents', $response['data']['channels']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertEquals($userId, $response['data']['user']['$id']); $client->close(); @@ -96,7 +96,7 @@ class RealtimeCustomClientTest extends Scope $this->assertNotEmpty($response['data']['user']); $this->assertCount(10, $response['data']['channels']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains('files', $response['data']['channels']); $this->assertContains('files.1', $response['data']['channels']); $this->assertContains('collections', $response['data']['channels']); @@ -120,7 +120,7 @@ class RealtimeCustomClientTest extends Scope * Test for SUCCESS */ $client = $this->getWebsocket(['account'], [ - 'origin' => 'http://localhost' + 'origin' => 'http://localhost', ]); $response = json_decode($client->receive(), true); @@ -134,8 +134,8 @@ class RealtimeCustomClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', 'data' => [ - 'session' => $session - ] + 'session' => $session, + ], ])); $response = json_decode($client->receive(), true); @@ -155,8 +155,8 @@ class RealtimeCustomClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', 'data' => [ - 'session' => 'invalid_session' - ] + 'session' => 'invalid_session', + ], ])); $response = json_decode($client->receive(), true); @@ -170,7 +170,7 @@ class RealtimeCustomClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', - 'data' => [] + 'data' => [], ])); $response = json_decode($client->receive(), true); @@ -185,8 +185,8 @@ class RealtimeCustomClientTest extends Scope $client->send(\json_encode([ 'type' => 'unknown', 'data' => [ - 'session' => 'invalid_session' - ] + 'session' => 'invalid_session', + ], ])); $response = json_decode($client->receive(), true); @@ -211,7 +211,6 @@ class RealtimeCustomClientTest extends Scope $this->assertEquals(1003, $response['data']['code']); $this->assertEquals('Message format is not valid.', $response['data']['message']); - $client->close(); } @@ -242,7 +241,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['account'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_' . $projectId . '=' . $session + 'cookie' => 'a_session_'.$projectId.'='.$session, ]); $response = json_decode($client->receive(), true); @@ -252,22 +251,22 @@ class RealtimeCustomClientTest extends Scope $this->assertNotEmpty($response['data']); $this->assertCount(2, $response['data']['channels']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertNotEmpty($response['data']['user']); $this->assertEquals($userId, $response['data']['user']['$id']); /** * Test Account Name Event */ - $name = "Torsten Dittmann"; + $name = 'Torsten Dittmann'; $this->client->call(Client::METHOD_PATCH, '/account/name', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $session, + 'cookie' => 'a_session_'.$projectId.'='.$session, ]), [ - 'name' => $name + 'name' => $name, ]); $response = json_decode($client->receive(), true); @@ -279,18 +278,17 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.update.name", $response['data']['events']); $this->assertContains("users.{$userId}.update", $response['data']['events']); $this->assertContains("users.{$userId}", $response['data']['events']); - $this->assertContains("users.*.update.name", $response['data']['events']); - $this->assertContains("users.*.update", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.update.name', $response['data']['events']); + $this->assertContains('users.*.update', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($name, $response['data']['payload']['name']); - /** * Test Account Password Event */ @@ -298,7 +296,7 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $session, + 'cookie' => 'a_session_'.$projectId.'='.$session, ]), [ 'password' => 'new-password', 'oldPassword' => 'password', @@ -313,13 +311,13 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.update.password", $response['data']['events']); $this->assertContains("users.{$userId}.update", $response['data']['events']); $this->assertContains("users.{$userId}", $response['data']['events']); - $this->assertContains("users.*.update.password", $response['data']['events']); - $this->assertContains("users.*.update", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.update.password', $response['data']['events']); + $this->assertContains('users.*.update', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($name, $response['data']['payload']['name']); @@ -331,7 +329,7 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $session, + 'cookie' => 'a_session_'.$projectId.'='.$session, ]), [ 'email' => 'torsten@appwrite.io', 'password' => 'new-password', @@ -346,13 +344,13 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.update.email", $response['data']['events']); $this->assertContains("users.{$userId}.update", $response['data']['events']); $this->assertContains("users.{$userId}", $response['data']['events']); - $this->assertContains("users.*.update.email", $response['data']['events']); - $this->assertContains("users.*.update", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.update.email', $response['data']['events']); + $this->assertContains('users.*.update', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals('torsten@appwrite.io', $response['data']['payload']['email']); @@ -363,7 +361,7 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $session, + 'cookie' => 'a_session_'.$projectId.'='.$session, ]), [ 'url' => 'http://localhost/verification', ]); @@ -377,7 +375,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.verification.{$verificationId}.create", $response['data']['events']); $this->assertContains("users.{$userId}.verification.{$verificationId}", $response['data']['events']); $this->assertContains("users.{$userId}.verification.*.create", $response['data']['events']); @@ -385,9 +383,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.verification.{$verificationId}.create", $response['data']['events']); $this->assertContains("users.*.verification.{$verificationId}", $response['data']['events']); - $this->assertContains("users.*.verification.*.create", $response['data']['events']); - $this->assertContains("users.*.verification.*", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.verification.*.create', $response['data']['events']); + $this->assertContains('users.*.verification.*', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $lastEmail = $this->getLastEmail(); $verification = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); @@ -399,7 +397,7 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $session, + 'cookie' => 'a_session_'.$projectId.'='.$session, ]), [ 'userId' => $userId, 'secret' => $verification, @@ -414,7 +412,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.verification.{$verificationId}.update", $response['data']['events']); $this->assertContains("users.{$userId}.verification.{$verificationId}", $response['data']['events']); $this->assertContains("users.{$userId}.verification.*.update", $response['data']['events']); @@ -422,9 +420,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.verification.{$verificationId}.update", $response['data']['events']); $this->assertContains("users.*.verification.{$verificationId}", $response['data']['events']); - $this->assertContains("users.*.verification.*.update", $response['data']['events']); - $this->assertContains("users.*.verification.*", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.verification.*.update', $response['data']['events']); + $this->assertContains('users.*.verification.*', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); /** * Test Acoount Prefs Update */ @@ -432,12 +430,12 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $session, + 'cookie' => 'a_session_'.$projectId.'='.$session, ]), [ 'prefs' => [ 'prefKey1' => 'prefValue1', 'prefKey2' => 'prefValue2', - ] + ], ]); $response = json_decode($client->receive(), true); @@ -449,13 +447,13 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.update.prefs", $response['data']['events']); $this->assertContains("users.{$userId}.update", $response['data']['events']); $this->assertContains("users.{$userId}", $response['data']['events']); - $this->assertContains("users.*.update.prefs", $response['data']['events']); - $this->assertContains("users.*.update", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.update.prefs', $response['data']['events']); + $this->assertContains('users.*.update', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $createSession = function () use ($projectId): array { @@ -468,10 +466,10 @@ class RealtimeCustomClientTest extends Scope 'password' => 'new-password', ]); - $sessionNew = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $projectId]; + $sessionNew = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$projectId]; $sessionNewId = $response['body']['$id']; - return array("session" => $sessionNew, "sessionId" => $sessionNewId); + return ['session' => $sessionNew, 'sessionId' => $sessionNewId]; }; /** @@ -490,7 +488,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}.create", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.*.create", $response['data']['events']); @@ -498,19 +496,19 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}.create", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}", $response['data']['events']); - $this->assertContains("users.*.sessions.*.create", $response['data']['events']); - $this->assertContains("users.*.sessions.*", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.sessions.*.create', $response['data']['events']); + $this->assertContains('users.*.sessions.*', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test Account Session Delete */ - $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionNewId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionNewId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_' . $projectId . '=' . $sessionNew, + 'cookie' => 'a_session_'.$projectId.'='.$sessionNew, ])); $response = json_decode($client->receive(), true); @@ -522,7 +520,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}.delete", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.*.delete", $response['data']['events']); @@ -530,21 +528,20 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}.delete", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}", $response['data']['events']); - $this->assertContains("users.*.sessions.*.delete", $response['data']['events']); - $this->assertContains("users.*.sessions.*", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.sessions.*.delete', $response['data']['events']); + $this->assertContains('users.*.sessions.*', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test User Account Session Delete */ - $sessionData = $createSession(); $sessionNew = $sessionData['session']; $sessionNewId = $sessionData['sessionId']; $client->receive(); // Receive the creation message and drop; this was tested earlier already - $this->client->call(Client::METHOD_DELETE, '/users/' . $userId . '/sessions/' . $sessionNewId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/users/'.$userId.'/sessions/'.$sessionNewId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, @@ -559,7 +556,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}.delete", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.*.delete", $response['data']['events']); @@ -567,9 +564,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}.delete", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}", $response['data']['events']); - $this->assertContains("users.*.sessions.*.delete", $response['data']['events']); - $this->assertContains("users.*.sessions.*", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.sessions.*.delete', $response['data']['events']); + $this->assertContains('users.*.sessions.*', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** @@ -596,7 +593,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.recovery.{$recoveryId}.create", $response['data']['events']); $this->assertContains("users.{$userId}.recovery.{$recoveryId}", $response['data']['events']); $this->assertContains("users.{$userId}.recovery.*.create", $response['data']['events']); @@ -604,9 +601,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.recovery.{$recoveryId}.create", $response['data']['events']); $this->assertContains("users.*.recovery.{$recoveryId}", $response['data']['events']); - $this->assertContains("users.*.recovery.*.create", $response['data']['events']); - $this->assertContains("users.*.recovery.*", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.recovery.*.create', $response['data']['events']); + $this->assertContains('users.*.recovery.*', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $response = $this->client->call(Client::METHOD_PUT, '/account/recovery', array_merge([ @@ -629,7 +626,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.' . $userId, $response['data']['channels']); + $this->assertContains('account.'.$userId, $response['data']['channels']); $this->assertContains("users.{$userId}.recovery.{$recoveryId}.update", $response['data']['events']); $this->assertContains("users.{$userId}.recovery.{$recoveryId}", $response['data']['events']); $this->assertContains("users.{$userId}.recovery.*.update", $response['data']['events']); @@ -637,9 +634,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.recovery.{$recoveryId}.update", $response['data']['events']); $this->assertContains("users.*.recovery.{$recoveryId}", $response['data']['events']); - $this->assertContains("users.*.recovery.*.update", $response['data']['events']); - $this->assertContains("users.*.recovery.*", $response['data']['events']); - $this->assertContains("users.*", $response['data']['events']); + $this->assertContains('users.*.recovery.*.update', $response['data']['events']); + $this->assertContains('users.*.recovery.*', $response['data']['events']); + $this->assertContains('users.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $client->close(); @@ -653,7 +650,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['documents', 'collections'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_' . $projectId . '=' . $session + 'cookie' => 'a_session_'.$projectId.'='.$session, ]); $response = json_decode($client->receive(), true); @@ -674,7 +671,7 @@ class RealtimeCustomClientTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'Actors DB', @@ -685,10 +682,10 @@ class RealtimeCustomClientTest extends Scope /** * Test Collection Create */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -700,10 +697,10 @@ class RealtimeCustomClientTest extends Scope $actorsId = $actors['body']['$id']; - $name = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ + $name = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'name', 'size' => 256, @@ -721,13 +718,13 @@ class RealtimeCustomClientTest extends Scope /** * Test Document Create */ - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Chris Evans' + 'name' => 'Chris Evans', ], 'permissions' => [ Permission::read(Role::any()), @@ -747,8 +744,8 @@ class RealtimeCustomClientTest extends Scope $this->assertArrayHasKey('timestamp', $response['data']); $this->assertCount(3, $response['data']['channels']); $this->assertContains('documents', $response['data']['channels']); - $this->assertContains('databases.' . $databaseId . '.collections.' . $actorsId . '.documents.' . $documentId, $response['data']['channels']); - $this->assertContains('databases.' . $databaseId . '.collections.' . $actorsId . '.documents', $response['data']['channels']); + $this->assertContains('databases.'.$databaseId.'.collections.'.$actorsId.'.documents.'.$documentId, $response['data']['channels']); + $this->assertContains('databases.'.$databaseId.'.collections.'.$actorsId.'.documents', $response['data']['channels']); $this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.{$documentId}.create", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.{$documentId}", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.*.create", $response['data']['events']); @@ -760,20 +757,20 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains("databases.*", $response['data']['events']); + $this->assertContains('databases.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Chris Evans'); /** * Test Document Update */ - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$documentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Chris Evans 2' + 'name' => 'Chris Evans 2', ], 'permissions' => [ Permission::read(Role::any()), @@ -804,7 +801,7 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains("databases.*", $response['data']['events']); + $this->assertContains('databases.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2'); @@ -812,13 +809,13 @@ class RealtimeCustomClientTest extends Scope /** * Test Document Delete */ - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Bradley Cooper' + 'name' => 'Bradley Cooper', ], 'permissions' => [ Permission::read(Role::any()), @@ -831,7 +828,7 @@ class RealtimeCustomClientTest extends Scope $documentId = $document['body']['$id']; - $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$documentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -858,7 +855,7 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains("databases.*", $response['data']['events']); + $this->assertContains('databases.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper'); @@ -873,7 +870,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['documents', 'collections'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_' . $projectId . '=' . $session + 'cookie' => 'a_session_'.$projectId.'='.$session, ]); $response = json_decode($client->receive(), true); @@ -894,7 +891,7 @@ class RealtimeCustomClientTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'databaseId' => ID::unique(), 'name' => 'Actors DB', @@ -905,10 +902,10 @@ class RealtimeCustomClientTest extends Scope /** * Test Collection Create */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -917,15 +914,15 @@ class RealtimeCustomClientTest extends Scope Permission::create(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()), - ] + ], ]); $actorsId = $actors['body']['$id']; - $name = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ + $name = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'name', 'size' => 256, @@ -943,13 +940,13 @@ class RealtimeCustomClientTest extends Scope /** * Test Document Create */ - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Chris Evans' + 'name' => 'Chris Evans', ], 'permissions' => [], ]); @@ -978,19 +975,19 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains("databases.*", $response['data']['events']); + $this->assertContains('databases.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Chris Evans'); /** * Test Document Update */ - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$documentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => [ - 'name' => 'Chris Evans 2' + 'name' => 'Chris Evans 2', ], 'permissions' => [], ]); @@ -1017,7 +1014,7 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains("databases.*", $response['data']['events']); + $this->assertContains('databases.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2'); @@ -1025,13 +1022,13 @@ class RealtimeCustomClientTest extends Scope /** * Test Document Delete */ - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Bradley Cooper' + 'name' => 'Bradley Cooper', ], 'permissions' => [], ]); @@ -1040,7 +1037,7 @@ class RealtimeCustomClientTest extends Scope $client->receive(); - $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$documentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1067,7 +1064,7 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains("databases.*", $response['data']['events']); + $this->assertContains('databases.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper'); @@ -1082,7 +1079,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['files'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_' . $projectId . '=' . $session + 'cookie' => 'a_session_'.$projectId.'='.$session, ]); $response = json_decode($client->receive(), true); @@ -1101,7 +1098,7 @@ class RealtimeCustomClientTest extends Scope $bucket1 = $this->client->call(Client::METHOD_POST, '/storage/buckets', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'bucketId' => ID::unique(), 'name' => 'Bucket 1', @@ -1110,7 +1107,7 @@ class RealtimeCustomClientTest extends Scope Permission::create(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()), - ] + ], ]); $bucketId = $bucket1['body']['$id']; @@ -1118,12 +1115,12 @@ class RealtimeCustomClientTest extends Scope /** * Test File Create */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -1151,9 +1148,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("buckets.{$bucketId}", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}.create", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}", $response['data']['events']); - $this->assertContains("buckets.*.files.*.create", $response['data']['events']); - $this->assertContains("buckets.*.files.*", $response['data']['events']); - $this->assertContains("buckets.*", $response['data']['events']); + $this->assertContains('buckets.*.files.*.create', $response['data']['events']); + $this->assertContains('buckets.*.files.*', $response['data']['events']); + $this->assertContains('buckets.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $fileId = $file['body']['$id']; @@ -1161,7 +1158,7 @@ class RealtimeCustomClientTest extends Scope /** * Test File Update */ - $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1190,15 +1187,15 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("buckets.{$bucketId}", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}.update", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}", $response['data']['events']); - $this->assertContains("buckets.*.files.*.update", $response['data']['events']); - $this->assertContains("buckets.*.files.*", $response['data']['events']); - $this->assertContains("buckets.*", $response['data']['events']); + $this->assertContains('buckets.*.files.*.update', $response['data']['events']); + $this->assertContains('buckets.*.files.*', $response['data']['events']); + $this->assertContains('buckets.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test File Delete */ - $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1221,9 +1218,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("buckets.{$bucketId}", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}.delete", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}", $response['data']['events']); - $this->assertContains("buckets.*.files.*.delete", $response['data']['events']); - $this->assertContains("buckets.*.files.*", $response['data']['events']); - $this->assertContains("buckets.*", $response['data']['events']); + $this->assertContains('buckets.*.files.*.delete', $response['data']['events']); + $this->assertContains('buckets.*.files.*', $response['data']['events']); + $this->assertContains('buckets.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $client->close(); @@ -1237,7 +1234,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['executions'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_' . $projectId . '=' . $session + 'cookie' => 'a_session_'.$projectId.'='.$session, ]); $response = json_decode($client->receive(), true); @@ -1257,7 +1254,7 @@ class RealtimeCustomClientTest extends Scope $function = $this->client->call(Client::METHOD_POST, '/functions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'functionId' => ID::unique(), 'name' => 'Test', @@ -1274,18 +1271,18 @@ class RealtimeCustomClientTest extends Scope $folder = 'timeout'; $stderr = ''; $stdout = ''; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/{$folder}/code.tar.gz"; + $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); + 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([ + $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'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', basename($code)), - 'activate' => true + 'activate' => true, ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -1296,20 +1293,20 @@ class RealtimeCustomClientTest extends Scope // Wait for deployment to be built. sleep(10); - $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), []); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']['$id']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'async' => true + 'async' => true, ]); $this->assertEquals($execution['headers']['status-code'], 202); @@ -1337,9 +1334,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("functions.{$functionId}", $response['data']['events']); $this->assertContains("functions.*.executions.{$executionId}.create", $response['data']['events']); $this->assertContains("functions.*.executions.{$executionId}", $response['data']['events']); - $this->assertContains("functions.*.executions.*.create", $response['data']['events']); - $this->assertContains("functions.*.executions.*", $response['data']['events']); - $this->assertContains("functions.*", $response['data']['events']); + $this->assertContains('functions.*.executions.*.create', $response['data']['events']); + $this->assertContains('functions.*.executions.*', $response['data']['events']); + $this->assertContains('functions.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertArrayHasKey('type', $responseUpdate); @@ -1359,15 +1356,15 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("functions.{$functionId}", $responseUpdate['data']['events']); $this->assertContains("functions.*.executions.{$executionId}.update", $responseUpdate['data']['events']); $this->assertContains("functions.*.executions.{$executionId}", $responseUpdate['data']['events']); - $this->assertContains("functions.*.executions.*.update", $responseUpdate['data']['events']); - $this->assertContains("functions.*.executions.*", $responseUpdate['data']['events']); - $this->assertContains("functions.*", $responseUpdate['data']['events']); + $this->assertContains('functions.*.executions.*.update', $responseUpdate['data']['events']); + $this->assertContains('functions.*.executions.*', $responseUpdate['data']['events']); + $this->assertContains('functions.*', $responseUpdate['data']['events']); $this->assertNotEmpty($responseUpdate['data']['payload']); $client->close(); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ + $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'], @@ -1384,7 +1381,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['teams'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_' . $projectId . '=' . $session + 'cookie' => 'a_session_'.$projectId.'='.$session, ]); $response = json_decode($client->receive(), true); @@ -1406,7 +1403,7 @@ class RealtimeCustomClientTest extends Scope 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal' + 'name' => 'Arsenal', ]); $teamId = $team['body']['$id'] ?? ''; @@ -1426,18 +1423,18 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("teams.{$teamId}", $response['data']['channels']); $this->assertContains("teams.{$teamId}.create", $response['data']['events']); $this->assertContains("teams.{$teamId}", $response['data']['events']); - $this->assertContains("teams.*.create", $response['data']['events']); - $this->assertContains("teams.*", $response['data']['events']); + $this->assertContains('teams.*.create', $response['data']['events']); + $this->assertContains('teams.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test Team Update */ - $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamId, array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$teamId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ - 'name' => 'Manchester' + 'name' => 'Manchester', ]); $this->assertEquals($team['headers']['status-code'], 200); @@ -1455,21 +1452,21 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("teams.{$teamId}", $response['data']['channels']); $this->assertContains("teams.{$teamId}.update", $response['data']['events']); $this->assertContains("teams.{$teamId}", $response['data']['events']); - $this->assertContains("teams.*.update", $response['data']['events']); - $this->assertContains("teams.*", $response['data']['events']); + $this->assertContains('teams.*.update', $response['data']['events']); + $this->assertContains('teams.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test Team Update Prefs */ - $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamId . '/prefs', array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$teamId.'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'prefs' => [ 'funcKey1' => 'funcValue1', 'funcKey2' => 'funcValue2', - ] + ], ]); $this->assertEquals($team['headers']['status-code'], 200); @@ -1489,9 +1486,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("teams.{$teamId}.update", $response['data']['events']); $this->assertContains("teams.{$teamId}.update.prefs", $response['data']['events']); $this->assertContains("teams.{$teamId}", $response['data']['events']); - $this->assertContains("teams.*.update.prefs", $response['data']['events']); - $this->assertContains("teams.*.update", $response['data']['events']); - $this->assertContains("teams.*", $response['data']['events']); + $this->assertContains('teams.*.update.prefs', $response['data']['events']); + $this->assertContains('teams.*.update', $response['data']['events']); + $this->assertContains('teams.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['funcKey1'], 'funcValue1'); $this->assertEquals($response['data']['payload']['funcKey2'], 'funcValue2'); @@ -1514,7 +1511,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['memberships'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_' . $projectId . '=' . $session + 'cookie' => 'a_session_'.$projectId.'='.$session, ]); $response = json_decode($client->receive(), true); @@ -1528,7 +1525,7 @@ class RealtimeCustomClientTest extends Scope $this->assertNotEmpty($response['data']['user']); $this->assertEquals($user['$id'], $response['data']['user']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamId . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamId.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1539,12 +1536,12 @@ class RealtimeCustomClientTest extends Scope * Test Update Membership */ $roles = ['admin', 'editor', 'uncle']; - $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamId . '/memberships/' . $membershipId, array_merge([ + $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamId.'/memberships/'.$membershipId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'roles' => $roles + 'roles' => $roles, ]); $response = json_decode($client->receive(), true); @@ -1564,9 +1561,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("teams.{$teamId}", $response['data']['events']); $this->assertContains("teams.*.memberships.{$membershipId}.update", $response['data']['events']); $this->assertContains("teams.*.memberships.{$membershipId}", $response['data']['events']); - $this->assertContains("teams.*.memberships.*.update", $response['data']['events']); - $this->assertContains("teams.*.memberships.*", $response['data']['events']); - $this->assertContains("teams.*", $response['data']['events']); + $this->assertContains('teams.*.memberships.*.update', $response['data']['events']); + $this->assertContains('teams.*.memberships.*', $response['data']['events']); + $this->assertContains('teams.*', $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $client->close(); diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index b19fe49ed0..9b0a6449d3 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -4,7 +4,6 @@ namespace Tests\E2E\Services\Storage; use CURLFile; use Tests\E2E\Client; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -26,7 +25,7 @@ trait StorageBase 'name' => 'Test Bucket', 'fileSecurity' => true, 'maximumFileSize' => 2000000, //2MB - 'allowedFileExtensions' => ["jpg", "png"], + 'allowedFileExtensions' => ['jpg', 'png'], 'permissions' => [ Permission::read(Role::any()), Permission::create(Role::any()), @@ -39,12 +38,12 @@ trait StorageBase $bucketId = $bucket['body']['$id']; - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -58,7 +57,7 @@ trait StorageBase $this->assertEquals('logo.png', $file['body']['name']); $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) == $file['body']['signature']); + $this->assertTrue(md5_file(realpath(__DIR__.'/../../../resources/logo.png')) == $file['body']['signature']); /** * Test for Large File above 20MB * This should also validate the test for when Bucket encryption @@ -85,27 +84,26 @@ trait StorageBase /** * Chunked Upload */ - - $source = __DIR__ . "/../../../resources/disk-a/large-file.mp4"; + $source = __DIR__.'/../../../resources/disk-a/large-file.mp4'; $totalSize = \filesize($source); $chunkSize = 5 * 1024 * 1024; - $handle = @fopen($source, "rb"); + $handle = @fopen($source, 'rb'); $fileId = 'unique()'; $mimeType = mime_content_type($source); $counter = 0; $size = filesize($source); $headers = [ 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ]; $id = ''; - while (!feof($handle)) { - $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4'); - $headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size; - if (!empty($id)) { + while (! feof($handle)) { + $curlFile = new \CURLFile('data://'.$mimeType.';base64,'.base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4'); + $headers['content-range'] = 'bytes '.($counter * $chunkSize).'-'.min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1).'/'.$size; + if (! empty($id)) { $headers['x-appwrite-id'] = $id; } - $largeFile = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket2['body']['$id'] . '/files', array_merge($headers, $this->getHeaders()), [ + $largeFile = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucket2['body']['$id'].'/files', array_merge($headers, $this->getHeaders()), [ 'fileId' => $fileId, 'file' => $curlFile, 'permissions' => [ @@ -125,28 +123,28 @@ trait StorageBase $this->assertEquals('large-file.mp4', $largeFile['body']['name']); $this->assertEquals('video/mp4', $largeFile['body']['mimeType']); $this->assertEquals($totalSize, $largeFile['body']['sizeOriginal']); - $this->assertEquals(md5_file(realpath(__DIR__ . '/../../../resources/disk-a/large-file.mp4')), $largeFile['body']['signature']); // should validate that the file is not encrypted + $this->assertEquals(md5_file(realpath(__DIR__.'/../../../resources/disk-a/large-file.mp4')), $largeFile['body']['signature']); // should validate that the file is not encrypted /** * Failure * Test for Chunk above 5MB */ - $source = __DIR__ . "/../../../resources/disk-a/large-file.mp4"; + $source = __DIR__.'/../../../resources/disk-a/large-file.mp4'; $totalSize = \filesize($source); $chunkSize = 6 * 1024 * 1024; - $handle = @fopen($source, "rb"); + $handle = @fopen($source, 'rb'); $fileId = 'unique()'; $mimeType = mime_content_type($source); $counter = 0; $size = filesize($source); $headers = [ 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ]; $id = ''; - $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4'); - $headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size; - $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket2['body']['$id'] . '/files', $this->getHeaders(), [ + $curlFile = new \CURLFile('data://'.$mimeType.';base64,'.base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4'); + $headers['content-range'] = 'bytes '.($counter * $chunkSize).'-'.min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1).'/'.$size; + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucket2['body']['$id'].'/files', $this->getHeaders(), [ 'fileId' => $fileId, 'file' => $curlFile, 'permissions' => [ @@ -159,17 +157,15 @@ trait StorageBase $this->assertEquals(413, $res['headers']['status-code']); - /** * Test for FAILURE unknown Bucket */ - $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/empty/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -181,13 +177,12 @@ trait StorageBase /** * Test for FAILURE file above bucket's file size limit */ - - $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/disk-b/kitten-1.png'), 'image/png', 'kitten-1.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/disk-b/kitten-1.png'), 'image/png', 'kitten-1.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -201,13 +196,12 @@ trait StorageBase /** * Test for FAILURE unsupported bucket file extension */ - - $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/disk-a/kitten-3.gif'), 'image/gif', 'kitten-3.gif'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/disk-a/kitten-3.gif'), 'image/gif', 'kitten-3.gif'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -230,7 +224,7 @@ trait StorageBase 'name' => 'Test Bucket 2', 'fileSecurity' => true, 'maximumFileSize' => 200000000, //200MB - 'allowedFileExtensions' => ["jpg", "png"], + 'allowedFileExtensions' => ['jpg', 'png'], 'permissions' => [ Permission::read(Role::any()), Permission::create(Role::any()), @@ -244,12 +238,12 @@ trait StorageBase /** * Test for FAILURE set x-appwrite-id to unique() */ - $source = realpath(__DIR__ . '/../../../resources/logo.png'); + $source = realpath(__DIR__.'/../../../resources/logo.png'); $totalSize = \filesize($source); - $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'content-range' => 'bytes 0-' . $size . '/' . $size, + 'content-range' => 'bytes 0-'.$size.'/'.$size, 'x-appwrite-id' => 'unique()', ], $this->getHeaders()), [ 'fileId' => ID::unique(), @@ -278,7 +272,7 @@ trait StorageBase 'name' => 'Test Bucket', 'fileSecurity' => true, 'maximumFileSize' => 2000000, //2MB - 'allowedFileExtensions' => ["jpg", "png"], + 'allowedFileExtensions' => ['jpg', 'png'], 'compression' => 'zstd', 'permissions' => [ Permission::read(Role::any()), @@ -293,12 +287,12 @@ trait StorageBase $bucketId = $bucket['body']['$id']; - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -311,7 +305,7 @@ trait StorageBase $this->assertEquals('logo.png', $file['body']['name']); $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) == $file['body']['signature']); + $this->assertTrue(md5_file(realpath(__DIR__.'/../../../resources/logo.png')) == $file['body']['signature']); return ['bucketId' => $bucketId]; } @@ -324,7 +318,7 @@ trait StorageBase /** * Test for SUCCESS */ - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -332,38 +326,38 @@ trait StorageBase $this->assertGreaterThan(0, $files['body']['total']); $this->assertGreaterThan(0, count($files['body']['files'])); - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'limit(1)' ] + 'queries' => ['limit(1)'], ]); $this->assertEquals(200, $files['headers']['status-code']); $this->assertEquals(1, count($files['body']['files'])); - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'offset(1)' ] + 'queries' => ['offset(1)'], ]); $this->assertEquals(200, $files['headers']['status-code']); $this->assertEquals(0, count($files['body']['files'])); - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("mimeType", "image/png")' ] + 'queries' => ['equal("mimeType", "image/png")'], ]); $this->assertEquals(200, $files['headers']['status-code']); $this->assertEquals(1, count($files['body']['files'])); - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("mimeType", "image/jpeg")' ] + 'queries' => ['equal("mimeType", "image/jpeg")'], ]); $this->assertEquals(200, $files['headers']['status-code']); $this->assertEquals(0, count($files['body']['files'])); @@ -371,7 +365,6 @@ trait StorageBase /** * Test for FAILURE unknown Bucket */ - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/empty/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -390,7 +383,7 @@ trait StorageBase /** * Test for SUCCESS */ - $file1 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'], array_merge([ + $file1 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -404,7 +397,7 @@ trait StorageBase $this->assertIsArray($file1['body']['$permissions']); $this->assertCount(3, $file1['body']['$permissions']); - $file2 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/preview', array_merge([ + $file2 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -414,7 +407,7 @@ trait StorageBase $this->assertNotEmpty($file2['body']); //new image preview features - $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/preview', array_merge([ + $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -432,13 +425,13 @@ trait StorageBase $image = new \Imagick(); $image->readImageBlob($file3['body']); - $original = new \Imagick(__DIR__ . '/../../../resources/logo-after.png'); + $original = new \Imagick(__DIR__.'/../../../resources/logo-after.png'); $this->assertEquals($image->getImageWidth(), $original->getImageWidth()); $this->assertEquals($image->getImageHeight(), $original->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $file4 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/preview', array_merge([ + $file4 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -455,13 +448,13 @@ trait StorageBase $image = new \Imagick(); $image->readImageBlob($file4['body']); - $original = new \Imagick(__DIR__ . '/../../../resources/logo-after.jpg'); + $original = new \Imagick(__DIR__.'/../../../resources/logo-after.jpg'); $this->assertEquals($image->getImageWidth(), $original->getImageWidth()); $this->assertEquals($image->getImageHeight(), $original->getImageHeight()); $this->assertEquals('JPEG', $image->getImageFormat()); - $file5 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ + $file5 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -472,13 +465,13 @@ trait StorageBase $this->assertNotEmpty($file5['body']); // Test ranged download - $file51 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ + $file51 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'Range' => 'bytes=0-99', ], $this->getHeaders())); - $path = __DIR__ . '/../../../resources/logo.png'; + $path = __DIR__.'/../../../resources/logo.png'; $originalChunk = \file_get_contents($path, false, null, 0, 100); $this->assertEquals(206, $file51['headers']['status-code']); @@ -488,7 +481,7 @@ trait StorageBase $this->assertEquals($originalChunk, $file51['body']); // Test ranged download - with invalid range - $file52 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ + $file52 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'Range' => 'bytes=0-', @@ -497,7 +490,7 @@ trait StorageBase $this->assertEquals(206, $file52['headers']['status-code']); // Test ranged download - with invalid range - $file53 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ + $file53 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'Range' => 'bytes=988', @@ -506,7 +499,7 @@ trait StorageBase $this->assertEquals(416, $file53['headers']['status-code']); // Test ranged download - with invalid range - $file54 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ + $file54 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'Range' => 'bytes=-988', @@ -514,7 +507,7 @@ trait StorageBase $this->assertEquals(416, $file54['headers']['status-code']); - $file6 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/view', array_merge([ + $file6 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -524,7 +517,7 @@ trait StorageBase $this->assertNotEmpty($file6['body']); // Test for negative angle values in fileGetPreview - $file7 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/preview', array_merge([ + $file7 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -542,7 +535,7 @@ trait StorageBase $image = new \Imagick(); $image->readImageBlob($file7['body']); - $original = new \Imagick(__DIR__ . '/../../../resources/logo-after.png'); + $original = new \Imagick(__DIR__.'/../../../resources/logo-after.png'); $this->assertEquals($image->getImageWidth(), $original->getImageWidth()); $this->assertEquals($image->getImageHeight(), $original->getImageHeight()); @@ -551,7 +544,7 @@ trait StorageBase /** * Test large files decompress successfully */ - $file7 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['largeBucketId'] . '/files/' . $data['largeFileId'] . '/download', array_merge([ + $file7 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['largeBucketId'].'/files/'.$data['largeFileId'].'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -560,17 +553,16 @@ trait StorageBase $this->assertEquals('attachment; filename="large-file.mp4"', $file7['headers']['content-disposition']); $this->assertEquals('video/mp4', $file7['headers']['content-type']); $this->assertNotEmpty($fileData); - $this->assertEquals(md5_file(realpath(__DIR__ . '/../../../resources/disk-a/large-file.mp4')), md5($fileData)); // validate the file is downloaded correctly + $this->assertEquals(md5_file(realpath(__DIR__.'/../../../resources/disk-a/large-file.mp4')), md5($fileData)); // validate the file is downloaded correctly /** * Test for FAILURE unknown Bucket */ - - $file8 = $this->client->call(Client::METHOD_GET, '/storage/buckets/empty/files/' . $data['fileId'], array_merge([ + $file8 = $this->client->call(Client::METHOD_GET, '/storage/buckets/empty/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'limit' => 2 + 'limit' => 2, ]); $this->assertEquals(404, $file8['headers']['status-code']); @@ -585,12 +577,12 @@ trait StorageBase { $bucketId = $data['bucketId']; - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::custom('testcache'), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -603,7 +595,7 @@ trait StorageBase $fileId = $file['body']['$id']; //get image preview - $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -622,7 +614,7 @@ trait StorageBase $imageBefore = new \Imagick(); $imageBefore->readImageBlob($file3['body']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $data['bucketId'] . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$data['bucketId'].'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -631,12 +623,12 @@ trait StorageBase $this->assertEmpty($file['body']); sleep(1); //upload again using the same ID - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::custom('testcache'), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/disk-b/kitten-2.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/disk-b/kitten-2.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -647,7 +639,7 @@ trait StorageBase $this->assertNotEmpty($file['body']['$id']); //get image preview after - $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -678,12 +670,12 @@ trait StorageBase { $bucketId = $data['bucketId']; - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -696,7 +688,7 @@ trait StorageBase $fileId = $file['body']['$id']; //get image preview - $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -723,7 +715,7 @@ trait StorageBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -732,7 +724,7 @@ trait StorageBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); $this->assertEquals(200, $file['headers']['status-code']); @@ -754,8 +746,7 @@ trait StorageBase /** * Test for FAILURE unknown Bucket */ - - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/empty/files/' . $data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/empty/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -763,7 +754,7 @@ trait StorageBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ] + ], ]); $this->assertEquals(404, $file['headers']['status-code']); @@ -779,7 +770,7 @@ trait StorageBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -787,7 +778,7 @@ trait StorageBase $this->assertEquals(204, $file['headers']['status-code']); $this->assertEmpty($file['body']); - $file = $this->client->call(Client::METHOD_GET, '/storage/files/' . $data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/e2e/Services/Storage/StorageConsoleClientTest.php b/tests/e2e/Services/Storage/StorageConsoleClientTest.php index aff055f18d..2d473c5c73 100644 --- a/tests/e2e/Services/Storage/StorageConsoleClientTest.php +++ b/tests/e2e/Services/Storage/StorageConsoleClientTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Storage; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Utopia\Database\Helpers\ID; @@ -21,9 +21,9 @@ class StorageConsoleClientTest extends Scope */ $response = $this->client->call(Client::METHOD_GET, '/storage/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '32h' + 'range' => '32h', ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -33,9 +33,9 @@ class StorageConsoleClientTest extends Scope */ $response = $this->client->call(Client::METHOD_GET, '/storage/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '24h' + 'range' => '24h', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -55,7 +55,7 @@ class StorageConsoleClientTest extends Scope ], $this->getHeaders()), [ 'bucketId' => ID::unique(), 'name' => 'Test Bucket', - 'permission' => 'file' + 'permission' => 'file', ]); $this->assertEquals(201, $bucket['headers']['status-code']); $bucketId = $bucket['body']['$id']; @@ -63,12 +63,11 @@ class StorageConsoleClientTest extends Scope /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_GET, '/storage/' . $bucketId . '/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/storage/'.$bucketId.'/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '32h' + 'range' => '32h', ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -77,9 +76,9 @@ class StorageConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/storage/randomBucketId/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '24h' + 'range' => '24h', ]); $this->assertEquals($response['headers']['status-code'], 404); @@ -87,11 +86,11 @@ class StorageConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/storage/' . $bucketId . '/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/storage/'.$bucketId.'/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'range' => '24h' + 'range' => '24h', ]); $this->assertEquals($response['headers']['status-code'], 200); diff --git a/tests/e2e/Services/Storage/StorageCustomClientTest.php b/tests/e2e/Services/Storage/StorageCustomClientTest.php index 12fc006968..f9ca64644a 100644 --- a/tests/e2e/Services/Storage/StorageCustomClientTest.php +++ b/tests/e2e/Services/Storage/StorageCustomClientTest.php @@ -4,10 +4,9 @@ namespace Tests\E2E\Services\Storage; use CURLFile; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -46,13 +45,13 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -63,14 +62,14 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -83,14 +82,14 @@ class StorageCustomClientTest extends Scope $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -101,14 +100,14 @@ class StorageCustomClientTest extends Scope $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -120,35 +119,34 @@ class StorageCustomClientTest extends Scope public function testBucketAnyPermissions(): void { - /** * Test for SUCCESS */ $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'bucketId' => ID::unique(), - 'name' => 'Test Bucket', - 'permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], + 'bucketId' => ID::unique(), + 'name' => 'Test Bucket', + 'permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], ]); $bucketId = $bucket['body']['$id']; $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ - 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -159,46 +157,46 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'name' => 'permissions.png', + 'name' => 'permissions.png', ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(204, $file['headers']['status-code']); @@ -229,12 +227,12 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -245,35 +243,35 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -285,24 +283,24 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -311,7 +309,7 @@ class StorageCustomClientTest extends Scope $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -321,7 +319,7 @@ class StorageCustomClientTest extends Scope /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -354,12 +352,12 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -370,35 +368,35 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -410,22 +408,22 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(401, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); - $this->client->call(CLient::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $this->client->call(CLient::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -436,50 +434,50 @@ class StorageCustomClientTest extends Scope $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals($file['headers']['status-code'], 401); - $email = ID::unique() . '@localhost.test'; + $email = ID::unique().'@localhost.test'; $password = 'password'; $user2 = $this->createUser('user2', $email, $password); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ], [ 'permissions' => [], ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); @@ -487,12 +485,11 @@ class StorageCustomClientTest extends Scope /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $this->assertEquals(204, $file['headers']['status-code']); $this->assertEmpty($file['body']); } @@ -501,8 +498,8 @@ class StorageCustomClientTest extends Scope { $team1 = $this->createTeam(ID::unique(), 'Team 1'); $team2 = $this->createTeam(ID::unique(), 'Team 1'); - $user1 = $this->createUser(ID::unique(), ID::unique() . '@localhost.test', 'password'); - $user2 = $this->createUser(ID::unique(), ID::unique() . '@localhost.test', 'password'); + $user1 = $this->createUser(ID::unique(), ID::unique().'@localhost.test', 'password'); + $user2 = $this->createUser(ID::unique(), ID::unique().'@localhost.test', 'password'); $this->addToTeam($user1['$id'], $team1['$id']); $this->addToTeam($user2['$id'], $team2['$id']); @@ -531,13 +528,13 @@ class StorageCustomClientTest extends Scope $this->assertNotEmpty($bucketId); // Team 1 create success - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -549,73 +546,73 @@ class StorageCustomClientTest extends Scope $this->assertEquals(47218, $file['body']['sizeOriginal']); // Team 1 read success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 read success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 preview success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 preview success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 download success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 download success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 view success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 view success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); @@ -625,22 +622,22 @@ class StorageCustomClientTest extends Scope */ // Team 2 create failure - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); // Team 2 update failure - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ], [ 'permissions' => [], ]); @@ -648,10 +645,10 @@ class StorageCustomClientTest extends Scope $this->assertEquals($file['headers']['status-code'], 401); // Team 2 delete failure - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); @@ -660,10 +657,10 @@ class StorageCustomClientTest extends Scope * Test for SUCCESS */ // Team 1 delete success - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(204, $file['headers']['status-code']); @@ -683,20 +680,20 @@ class StorageCustomClientTest extends Scope 'bucketId' => ID::unique(), 'name' => 'Test Bucket', 'permissions' => [], - 'fileSecurity' => true + 'fileSecurity' => true, ]); $bucketId = $bucket['body']['$id']; $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::read(Role::any()), ], @@ -710,28 +707,28 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file1['body']['mimeType']); $this->assertEquals(47218, $file1['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -741,17 +738,17 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals(401, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -772,20 +769,20 @@ class StorageCustomClientTest extends Scope 'bucketId' => ID::unique(), 'name' => 'Test Bucket', 'permissions' => [], - 'fileSecurity' => true + 'fileSecurity' => true, ]); $bucketId = $bucket['body']['$id']; $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::read(Role::users()), ], @@ -799,28 +796,28 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file1['body']['mimeType']); $this->assertEquals(47218, $file1['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -830,17 +827,17 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals(401, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -861,20 +858,20 @@ class StorageCustomClientTest extends Scope 'bucketId' => ID::unique(), 'name' => 'Test Bucket', 'permissions' => [], - 'fileSecurity' => true + 'fileSecurity' => true, ]); $bucketId = $bucket['body']['$id']; $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), ], @@ -888,28 +885,28 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file1['body']['mimeType']); $this->assertEquals(47218, $file1['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -919,58 +916,58 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals(401, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(401, $file['headers']['status-code']); - $user2 = $this->createUser(ID::unique(), uniqid() . '@localhost.test', 'password'); + $user2 = $this->createUser(ID::unique(), uniqid().'@localhost.test', 'password'); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 404); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ], [ 'permissions' => [], ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); @@ -980,8 +977,8 @@ class StorageCustomClientTest extends Scope { $team1 = $this->createTeam(ID::unique(), 'Team 1'); $team2 = $this->createTeam(ID::unique(), 'Team 1'); - $user1 = $this->createUser(ID::unique(), ID::unique() . '@localhost.test', 'password'); - $user2 = $this->createUser(ID::unique(), ID::unique() . '@localhost.test', 'password'); + $user1 = $this->createUser(ID::unique(), ID::unique().'@localhost.test', 'password'); + $user2 = $this->createUser(ID::unique(), ID::unique().'@localhost.test', 'password'); $this->addToTeam($user1['$id'], $team1['$id']); $this->addToTeam($user2['$id'], $team2['$id']); @@ -1004,13 +1001,13 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::read(Role::team(ID::custom($team1['$id']))), Permission::read(Role::team(ID::custom($team2['$id']))), @@ -1028,73 +1025,73 @@ class StorageCustomClientTest extends Scope $this->assertEquals(47218, $file['body']['sizeOriginal']); // Team 1 read success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 read success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 preview success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 preview success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 download success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 download success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 view success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 view success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); @@ -1104,32 +1101,32 @@ class StorageCustomClientTest extends Scope */ // Team 1 create failure - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); // Team 2 create failure - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); // Team 2 update failure - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ], [ 'permissions' => [], ]); @@ -1137,10 +1134,10 @@ class StorageCustomClientTest extends Scope $this->assertEquals($file['headers']['status-code'], 401); // Team 2 delete failure - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); @@ -1149,10 +1146,10 @@ class StorageCustomClientTest extends Scope * Test for SUCCESS */ // Team 1 delete success - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], ]); $this->assertEquals(204, $file['headers']['status-code']); @@ -1187,15 +1184,15 @@ class StorageCustomClientTest extends Scope $this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $bucket['body']['$permissions']); // File aliases write to update, delete - $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::write(Role::user($this->getUser()['$id'])), - ] + ], ]); $this->assertNotContains(Permission::create(Role::user($this->getUser()['$id'])), $file1['body']['$permissions']); @@ -1207,15 +1204,15 @@ class StorageCustomClientTest extends Scope */ // File does not allow create permission - $file2 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + $file2 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::create(Role::user($this->getUser()['$id'])), - ] + ], ]); $this->assertEquals(400, $file2['headers']['status-code']); @@ -1244,12 +1241,12 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucket['body']['$id']); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket['body']['$id'] . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucket['body']['$id'].'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 201); @@ -1273,12 +1270,12 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'folderId' => ID::custom('xyz'), 'permissions' => [ Permission::read(Role::user(ID::custom('notme'))), @@ -1289,33 +1286,33 @@ class StorageCustomClientTest extends Scope $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'folderId' => ID::custom('xyz'), 'permissions' => [ Permission::update(Role::user(ID::custom('notme'))), Permission::delete(Role::user(ID::custom('notme'))), - ] + ], ]); $this->assertEquals(401, $file['headers']['status-code']); $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'folderId' => ID::custom('xyz'), 'permissions' => [ Permission::read(Role::user(ID::custom('notme'))), @@ -1328,7 +1325,7 @@ class StorageCustomClientTest extends Scope $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); } /** @@ -1339,7 +1336,7 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1352,25 +1349,25 @@ class StorageCustomClientTest extends Scope $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'permissions' => [ Permission::update(Role::user(ID::custom('notme'))), Permission::delete(Role::user(ID::custom('notme'))), - ] + ], ]); $this->assertEquals(401, $file['headers']['status-code']); $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1385,6 +1382,6 @@ class StorageCustomClientTest extends Scope $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); } } diff --git a/tests/e2e/Services/Storage/StorageCustomServerTest.php b/tests/e2e/Services/Storage/StorageCustomServerTest.php index 38fb0e0b9d..2da95f7983 100644 --- a/tests/e2e/Services/Storage/StorageCustomServerTest.php +++ b/tests/e2e/Services/Storage/StorageCustomServerTest.php @@ -83,8 +83,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets', array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -98,7 +98,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'limit(1)' ], + 'queries' => ['limit(1)'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -108,7 +108,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'offset(1)' ], + 'queries' => ['offset(1)'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -118,7 +118,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("$id", "bucket1")' ], + 'queries' => ['equal("$id", "bucket1")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -128,7 +128,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("fileSecurity", true)' ], + 'queries' => ['equal("fileSecurity", true)'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -138,7 +138,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'cursorAfter("' . $response['body']['buckets'][0]['$id'] . '")' ], + 'queries' => ['cursorAfter("'.$response['body']['buckets'][0]['$id'].'")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -147,6 +147,7 @@ class StorageCustomServerTest extends Scope $this->assertCount(1, $response['body']['buckets']); $this->assertEquals('bucket1', $response['body']['buckets'][0]['$id']); + return $data; } @@ -161,11 +162,11 @@ class StorageCustomServerTest extends Scope */ $response = $this->client->call( Client::METHOD_GET, - '/storage/buckets/' . $id, + '/storage/buckets/'.$id, array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -178,14 +179,13 @@ class StorageCustomServerTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call( Client::METHOD_GET, '/storage/buckets/empty', array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -197,8 +197,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets/id-is-really-long-id-is-really-long-id-is-really-long-id-is-really-long', array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -217,7 +217,7 @@ class StorageCustomServerTest extends Scope /** * Test for SUCCESS */ - $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $id, array_merge([ + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -239,7 +239,7 @@ class StorageCustomServerTest extends Scope /** * Test for FAILURE */ - $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $id, array_merge([ + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -262,11 +262,11 @@ class StorageCustomServerTest extends Scope */ $response = $this->client->call( Client::METHOD_DELETE, - '/storage/buckets/' . $id, + '/storage/buckets/'.$id, array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -276,11 +276,11 @@ class StorageCustomServerTest extends Scope $response = $this->client->call( Client::METHOD_GET, - '/storage/buckets/' . $id, + '/storage/buckets/'.$id, array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) diff --git a/tests/e2e/Services/Storage/StoragePermissionsScope.php b/tests/e2e/Services/Storage/StoragePermissionsScope.php index 09b35fad36..e6502cc183 100644 --- a/tests/e2e/Services/Storage/StoragePermissionsScope.php +++ b/tests/e2e/Services/Storage/StoragePermissionsScope.php @@ -7,6 +7,7 @@ use Tests\E2E\Client; trait StoragePermissionsScope { public array $users = []; + public array $teams = []; public function createUser(string $id, string $email, string $password = 'test123!'): array @@ -18,7 +19,7 @@ trait StoragePermissionsScope ], [ 'userId' => $id, 'email' => $email, - 'password' => $password + 'password' => $password, ]); $this->assertEquals(201, $user['headers']['status-code']); @@ -32,8 +33,7 @@ trait StoragePermissionsScope 'password' => $password, ]); - $session = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; - + $session = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $user = [ '$id' => $user['body']['$id'], @@ -54,7 +54,7 @@ trait StoragePermissionsScope { $team = $this->client->call(Client::METHOD_POST, '/teams', $this->getServerHeader(), [ 'teamId' => $id, - 'name' => $name + 'name' => $name, ]); $this->teams[$id] = $team['body']; @@ -63,16 +63,16 @@ trait StoragePermissionsScope public function addToTeam(string $user, string $team, array $roles = []): array { - $membership = $this->client->call(Client::METHOD_POST, '/teams/' . $team . '/memberships', $this->getServerHeader(), [ + $membership = $this->client->call(Client::METHOD_POST, '/teams/'.$team.'/memberships', $this->getServerHeader(), [ 'teamId' => $team, 'email' => $this->getCreatedUser($user)['email'], 'roles' => $roles, - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); return [ 'user' => $membership['body']['userId'], - 'membership' => $membership['body']['$id'] + 'membership' => $membership['body']['$id'], ]; } @@ -81,7 +81,7 @@ trait StoragePermissionsScope return [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]; } } diff --git a/tests/e2e/Services/Teams/TeamsBase.php b/tests/e2e/Services/Teams/TeamsBase.php index 83b9042f13..7b960b3aa5 100644 --- a/tests/e2e/Services/Teams/TeamsBase.php +++ b/tests/e2e/Services/Teams/TeamsBase.php @@ -3,7 +3,6 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Client; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -42,7 +41,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => $teamId, - 'name' => 'Manchester United' + 'name' => 'Manchester United', ]); $this->assertEquals(201, $response2['headers']['status-code']); @@ -59,7 +58,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Newcastle' + 'name' => 'Newcastle', ]); $this->assertEquals(201, $response3['headers']['status-code']); @@ -85,7 +84,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => $teamId, - 'name' => 'John' + 'name' => 'John', ]); $this->assertEquals(409, $response['headers']['status-code']); @@ -104,7 +103,7 @@ trait TeamsBase /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -147,7 +146,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'limit(2)' ], + 'queries' => ['limit(2)'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -157,7 +156,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'offset(1)' ], + 'queries' => ['offset(1)'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -167,7 +166,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'greaterThanEqual("total", 0)' ], + 'queries' => ['greaterThanEqual("total", 0)'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -177,7 +176,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("name", ["Arsenal", "Newcastle"])' ], + 'queries' => ['equal("name", ["Arsenal", "Newcastle"])'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -226,7 +225,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'limit(2)' ], + 'queries' => ['limit(2)'], ]); $this->assertEquals(200, $teams['headers']['status-code']); @@ -238,7 +237,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'limit(1)', 'cursorAfter("' . $teams['body']['teams'][0]['$id'] . '")' ], + 'queries' => ['limit(1)', 'cursorAfter("'.$teams['body']['teams'][0]['$id'].'")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -251,7 +250,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'limit(1)', 'cursorBefore("' . $teams['body']['teams'][1]['$id'] . '")' ], + 'queries' => ['limit(1)', 'cursorBefore("'.$teams['body']['teams'][1]['$id'].'")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -267,7 +266,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'cursorAfter("unknown")' ], + 'queries' => ['cursorAfter("unknown")'], ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -285,7 +284,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Demo' + 'name' => 'Demo', ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -295,12 +294,12 @@ trait TeamsBase $this->assertIsInt($response['body']['total']); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['$createdAt'])); - $response = $this->client->call(Client::METHOD_PUT, '/teams/' . $response['body']['$id'], array_merge([ + $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()), [ 'teamId' => ID::unique(), - 'name' => 'Demo New' + 'name' => 'Demo New', ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -314,7 +313,7 @@ trait TeamsBase /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PUT, '/teams/' . $response['body']['$id'], array_merge([ + $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()), [ @@ -335,7 +334,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Demo' + 'name' => 'Demo', ]); $teamUid = $response['body']['$id']; @@ -349,7 +348,7 @@ trait TeamsBase $dateValidator = new DatetimeValidator(); $this->assertEquals(true, $dateValidator->isValid($response['body']['$createdAt'])); - $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -360,7 +359,7 @@ trait TeamsBase /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -380,7 +379,7 @@ trait TeamsBase /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $id . '/prefs', array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$id.'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -394,7 +393,7 @@ trait TeamsBase $this->assertEquals($team['body']['funcKey1'], 'funcValue1'); $this->assertEquals($team['body']['funcKey2'], 'funcValue2'); - $team = $this->client->call(Client::METHOD_GET, '/teams/' . $id . '/prefs', array_merge([ + $team = $this->client->call(Client::METHOD_GET, '/teams/'.$id.'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -405,7 +404,7 @@ trait TeamsBase 'funcKey2' => 'funcValue2', ]); - $team = $this->client->call(Client::METHOD_GET, '/teams/' . $id, array_merge([ + $team = $this->client->call(Client::METHOD_GET, '/teams/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -419,7 +418,7 @@ trait TeamsBase /** * Test for FAILURE */ - $user = $this->client->call(Client::METHOD_PUT, '/teams/' . $id . '/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PUT, '/teams/'.$id.'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 7b6b439558..4a3a2859dd 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -3,7 +3,6 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Client; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -20,7 +19,7 @@ trait TeamsBaseClient /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -36,51 +35,51 @@ trait TeamsBaseClient $membershipId = $response['body']['memberships'][0]['$id']; - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'limit(1)' ] + 'queries' => ['limit(1)'], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'offset(1)' ] + 'queries' => ['offset(1)'], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(0, $response['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("confirm", true)' ] + 'queries' => ['equal("confirm", true)'], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("confirm", false)' ] + 'queries' => ['equal("confirm", false)'], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(0, $response['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => $this->getUser()['$id'] + 'search' => $this->getUser()['$id'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -92,11 +91,11 @@ trait TeamsBaseClient $this->assertContains('owner', $response['body']['memberships'][0]['roles']); $this->assertContains('player', $response['body']['memberships'][0]['roles']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => $membershipId + 'search' => $membershipId, ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -108,11 +107,11 @@ trait TeamsBaseClient $this->assertContains('owner', $response['body']['memberships'][0]['roles']); $this->assertContains('player', $response['body']['memberships'][0]['roles']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'unknown' + 'search' => 'unknown', ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -138,7 +137,7 @@ trait TeamsBaseClient /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -157,15 +156,14 @@ trait TeamsBaseClient /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid . 'dasdasd', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'dasdasd', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -180,20 +178,20 @@ trait TeamsBaseClient { $teamUid = $data['teamUid'] ?? ''; $teamName = $data['teamName'] ?? ''; - $email = uniqid() . 'friend@localhost.test'; + $email = uniqid().'friend@localhost.test'; $name = 'Friend User'; /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -211,7 +209,7 @@ trait TeamsBaseClient $this->assertEquals($email, $lastEmail['to'][0]['address']); $this->assertEquals($name, $lastEmail['to'][0]['name']); - $this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']); + $this->assertEquals('Invitation to '.$teamName.' Team at '.$this->getProject()['name'], $lastEmail['subject']); $secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); $membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20); @@ -221,7 +219,7 @@ trait TeamsBaseClient * Test with UserId * Create user */ - $secondEmail = uniqid() . 'foe@localhost.test'; + $secondEmail = uniqid().'foe@localhost.test'; $secondName = 'Another Foe'; $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ 'content-type' => 'application/json', @@ -230,7 +228,7 @@ trait TeamsBaseClient 'userId' => 'unique()', 'email' => $secondEmail, 'password' => 'password', - 'name' => $secondName + 'name' => $secondName, ]); $this->assertEquals(201, $response['headers']['status-code']); $userId = $response['body']['$id']; @@ -239,13 +237,13 @@ trait TeamsBaseClient * Test for UserID * Failure */ - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'userId' => 'abcdefdg', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -254,13 +252,13 @@ trait TeamsBaseClient * Test for UserID * SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'userId' => $userId, 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -278,56 +276,55 @@ trait TeamsBaseClient $this->assertEquals($secondEmail, $lastEmail['to'][0]['address']); $this->assertEquals($secondName, $lastEmail['to'][0]['name']); - $this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']); + $this->assertEquals('Invitation to '.$teamName.' Team at '.$this->getProject()['name'], $lastEmail['subject']); /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(409, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => 'dasdkaskdjaskdjasjkd', 'name' => $name, 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, 'roles' => 'bad string', - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, 'roles' => ['admin', 'editor'], - 'url' => 'http://example.com/join-us#title' // bad url + 'url' => 'http://example.com/join-us#title', // bad url ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -339,7 +336,7 @@ trait TeamsBaseClient 'membershipUid' => $membershipUid, 'userUid' => $userUid, 'email' => $email, - 'name' => $name + 'name' => $name, ]; } @@ -348,7 +345,7 @@ trait TeamsBaseClient */ public function testListTeamMemberships($data): void { - $memberships = $this->client->call(Client::METHOD_GET, '/teams/' . $data['teamUid'] . '/memberships', array_merge([ + $memberships = $this->client->call(Client::METHOD_GET, '/teams/'.$data['teamUid'].'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -358,11 +355,11 @@ trait TeamsBaseClient $this->assertNotEmpty($memberships['body']['memberships']); $this->assertCount(3, $memberships['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $data['teamUid'] . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$data['teamUid'].'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'cursorAfter("' . $memberships['body']['memberships'][0]['$id'] . '")' ] + 'queries' => ['cursorAfter("'.$memberships['body']['memberships'][0]['$id'].'")'], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -387,7 +384,7 @@ trait TeamsBaseClient /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -403,19 +400,18 @@ trait TeamsBaseClient $this->assertCount(2, $response['body']['roles']); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['joined'])); $this->assertEquals(true, $response['body']['confirm']); - $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $data['session'] = $session; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals(true, $response['body']['emailVerification']); - /** [START] TESTS TO CHECK PASSWORD UPDATE OF NEW USER CREATED USING TEAM INVITE */ /** * New User tries to update password without old password -> SHOULD PASS @@ -424,9 +420,9 @@ trait TeamsBaseClient 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'password' => 'new-password' + 'password' => 'new-password', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -444,7 +440,7 @@ trait TeamsBaseClient 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'password' => 'new-password', ]); @@ -457,10 +453,10 @@ trait TeamsBaseClient 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'password' => 'newer-password', - 'oldPassword' => 'new-password' + 'oldPassword' => 'new-password', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -476,7 +472,7 @@ trait TeamsBaseClient /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -487,7 +483,7 @@ trait TeamsBaseClient $this->assertEquals(401, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -498,7 +494,7 @@ trait TeamsBaseClient $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -509,7 +505,7 @@ trait TeamsBaseClient $this->assertEquals(401, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -520,7 +516,7 @@ trait TeamsBaseClient $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -531,7 +527,7 @@ trait TeamsBaseClient $this->assertEquals(401, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -558,12 +554,12 @@ trait TeamsBaseClient * Test for SUCCESS */ $roles = ['admin', 'editor', 'uncle']; - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ + $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 + 'roles' => $roles, ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -578,12 +574,12 @@ trait TeamsBaseClient /** * Test for unknown team */ - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . 'abc' . '/memberships/' . $membershipUid, array_merge([ + $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 + 'roles' => $roles, ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -591,27 +587,26 @@ trait TeamsBaseClient /** * Test for unknown membership ID */ - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . 'abc', array_merge([ + $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 + '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, [ + $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, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ], [ - 'roles' => $roles + 'roles' => $roles, ]); $this->assertEquals(401, $response['headers']['status-code']); @@ -620,7 +615,7 @@ trait TeamsBaseClient return $data; } - /** + /** * @depends testUpdateTeamMembershipRoles */ public function testDeleteTeamMembership($data): array @@ -629,7 +624,7 @@ trait TeamsBaseClient $membershipUid = $data['membershipUid'] ?? ''; $session = $data['session'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -646,11 +641,11 @@ trait TeamsBaseClient /** * Test deleting a membership that does not exists */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/dne', [ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/dne', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -658,11 +653,11 @@ trait TeamsBaseClient /** * Test deleting another user's membership */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, [ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]); $this->assertEquals(401, $response['headers']['status-code']); @@ -674,17 +669,17 @@ trait TeamsBaseClient /** * Test for when a user other than the owner tries to delete their membership */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$membershipUid, [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]); $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -695,7 +690,7 @@ trait TeamsBaseClient /** * Test for when the owner tries to delete their membership */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -704,7 +699,7 @@ trait TeamsBaseClient $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Teams/TeamsBaseServer.php b/tests/e2e/Services/Teams/TeamsBaseServer.php index 7bb6241c4a..642078d72b 100644 --- a/tests/e2e/Services/Teams/TeamsBaseServer.php +++ b/tests/e2e/Services/Teams/TeamsBaseServer.php @@ -17,7 +17,7 @@ trait TeamsBaseServer /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $id . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$id.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -43,7 +43,7 @@ trait TeamsBaseServer /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -62,15 +62,14 @@ trait TeamsBaseServer /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid . 'dasdasd', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'dasdasd', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -85,19 +84,19 @@ trait TeamsBaseServer { $teamUid = $data['teamUid'] ?? ''; $teamName = $data['teamName'] ?? ''; - $email = uniqid() . 'friend@localhost.test'; + $email = uniqid().'friend@localhost.test'; /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -126,51 +125,50 @@ trait TeamsBaseServer /** * Test for FAILURE */ - - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(409, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => 'dasdkaskdjaskdjasjkd', 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => 'bad string', - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://example.com/join-us#title' // bad url + 'url' => 'http://example.com/join-us#title', // bad url ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -178,7 +176,7 @@ trait TeamsBaseServer return [ 'teamUid' => $teamUid, 'userUid' => $userUid, - 'membershipUid' => $membershipUid + 'membershipUid' => $membershipUid, ]; } @@ -194,12 +192,12 @@ trait TeamsBaseServer * Test for SUCCESS */ $roles = ['admin', 'editor', 'uncle']; - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ + $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 + 'roles' => $roles, ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -211,19 +209,18 @@ trait TeamsBaseServer $this->assertEquals($roles[1], $response['body']['roles'][1]); $this->assertEquals($roles[2], $response['body']['roles'][2]); - /** * Test for FAILURE */ $apiKey = $this->getNewKey(['teams.read']); $roles = ['admin', 'editor', 'uncle']; - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid, [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $apiKey + 'x-appwrite-key' => $apiKey, ], [ - 'roles' => $roles + 'roles' => $roles, ]); $this->assertEquals(401, $response['headers']['status-code']); @@ -240,7 +237,7 @@ trait TeamsBaseServer $userUid = $data['userUid'] ?? ''; /** Get Team Count */ - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -253,7 +250,7 @@ trait TeamsBaseServer $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['$createdAt'])); /** Delete User */ - $user = $this->client->call(Client::METHOD_DELETE, '/users/' . $userUid, array_merge([ + $user = $this->client->call(Client::METHOD_DELETE, '/users/'.$userUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -264,12 +261,11 @@ trait TeamsBaseServer sleep(5); /** Get Team Count */ - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); $this->assertEquals('Arsenal', $response['body']['name']); diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index e86c18a8e2..7c5a667bbc 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; @@ -22,10 +22,10 @@ class TeamsConsoleClientTest extends Scope */ $response = $this->client->call(Client::METHOD_POST, '/teams', \array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => 'console' + 'x-appwrite-project' => 'console', ], $this->getHeaders()), [ 'name' => 'Latest version Team', - 'teamId' => ID::unique() + 'teamId' => ID::unique(), ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -37,9 +37,9 @@ class TeamsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/teams', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', - 'x-appwrite-response-format' => '0.11.0' + 'x-appwrite-response-format' => '0.11.0', ], $this->getHeaders()), [ - 'name' => 'Latest version Team' + 'name' => 'Latest version Team', // Notice "teamId' is not defined ]); @@ -49,14 +49,14 @@ class TeamsConsoleClientTest extends Scope /** * Cleanup, so I don't invalidate some listTeams requests by mistake */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $team1Id, \array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$team1Id, \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $team2Id, \array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$team2Id, \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', ], $this->getHeaders())); @@ -71,18 +71,18 @@ class TeamsConsoleClientTest extends Scope { $teamUid = $data['teamUid'] ?? ''; $teamName = $data['teamName'] ?? ''; - $email = uniqid() . 'friend@localhost.test'; + $email = uniqid().'friend@localhost.test'; $name = 'Friend User'; $password = 'password'; // 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, + 'x-appwrite-project' => 'console', ], [ + 'userId' => 'unique()', + 'email' => $email, + 'password' => $password, + 'name' => $name, ], false); $this->assertEquals(201, $user['headers']['status-code']); @@ -90,14 +90,14 @@ class TeamsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -108,7 +108,7 @@ class TeamsConsoleClientTest extends Scope ], $this->getHeaders())); $this->assertEquals(401, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -117,7 +117,7 @@ class TeamsConsoleClientTest extends Scope $ownerMembershipUid = $response['body']['memberships'][1]['$id']; - $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Teams/TeamsCustomClientTest.php b/tests/e2e/Services/Teams/TeamsCustomClientTest.php index 3b46cbcb7f..83a8080d1d 100644 --- a/tests/e2e/Services/Teams/TeamsCustomClientTest.php +++ b/tests/e2e/Services/Teams/TeamsCustomClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Teams; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class TeamsCustomClientTest extends Scope diff --git a/tests/e2e/Services/Teams/TeamsCustomServerTest.php b/tests/e2e/Services/Teams/TeamsCustomServerTest.php index ccbb598934..325b5892fc 100644 --- a/tests/e2e/Services/Teams/TeamsCustomServerTest.php +++ b/tests/e2e/Services/Teams/TeamsCustomServerTest.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Tests\E2E\Client; class TeamsCustomServerTest extends Scope { diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index baf601789a..5842212e07 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -107,7 +107,7 @@ trait UsersBase 'email' => 'sha512@appwrite.io', 'password' => '4243da0a694e8a2f727c8060fe0507c8fa01ca68146c76d2c190805b638c20c6bf6ba04e21f11ae138785d0bff63c416e6f87badbffad37f6dee50094cc38c70', // appwrite (sha512) 'name' => 'SHA512 User', - 'passwordVersion' => 'sha512' + 'passwordVersion' => 'sha512', ]); $this->assertEquals($res['headers']['status-code'], 201); @@ -127,7 +127,7 @@ trait UsersBase 'passwordCpu' => 16384, 'passwordMemory' => 13, 'passwordParallel' => 2, - 'passwordLength' => 64 + 'passwordLength' => 64, ]); $this->assertEquals($res['headers']['status-code'], 201); @@ -191,7 +191,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]), [ - 'email' => $userId . '@appwrite.io', + 'email' => $userId.'@appwrite.io', 'password' => 'appwrite', ]); @@ -201,14 +201,14 @@ trait UsersBase foreach ($userIds as $userId) { // Ensure all passwords were re-hashed - $response = $this->client->call(Client::METHOD_GET, '/users/' . $userId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/'.$userId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($userId, $response['body']['$id']); - $this->assertEquals($userId . '@appwrite.io', $response['body']['email']); + $this->assertEquals($userId.'@appwrite.io', $response['body']['email']); $this->assertEquals('argon2', $response['body']['hash']); $this->assertStringStartsWith('$argon2', $response['body']['password']); } @@ -220,7 +220,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]), [ - 'email' => $userId . '@appwrite.io', + 'email' => $userId.'@appwrite.io', 'password' => 'appwrite', ]); @@ -349,7 +349,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("name", "' . $user1['name'] . '")'] + 'queries' => ['equal("name", "'.$user1['name'].'")'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -362,7 +362,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("email", "' . $user1['email'] . '")'] + 'queries' => ['equal("email", "'.$user1['email'].'")'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -375,7 +375,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("status", true)'] + 'queries' => ['equal("status", true)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -391,7 +391,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("status", false)'] + 'queries' => ['equal("status", false)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -403,7 +403,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("passwordUpdate", "' . $user1['passwordUpdate'] . '")'] + 'queries' => ['equal("passwordUpdate", "'.$user1['passwordUpdate'].'")'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -416,7 +416,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("registration", "' . $user1['registration'] . '")'] + 'queries' => ['equal("registration", "'.$user1['registration'].'")'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -429,7 +429,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("emailVerification", false)'] + 'queries' => ['equal("emailVerification", false)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -445,7 +445,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("emailVerification", true)'] + 'queries' => ['equal("emailVerification", true)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -457,7 +457,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("phoneVerification", false)'] + 'queries' => ['equal("phoneVerification", false)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -469,7 +469,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("phoneVerification", true)'] + 'queries' => ['equal("phoneVerification", true)'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -481,7 +481,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("' . $data['userId'] . '")'] + 'queries' => ['cursorAfter("'.$data['userId'].'")'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -494,7 +494,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("user1")'] + 'queries' => ['cursorBefore("user1")'], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -510,7 +510,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => "Ronaldo", + 'search' => 'Ronaldo', ]); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']); @@ -522,7 +522,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => "cristiano.ronaldo@manchester-united.co.uk", + 'search' => 'cristiano.ronaldo@manchester-united.co.uk', ]); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']); @@ -534,7 +534,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => "cristiano.ronaldo", + 'search' => 'cristiano.ronaldo', ]); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']); @@ -546,7 +546,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => "manchester", + 'search' => 'manchester', ]); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']); @@ -558,7 +558,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => "united.co.uk", + 'search' => 'united.co.uk', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -572,7 +572,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => "man", + 'search' => 'man', ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -602,7 +602,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("unknown")'] + 'queries' => ['cursorAfter("unknown")'], ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -616,7 +616,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -627,7 +627,7 @@ trait UsersBase $this->assertEquals($user['body']['status'], true); $this->assertGreaterThan('2000-01-01 00:00:00', $user['body']['registration']); - $sessions = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/sessions', array_merge([ + $sessions = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/sessions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -670,7 +670,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/name', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/name', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -680,7 +680,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['name'], 'Updated name'); - $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -737,7 +737,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/email', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/email', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -747,7 +747,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['email'], 'users.service@updated.com'); - $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -804,7 +804,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/password', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/password', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -819,7 +819,7 @@ trait UsersBase 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'email' => 'users.service@updated.com', - 'password' => 'password2' + 'password' => 'password2', ]); $this->assertEquals($session['headers']['status-code'], 201); @@ -836,7 +836,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/status', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/status', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -846,7 +846,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['status'], false); - $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -865,7 +865,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/verification', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/verification', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -875,7 +875,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['emailVerification'], true); - $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -895,7 +895,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -909,7 +909,7 @@ trait UsersBase $this->assertEquals($user['body']['funcKey1'], 'funcValue1'); $this->assertEquals($user['body']['funcKey2'], 'funcValue2'); - $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -923,7 +923,7 @@ trait UsersBase /** * Test for FAILURE */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -932,7 +932,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 400); - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -950,8 +950,8 @@ trait UsersBase /** * Test for SUCCESS */ - $updatedNumber = "+910000000000"; //dummy number - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/phone', array_merge([ + $updatedNumber = '+910000000000'; //dummy number + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/phone', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -961,7 +961,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['phone'], $updatedNumber); - $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -972,13 +972,12 @@ trait UsersBase /** * Test for FAILURE */ - - $errorType = "user_phone_already_exists"; - $user1Id = "user1"; + $errorType = 'user_phone_already_exists'; + $user1Id = 'user1'; $statusCodeForUserPhoneAlredyExists = 409; // adding same number ($updatedNumber) to different user i.e user1 - $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $user1Id . '/phone', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/users/'.$user1Id.'/phone', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -997,7 +996,7 @@ trait UsersBase public function testUpdateUserNumberSearch($data): void { $id = $data['userId'] ?? ''; - $newNumber = "+910000000000"; //dummy number + $newNumber = '+910000000000'; //dummy number /** * Test for SUCCESS @@ -1067,7 +1066,7 @@ trait UsersBase */ public function testUpdateUserLabels(array $labels, int $expectedStatus, array $expectedLabels, array $data): array { - $user = $this->client->call(Client::METHOD_PUT, '/users/' . $data['userId'] . '/labels', array_merge([ + $user = $this->client->call(Client::METHOD_PUT, '/users/'.$data['userId'].'/labels', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1087,7 +1086,7 @@ trait UsersBase */ public function testUpdateUserLabelsWithoutLabels(array $data): array { - $user = $this->client->call(Client::METHOD_PUT, '/users/' . $data['userId'] . '/labels', array_merge([ + $user = $this->client->call(Client::METHOD_PUT, '/users/'.$data['userId'].'/labels', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -1109,7 +1108,6 @@ trait UsersBase $this->assertEquals(Response::STATUS_CODE_NOT_FOUND, $user['headers']['status-code']); } - /** * @depends testGetUser */ @@ -1118,7 +1116,7 @@ trait UsersBase /** * Test for SUCCESS */ - $logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1127,7 +1125,7 @@ trait UsersBase $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1139,7 +1137,7 @@ trait UsersBase $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1150,7 +1148,7 @@ trait UsersBase $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1165,47 +1163,47 @@ trait UsersBase /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(-1)'] + 'queries' => ['limit(-1)'], ]); $this->assertEquals($response['headers']['status-code'], 400); - $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(-1)'] + 'queries' => ['offset(-1)'], ]); $this->assertEquals($response['headers']['status-code'], 400); - $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("$id", "asdf")'] + 'queries' => ['equal("$id", "asdf")'], ]); $this->assertEquals($response['headers']['status-code'], 400); - $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['orderAsc("$id")'] + 'queries' => ['orderAsc("$id")'], ]); $this->assertEquals($response['headers']['status-code'], 400); - $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAsc("$id")'] + 'queries' => ['cursorAsc("$id")'], ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -1219,7 +1217,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_DELETE, '/users/'.$data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1229,7 +1227,7 @@ trait UsersBase /** * Test for FAILURE */ - $user = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_DELETE, '/users/'.$data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/e2e/Services/Users/UsersConsoleClientTest.php b/tests/e2e/Services/Users/UsersConsoleClientTest.php index 8943bfab63..cc44520387 100644 --- a/tests/e2e/Services/Users/UsersConsoleClientTest.php +++ b/tests/e2e/Services/Users/UsersConsoleClientTest.php @@ -2,9 +2,9 @@ namespace Tests\E2E\Services\Users; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; class UsersConsoleClientTest extends Scope @@ -17,10 +17,9 @@ class UsersConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/users/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'range' => '32h', ]); @@ -32,7 +31,7 @@ class UsersConsoleClientTest extends Scope */ $response = $this->client->call(Client::METHOD_GET, '/users/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'range' => '24h', ]); diff --git a/tests/e2e/Services/Users/UsersCustomServerTest.php b/tests/e2e/Services/Users/UsersCustomServerTest.php index 6b9a990d4c..2442f1bf7d 100644 --- a/tests/e2e/Services/Users/UsersCustomServerTest.php +++ b/tests/e2e/Services/Users/UsersCustomServerTest.php @@ -2,7 +2,6 @@ namespace Tests\E2E\Services\Users; -use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; diff --git a/tests/e2e/Services/Webhooks/WebhooksBase.php b/tests/e2e/Services/Webhooks/WebhooksBase.php index 6e30e7abc1..663167e38b 100644 --- a/tests/e2e/Services/Webhooks/WebhooksBase.php +++ b/tests/e2e/Services/Webhooks/WebhooksBase.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\Webhooks; use Appwrite\Tests\Retry; use CURLFile; use Tests\E2E\Client; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -16,10 +15,10 @@ trait WebhooksBase public static function getWebhookSignature(array $webhook, string $signatureKey): string { $payload = json_encode($webhook['data']); - $url = $webhook['url']; - return base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); - } + $url = $webhook['url']; + return base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + } public function testCreateCollection(): array { @@ -27,23 +26,23 @@ trait WebhooksBase * Create database */ $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'databaseId' => ID::unique(), - 'name' => 'Actors DB', + 'databaseId' => ID::unique(), + 'name' => 'Actors DB', ]); $databaseId = $database['body']['$id']; - /** + /** * Test for SUCCESS */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -67,8 +66,8 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); @@ -91,30 +90,30 @@ trait WebhooksBase $actorsId = $data['actorsId']; $databaseId = $data['databaseId']; - $firstName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ + $firstName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'firstName', 'size' => 256, 'required' => true, ]); - $lastName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ + $lastName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'lastName', 'size' => 256, 'required' => true, ]); - $extra = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ + $extra = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'extra', 'size' => 64, @@ -139,9 +138,9 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.attributes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -151,10 +150,10 @@ trait WebhooksBase $this->assertNotEmpty($webhook['data']['key']); $this->assertEquals($webhook['data']['key'], 'extra'); - $removed = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/attributes/' . $extra['body']['key'], array_merge([ + $removed = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['actorsId'].'/attributes/'.$extra['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals(204, $removed['headers']['status-code']); @@ -165,9 +164,9 @@ trait WebhooksBase // $this->assertEquals($webhook['method'], 'DELETE'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.attributes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -191,7 +190,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -218,9 +217,9 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -254,7 +253,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $data['documentId'], array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$data['documentId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -280,9 +279,9 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -315,7 +314,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -337,7 +336,7 @@ trait WebhooksBase $this->assertEquals($document['headers']['status-code'], 201); $this->assertNotEmpty($document['body']['$id']); - $document = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $document['body']['$id'], array_merge([ + $document = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$document['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -350,9 +349,9 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -373,7 +372,6 @@ trait WebhooksBase return $data; } - public function testCreateStorageBucket(): array { /** @@ -382,7 +380,7 @@ trait WebhooksBase $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'bucketId' => ID::unique(), 'name' => 'Test Bucket', @@ -431,10 +429,10 @@ trait WebhooksBase /** * Test for SUCCESS */ - $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'], array_merge([ + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Test Bucket Updated', 'fileSecurity' => true, @@ -474,10 +472,10 @@ trait WebhooksBase $bucketId = $data['bucketId']; //enable bucket - $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'], array_merge([ + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Test Bucket Updated', 'fileSecurity' => true, @@ -488,12 +486,12 @@ trait WebhooksBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -551,7 +549,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -607,7 +605,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -655,10 +653,10 @@ trait WebhooksBase /** * Test for SUCCESS */ - $bucket = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId, array_merge([ + $bucket = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals($bucket['headers']['status-code'], 204); @@ -694,7 +692,7 @@ trait WebhooksBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal' + 'name' => 'Arsenal', ]); $teamId = $team['body']['$id']; @@ -737,11 +735,11 @@ trait WebhooksBase /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamId, array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$teamId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'name' => 'Demo New' + 'name' => 'Demo New', ]); $this->assertEquals(200, $team['headers']['status-code']); @@ -780,14 +778,14 @@ trait WebhooksBase { $id = $data['teamId'] ?? ''; - $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $id . '/prefs', array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$id.'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'prefs' => [ 'prefKey1' => 'prefValue1', 'prefKey2' => 'prefValue2', - ] + ], ]); $this->assertEquals($team['headers']['status-code'], 200); @@ -796,8 +794,8 @@ trait WebhooksBase $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -830,7 +828,7 @@ trait WebhooksBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Chelsea' + 'name' => 'Chelsea', ]); $teamId = $team['body']['$id']; @@ -838,7 +836,7 @@ trait WebhooksBase $this->assertEquals(201, $team['headers']['status-code']); $this->assertNotEmpty($team['body']['$id']); - $team = $this->client->call(Client::METHOD_DELETE, '/teams/' . $team['body']['$id'], array_merge([ + $team = $this->client->call(Client::METHOD_DELETE, '/teams/'.$team['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -875,19 +873,19 @@ trait WebhooksBase public function testCreateTeamMembership($data): array { $teamId = $data['teamId'] ?? ''; - $email = uniqid() . 'friend@localhost.test'; + $email = uniqid().'friend@localhost.test'; /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_POST, '/teams/' . $teamId . '/memberships', array_merge([ + $team = $this->client->call(Client::METHOD_POST, '/teams/'.$teamId.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $this->assertEquals(201, $team['headers']['status-code']); @@ -942,19 +940,19 @@ trait WebhooksBase public function testDeleteTeamMembership($data): void { $teamId = $data['teamId'] ?? ''; - $email = uniqid() . 'friend@localhost.test'; + $email = uniqid().'friend@localhost.test'; /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_POST, '/teams/' . $teamId . '/memberships', array_merge([ + $team = $this->client->call(Client::METHOD_POST, '/teams/'.$teamId.'/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title' + 'url' => 'http://localhost:5000/join-us#title', ]); $membershipId = $team['body']['$id'] ?? ''; @@ -962,7 +960,7 @@ trait WebhooksBase $this->assertEquals(201, $team['headers']['status-code']); $this->assertNotEmpty($team['body']['$id']); - $team = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamId . '/memberships/' . $team['body']['$id'], array_merge([ + $team = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamId.'/memberships/'.$team['body']['$id'], array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php index 67c2dec36b..48f33a24e5 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php @@ -4,10 +4,9 @@ namespace Tests\E2E\Services\Webhooks; use Appwrite\Tests\Retry; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -19,7 +18,7 @@ class WebhooksCustomClientTest extends Scope public function testCreateAccount(): array { - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -45,8 +44,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -77,7 +76,7 @@ class WebhooksCustomClientTest extends Scope public function testDeleteAccount(): array { - $email = uniqid() . 'user1@localhost.test'; + $email = uniqid().'user1@localhost.test'; $password = 'password'; $name = 'User Name 1'; @@ -107,13 +106,13 @@ class WebhooksCustomClientTest extends Scope $this->assertEquals($accountSession['headers']['status-code'], 201); $id = $account['body']['$id']; - $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $account = $this->client->call(Client::METHOD_PATCH, '/account/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($account['headers']['status-code'], 200); @@ -121,8 +120,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -170,13 +169,13 @@ class WebhooksCustomClientTest extends Scope $this->assertEquals($accountSession['headers']['status-code'], 201); $sessionId = $accountSession['body']['$id']; - $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -248,15 +247,15 @@ class WebhooksCustomClientTest extends Scope ]); $sessionId = $accountSession['body']['$id']; - $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $this->assertEquals($accountSession['headers']['status-code'], 201); - $accountSession = $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionId, array_merge([ + $accountSession = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($accountSession['headers']['status-code'], 204); @@ -264,8 +263,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -334,7 +333,7 @@ class WebhooksCustomClientTest extends Scope ]); $sessionId = $accountSession['body']['$id']; - $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; $this->assertEquals($accountSession['headers']['status-code'], 201); @@ -342,7 +341,7 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ])); $this->assertEquals($accountSession['headers']['status-code'], 204); @@ -350,8 +349,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -407,7 +406,7 @@ class WebhooksCustomClientTest extends Scope $this->assertEquals($accountSession['headers']['status-code'], 201); $sessionId = $accountSession['body']['$id']; - $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; return array_merge($data, [ 'sessionId' => $sessionId, @@ -430,9 +429,9 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ - 'name' => $newName + 'name' => $newName, ]); $this->assertEquals($account['headers']['status-code'], 200); @@ -441,9 +440,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); - + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -483,7 +481,7 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'password' => 'new-password', 'oldPassword' => $password, @@ -495,8 +493,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -531,14 +529,14 @@ class WebhooksCustomClientTest extends Scope { $id = $data['id'] ?? ''; $email = $data['email'] ?? ''; - $newEmail = uniqid() . 'new@localhost.test'; + $newEmail = uniqid().'new@localhost.test'; $session = $data['session'] ?? ''; $account = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'email' => $newEmail, 'password' => 'new-password', @@ -550,8 +548,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -592,12 +590,12 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'prefs' => [ 'prefKey1' => 'prefValue1', 'prefKey2' => 'prefValue2', - ] + ], ]); $this->assertEquals($account['headers']['status-code'], 200); @@ -606,8 +604,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -661,8 +659,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -721,8 +719,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -764,7 +762,7 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'url' => 'http://localhost/verification', ]); @@ -777,8 +775,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -821,7 +819,7 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, ]), [ 'userId' => $id, 'secret' => $secret, @@ -835,8 +833,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -878,7 +876,7 @@ class WebhooksCustomClientTest extends Scope /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ + $team = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -893,8 +891,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index 02c3a2dbfd..836c81822b 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -8,7 +8,6 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; use Utopia\CLI\Console; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -31,10 +30,10 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $actors = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $id, array_merge([ + $actors = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'name' => 'Actors1', 'documentSecurity' => true, @@ -49,8 +48,8 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); @@ -73,10 +72,10 @@ class WebhooksCustomServerTest extends Scope $actorsId = $data['actorsId']; $databaseId = $data['databaseId']; - $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['actorsId'].'/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'key' => 'fullname', 'type' => 'key', @@ -97,9 +96,9 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -109,10 +108,10 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true); // Remove index - $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/indexes/' . $index['body']['key'], array_merge([ + $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['actorsId'].'/indexes/'.$index['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ])); // // wait for database worker to remove index @@ -122,9 +121,9 @@ class WebhooksCustomServerTest extends Scope // $this->assertEquals($webhook['method'], 'DELETE'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.indexes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -144,7 +143,7 @@ class WebhooksCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ], $this->getHeaders()), [ 'databaseId' => ID::unique(), 'name' => 'Actors DB', @@ -155,10 +154,10 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'collectionId' => ID::unique(), 'name' => 'Demo', @@ -176,10 +175,10 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($actors['headers']['status-code'], 201); $this->assertNotEmpty($actors['body']['$id']); - $actors = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([ + $actors = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'x-appwrite-key' => $this->getProject()['apiKey'], ]), []); $this->assertEquals($actors['headers']['status-code'], 204); @@ -190,8 +189,8 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$id}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); @@ -208,7 +207,7 @@ class WebhooksCustomServerTest extends Scope public function testCreateUser(): array { - $email = uniqid() . 'user@localhost.test'; + $email = uniqid().'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -268,11 +267,11 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $id . '/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$id.'/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'prefs' => ['a' => 'b'] + 'prefs' => ['a' => 'b'], ]); $this->assertEquals($user['headers']['status-code'], 200); @@ -309,7 +308,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/status', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/status', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -356,7 +355,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_DELETE, '/users/'.$data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -442,7 +441,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $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()), [ @@ -451,14 +450,14 @@ class WebhooksCustomServerTest extends Scope 'execute' => [Role::any()->toString()], 'vars' => [ 'key1' => 'value1', - ] + ], ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertEquals($function['body']['$id'], $data['functionId']); // Create variable - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -496,16 +495,16 @@ class WebhooksCustomServerTest extends Scope $stderr = ''; $stdout = ''; $folder = 'timeout'; - $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); + $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/' . $data['functionId'] . '/deployments', array_merge([ + $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()), [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), - 'activate' => true + 'activate' => true, ]); $id = $data['functionId'] ?? ''; @@ -546,7 +545,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $id . '/deployments/' . $deploymentId, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/functions/'.$id.'/deployments/'.$deploymentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -594,11 +593,11 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $id . '/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$id.'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'async' => true + 'async' => true, ]); $executionId = $execution['body']['$id'] ?? ''; @@ -665,7 +664,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $deployment = $this->client->call(Client::METHOD_DELETE, '/functions/' . $id . '/deployments/' . $deploymentId, array_merge([ + $deployment = $this->client->call(Client::METHOD_DELETE, '/functions/'.$id.'/deployments/'.$deploymentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -710,7 +709,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $id, array_merge([ + $function = $this->client->call(Client::METHOD_DELETE, '/functions/'.$id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/extensions/Retryable.php b/tests/extensions/Retryable.php index 61fec0ef12..aa85d22eae 100644 --- a/tests/extensions/Retryable.php +++ b/tests/extensions/Retryable.php @@ -14,6 +14,7 @@ trait Retryable * accounting for any retries configured by the {@see Retry} annotation. * * @return void + * * @throws \ReflectionException * @throws \Throwable */ @@ -21,14 +22,15 @@ trait Retryable { $retries = $this->getNumberOfRetries(); $ex = null; - for ($i = 0; $i <= $retries; ++$i) { + for ($i = 0; $i <= $retries; $i++) { try { parent::runBare(); + return; - } catch (\Throwable | \Exception $ex) { + } catch (\Throwable|\Exception $ex) { // Swallow the exception until we have exhausted our retries. if ($i !== $retries) { - echo 'Flaky test failed, retrying...' . PHP_EOL; + echo 'Flaky test failed, retrying...'.PHP_EOL; } } } @@ -39,6 +41,7 @@ trait Retryable /** * @return int + * * @throws \ReflectionException */ private function getNumberOfRetries(): int @@ -53,11 +56,12 @@ trait Retryable $attribute = $attributes[0] ?? null; $args = $attribute?->getArguments(); $retries = $args['count'] ?? 0; + return \max(0, $retries); } /** - * @param \ReflectionClass $reflection + * @param \ReflectionClass $reflection * @return \ReflectionClass */ private function getTestCaseRoot(\ReflectionClass $reflection): \ReflectionClass @@ -65,6 +69,7 @@ trait Retryable if ($reflection->getName() === TestCase::class) { return $reflection; } + return $this->getTestCaseRoot($reflection->getParentClass()); } } diff --git a/tests/extensions/TestHook.php b/tests/extensions/TestHook.php index 67c1215c4c..f6db16a227 100644 --- a/tests/extensions/TestHook.php +++ b/tests/extensions/TestHook.php @@ -3,11 +3,11 @@ namespace Appwrite\Tests; use PHPUnit\Runner\AfterTestHook; -use Exception; class TestHook implements AfterTestHook { protected const MAX_SECONDS_ALLOWED = 15; + public function executeAfterTest(string $test, float $time): void { printf( diff --git a/tests/resources/functions/php-fn/index.php b/tests/resources/functions/php-fn/index.php index 7947c4a6a6..6da31cd499 100644 --- a/tests/resources/functions/php-fn/index.php +++ b/tests/resources/functions/php-fn/index.php @@ -1,7 +1,7 @@ json([ 'APPWRITE_FUNCTION_ID' => $request['variables']['APPWRITE_FUNCTION_ID'], diff --git a/tests/resources/functions/php-large/index.php b/tests/resources/functions/php-large/index.php index 84b6a991fe..83140c27ff 100644 --- a/tests/resources/functions/php-large/index.php +++ b/tests/resources/functions/php-large/index.php @@ -10,6 +10,6 @@ return function ($request, $response) { 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'], 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'], 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'], - 'UNICODE_TEST' => "êä" + 'UNICODE_TEST' => 'êä', ]); }; diff --git a/tests/resources/functions/php/index.php b/tests/resources/functions/php/index.php index 84b6a991fe..83140c27ff 100644 --- a/tests/resources/functions/php/index.php +++ b/tests/resources/functions/php/index.php @@ -10,6 +10,6 @@ return function ($request, $response) { 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'], 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'], 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'], - 'UNICODE_TEST' => "êä" + 'UNICODE_TEST' => 'êä', ]); }; diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php index 3e6a760b25..a3aa78bc6d 100644 --- a/tests/unit/Auth/AuthTest.php +++ b/tests/unit/Auth/AuthTest.php @@ -3,12 +3,12 @@ namespace Tests\Unit\Auth; use Appwrite\Auth\Auth; +use PHPUnit\Framework\TestCase; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; -use PHPUnit\Framework\TestCase; use Utopia\Database\Validator\Roles; class AuthTest extends TestCase @@ -127,13 +127,13 @@ class AuthTest extends TestCase // Scrypt $plain = 'some-scrypt-password'; $hash = 'b448ad7ba88b653b5b56b8053a06806724932d0751988bc9cd0ef7ff059e8ba8a020e1913b7069a650d3f99a1559aba0221f2c277826919513a054e76e339028'; - $generatedHash = Auth::passwordHash($plain, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2]); + $generatedHash = Auth::passwordHash($plain, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2]); - $this->assertEquals(true, Auth::passwordVerify($plain, $generatedHash, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); - $this->assertEquals(true, Auth::passwordVerify($plain, $hash, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); - $this->assertEquals(false, Auth::passwordVerify($plain, $hash, 'scrypt', [ 'salt' => 'some-wrong-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); - $this->assertEquals(false, Auth::passwordVerify($plain, $hash, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 10, 'costParallel' => 2])); - $this->assertEquals(false, Auth::passwordVerify('wrongPassword', $hash, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); + $this->assertEquals(true, Auth::passwordVerify($plain, $generatedHash, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); + $this->assertEquals(true, Auth::passwordVerify($plain, $hash, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); + $this->assertEquals(false, Auth::passwordVerify($plain, $hash, 'scrypt', ['salt' => 'some-wrong-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); + $this->assertEquals(false, Auth::passwordVerify($plain, $hash, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 10, 'costParallel' => 2])); + $this->assertEquals(false, Auth::passwordVerify('wrongPassword', $hash, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); // ScryptModified tested are in provider-specific tests below @@ -164,7 +164,7 @@ class AuthTest extends TestCase $saltSeparator = 'Bw=='; $signerKey = 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=='; - $options = [ 'salt' => $salt, 'saltSeparator' => $saltSeparator, 'signerKey' => $signerKey ]; + $options = ['salt' => $salt, 'saltSeparator' => $saltSeparator, 'signerKey' => $signerKey]; $generatedHash = Auth::passwordHash($plain, 'scryptMod', $options); $this->assertEquals(true, Auth::passwordVerify($plain, $generatedHash, 'scryptMod', $options)); $this->assertEquals(true, Auth::passwordVerify($plain, $hash, 'scryptMod', $options)); @@ -339,7 +339,7 @@ class AuthTest extends TestCase public function testGuestRoles(): void { $user = new Document([ - '$id' => '' + '$id' => '', ]); $roles = Auth::getRoles($user); @@ -349,11 +349,11 @@ class AuthTest extends TestCase public function testUserRoles(): void { - $user = new Document([ + $user = new Document([ '$id' => ID::custom('123'), 'labels' => [ 'vip', - 'admin' + 'admin', ], 'emailVerification' => true, 'phoneVerification' => true, @@ -364,18 +364,18 @@ class AuthTest extends TestCase 'confirm' => true, 'roles' => [ 'administrator', - 'moderator' - ] + 'moderator', + ], ], [ '$id' => ID::custom('abc'), 'teamId' => ID::custom('def'), 'confirm' => true, 'roles' => [ - 'guest' - ] - ] - ] + 'guest', + ], + ], + ], ]); $roles = Auth::getRoles($user); @@ -414,7 +414,7 @@ class AuthTest extends TestCase public function testPrivilegedUserRoles(): void { Authorization::setRole(Auth::USER_ROLE_OWNER); - $user = new Document([ + $user = new Document([ '$id' => ID::custom('123'), 'emailVerification' => true, 'phoneVerification' => true, @@ -425,18 +425,18 @@ class AuthTest extends TestCase 'confirm' => true, 'roles' => [ 'administrator', - 'moderator' - ] + 'moderator', + ], ], [ '$id' => ID::custom('abc'), 'teamId' => ID::custom('def'), 'confirm' => true, 'roles' => [ - 'guest' - ] - ] - ] + 'guest', + ], + ], + ], ]); $roles = Auth::getRoles($user); @@ -458,7 +458,7 @@ class AuthTest extends TestCase public function testAppUserRoles(): void { Authorization::setRole(Auth::USER_ROLE_APPS); - $user = new Document([ + $user = new Document([ '$id' => ID::custom('123'), 'memberships' => [ [ @@ -467,18 +467,18 @@ class AuthTest extends TestCase 'confirm' => true, 'roles' => [ 'administrator', - 'moderator' - ] + 'moderator', + ], ], [ '$id' => ID::custom('abc'), 'teamId' => ID::custom('def'), 'confirm' => true, 'roles' => [ - 'guest' - ] - ] - ] + 'guest', + ], + ], + ], ]); $roles = Auth::getRoles($user); diff --git a/tests/unit/Auth/Validator/PasswordDictionaryTest.php b/tests/unit/Auth/Validator/PasswordDictionaryTest.php index fd7f51ff16..283d5c79fa 100644 --- a/tests/unit/Auth/Validator/PasswordDictionaryTest.php +++ b/tests/unit/Auth/Validator/PasswordDictionaryTest.php @@ -4,7 +4,6 @@ namespace Tests\Unit\Auth\Validator; use Appwrite\Auth\Validator\PasswordDictionary; use PHPUnit\Framework\TestCase; -use Utopia\Database\Document; class PasswordDictionaryTest extends TestCase { diff --git a/tests/unit/Docker/ComposeTest.php b/tests/unit/Docker/ComposeTest.php index 56448ffd01..350b41a820 100644 --- a/tests/unit/Docker/ComposeTest.php +++ b/tests/unit/Docker/ComposeTest.php @@ -12,7 +12,7 @@ class ComposeTest extends TestCase public function setUp(): void { - $data = @file_get_contents(__DIR__ . '/../../resources/docker/docker-compose.yml'); + $data = @file_get_contents(__DIR__.'/../../resources/docker/docker-compose.yml'); if ($data === false) { throw new Exception('Failed to read compose file'); diff --git a/tests/unit/Docker/EnvTest.php b/tests/unit/Docker/EnvTest.php index e6c9b8cadf..b271bde504 100644 --- a/tests/unit/Docker/EnvTest.php +++ b/tests/unit/Docker/EnvTest.php @@ -12,7 +12,7 @@ class EnvTest extends TestCase public function setUp(): void { - $data = @file_get_contents(__DIR__ . '/../../resources/docker/.env'); + $data = @file_get_contents(__DIR__.'/../../resources/docker/.env'); if ($data === false) { throw new Exception('Failed to read compose file'); @@ -34,10 +34,10 @@ class EnvTest extends TestCase public function testExport(): void { - $this->assertEquals("_APP_X=value1 + $this->assertEquals('_APP_X=value1 _APP_Y=value2 _APP_Z=value3 _APP_W=value5= -", $this->object->export()); +', $this->object->export()); } } diff --git a/tests/unit/Event/EventTest.php b/tests/unit/Event/EventTest.php index a328c8d599..13f2bb4fd2 100644 --- a/tests/unit/Event/EventTest.php +++ b/tests/unit/Event/EventTest.php @@ -10,15 +10,16 @@ use Utopia\App; class EventTest extends TestCase { protected ?Event $object = null; + protected string $queue = ''; public function setUp(): void { $redisHost = App::getEnv('_APP_REDIS_HOST', ''); $redisPort = App::getEnv('_APP_REDIS_PORT', ''); - \Resque::setBackend($redisHost . ':' . $redisPort); + \Resque::setBackend($redisHost.':'.$redisPort); - $this->queue = 'v1-tests' . uniqid(); + $this->queue = 'v1-tests'.uniqid(); $this->object = new Event($this->queue, 'TestsV1'); } @@ -85,7 +86,7 @@ class EventTest extends TestCase public function testGenerateEvents(): void { $event = Event::generateEvents('users.[userId].create', [ - 'userId' => 'torsten' + 'userId' => 'torsten', ]); $this->assertCount(4, $event); $this->assertContains('users.torsten.create', $event); @@ -94,7 +95,7 @@ class EventTest extends TestCase $this->assertContains('users.*', $event); $event = Event::generateEvents('users.[userId].update.email', [ - 'userId' => 'torsten' + 'userId' => 'torsten', ]); $this->assertCount(6, $event); $this->assertContains('users.torsten.update.email', $event); @@ -151,10 +152,9 @@ class EventTest extends TestCase $this->assertContains('databases.chaptersDB.collections.*.documents.*', $event); $this->assertContains('databases.chaptersDB.collections.*.documents.*.create', $event); - try { $event = Event::generateEvents('collections.[collectionId].documents.[documentId].create', [ - 'collectionId' => 'chapters' + 'collectionId' => 'chapters', ]); $this->fail(); } catch (\Throwable $th) { diff --git a/tests/unit/General/CollectionsTest.php b/tests/unit/General/CollectionsTest.php index 73a9ccd0c2..8596b857a8 100644 --- a/tests/unit/General/CollectionsTest.php +++ b/tests/unit/General/CollectionsTest.php @@ -10,7 +10,7 @@ class CollectionsTest extends TestCase public function setUp(): void { - $this->collections = require('app/config/collections.php'); + $this->collections = require 'app/config/collections.php'; } public function testDuplicateRules(): void diff --git a/tests/unit/Messaging/MessagingChannelsTest.php b/tests/unit/Messaging/MessagingChannelsTest.php index 6fe7dda71f..14ec84a8e6 100644 --- a/tests/unit/Messaging/MessagingChannelsTest.php +++ b/tests/unit/Messaging/MessagingChannelsTest.php @@ -3,9 +3,9 @@ namespace Tests\Unit\Messaging; use Appwrite\Auth\Auth; -use Utopia\Database\Document; use Appwrite\Messaging\Adapter\Realtime; use PHPUnit\Framework\TestCase; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; @@ -17,10 +17,15 @@ class MessagingChannelsTest extends TestCase public $connectionsPerChannel = 10; public Realtime $realtime; + public $connectionsCount = 0; + public $connectionsAuthenticated = 0; + public $connectionsGuest = 0; + public $connectionsTotal = 0; + public $allChannels = [ 'files', 'files.1', @@ -51,19 +56,19 @@ class MessagingChannelsTest extends TestCase for ($i = 0; $i < $this->connectionsPerChannel; $i++) { foreach ($this->allChannels as $index => $channel) { $user = new Document([ - '$id' => ID::custom('user' . $this->connectionsCount), + '$id' => ID::custom('user'.$this->connectionsCount), 'memberships' => [ [ - '$id' => ID::custom('member' . $i), - 'teamId' => ID::custom('team' . $i), + '$id' => ID::custom('member'.$i), + 'teamId' => ID::custom('team'.$i), 'confirm' => true, 'roles' => [ empty($index % 2) ? Auth::USER_ROLE_ADMIN : 'member', - ] - ] - ] + ], + ], + ], ]); $roles = Auth::getRoles($user); @@ -87,7 +92,7 @@ class MessagingChannelsTest extends TestCase for ($i = 0; $i < $this->connectionsPerChannel; $i++) { foreach ($this->allChannels as $index => $channel) { $user = new Document([ - '$id' => '' + '$id' => '', ]); $roles = Auth::getRoles($user); @@ -170,8 +175,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ] - ] + ], + ], ]; $receivers = $this->realtime->getSubscribers($event); @@ -194,7 +199,7 @@ class MessagingChannelsTest extends TestCase { $roles = [ Role::guests()->toString(), - Role::users()->toString() + Role::users()->toString(), ]; foreach ($this->allChannels as $index => $channel) { foreach ($roles as $role) { @@ -206,8 +211,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ] - ] + ], + ], ]; $receivers = $this->realtime->getSubscribers($event); @@ -232,7 +237,7 @@ class MessagingChannelsTest extends TestCase foreach ($this->allChannels as $index => $channel) { $permissions = []; for ($i = 0; $i < $this->connectionsPerChannel; $i++) { - $permissions[] = Role::user(ID::custom('user' . (!empty($i) ? $i : '') . $index))->toString(); + $permissions[] = Role::user(ID::custom('user'.(! empty($i) ? $i : '').$index))->toString(); } $event = [ 'project' => '1', @@ -240,8 +245,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ] - ] + ], + ], ]; $receivers = $this->realtime->getSubscribers($event); @@ -266,8 +271,8 @@ class MessagingChannelsTest extends TestCase $permissions = []; for ($i = 0; $i < $this->connectionsPerChannel; $i++) { - $permissions[] = Role::team(ID::custom('team' . $i))->toString(); - $permissions[] = Role::member(ID::custom('member' . $i))->toString(); + $permissions[] = Role::team(ID::custom('team'.$i))->toString(); + $permissions[] = Role::member(ID::custom('member'.$i))->toString(); } $event = [ 'project' => '1', @@ -275,8 +280,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ] - ] + ], + ], ]; $receivers = $this->realtime->getSubscribers($event); @@ -298,8 +303,8 @@ class MessagingChannelsTest extends TestCase : 'member'; $permissions = [ - Role::team(ID::custom('team' . $index), $role)->toString(), - Role::member(ID::custom('member' . $index))->toString() + Role::team(ID::custom('team'.$index), $role)->toString(), + Role::member(ID::custom('member'.$index))->toString(), ]; $event = [ @@ -308,8 +313,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ] - ] + ], + ], ]; $receivers = $this->realtime->getSubscribers($event); diff --git a/tests/unit/Messaging/MessagingGuestTest.php b/tests/unit/Messaging/MessagingGuestTest.php index 1aaa1febca..660e9519e3 100644 --- a/tests/unit/Messaging/MessagingGuestTest.php +++ b/tests/unit/Messaging/MessagingGuestTest.php @@ -27,8 +27,8 @@ class MessagingGuestTest extends TestCase 'channels' => [ 0 => 'documents', 1 => 'documents', - ] - ] + ], + ], ]; $receivers = $realtime->getSubscribers($event); diff --git a/tests/unit/Messaging/MessagingTest.php b/tests/unit/Messaging/MessagingTest.php index c2e3971945..d6ae6b095b 100644 --- a/tests/unit/Messaging/MessagingTest.php +++ b/tests/unit/Messaging/MessagingTest.php @@ -2,9 +2,9 @@ namespace Tests\Unit\Messaging; -use Utopia\Database\Document; use Appwrite\Messaging\Adapter\Realtime; use PHPUnit\Framework\TestCase; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -44,8 +44,8 @@ class MessagingTest extends TestCase 'data' => [ 'channels' => [ 0 => 'account.123', - ] - ] + ], + ], ]; $receivers = $realtime->getSubscribers($event); @@ -148,7 +148,7 @@ class MessagingTest extends TestCase public function testConvertChannelsGuest(): void { $user = new Document([ - '$id' => '' + '$id' => '', ]); $channels = [ @@ -156,7 +156,7 @@ class MessagingTest extends TestCase 1 => 'documents', 2 => 'documents.789', 3 => 'account', - 4 => 'account.456' + 4 => 'account.456', ]; $channels = Realtime::convertChannels($channels, $user->getId()); @@ -170,30 +170,30 @@ class MessagingTest extends TestCase public function testConvertChannelsUser(): void { - $user = new Document([ + $user = new Document([ '$id' => ID::custom('123'), 'memberships' => [ [ 'teamId' => ID::custom('abc'), 'roles' => [ 'administrator', - 'moderator' - ] + 'moderator', + ], ], [ 'teamId' => ID::custom('def'), 'roles' => [ - 'guest' - ] - ] - ] + 'guest', + ], + ], + ], ]); $channels = [ 0 => 'files', 1 => 'documents', 2 => 'documents.789', 3 => 'account', - 4 => 'account.456' + 4 => 'account.456', ]; $channels = Realtime::convertChannels($channels, $user->getId()); @@ -321,7 +321,7 @@ class MessagingTest extends TestCase Permission::update(Role::team('123abc')), Permission::delete(Role::team('123abc')), ], - 'fileSecurity' => true + 'fileSecurity' => true, ]) ); diff --git a/tests/unit/Migration/MigrationTest.php b/tests/unit/Migration/MigrationTest.php index 13f9b9a3f5..c322cc9635 100644 --- a/tests/unit/Migration/MigrationTest.php +++ b/tests/unit/Migration/MigrationTest.php @@ -22,12 +22,12 @@ abstract class MigrationTest extends TestCase /** * Runs every document fix twice, to prevent corrupted data on multiple migrations. * - * @param Document $document + * @param Document $document */ protected function fixDocument(Document $document) { return $this->method->invokeArgs($this->migration, [ - $this->method->invokeArgs($this->migration, [$document]) + $this->method->invokeArgs($this->migration, [$document]), ]); } @@ -36,14 +36,14 @@ abstract class MigrationTest extends TestCase */ public function testMigrationVersions(): void { - require_once __DIR__ . '/../../../app/init.php'; + require_once __DIR__.'/../../../app/init.php'; foreach (Migration::$versions as $class) { - $this->assertTrue(class_exists('Appwrite\\Migration\\Version\\' . $class)); + $this->assertTrue(class_exists('Appwrite\\Migration\\Version\\'.$class)); } // Test if current version exists // Only test official releases - skip if latest is release candidate - if (!(\str_contains(APP_VERSION_STABLE, 'RC'))) { + if (! (\str_contains(APP_VERSION_STABLE, 'RC'))) { $this->assertArrayHasKey(APP_VERSION_STABLE, Migration::$versions); } } @@ -60,8 +60,8 @@ abstract class MigrationTest extends TestCase 'a' => true, 'b' => 'abc', 'c' => 123, - 'd' => ['a', 'b', 'c'] - ] + 'd' => ['a', 'b', 'c'], + ], ], [ 'bool' => true, 'string' => 'abc', @@ -71,8 +71,8 @@ abstract class MigrationTest extends TestCase 'a' => true, 'b' => 'abc', 'c' => 123, - 'd' => ['a', 'b', 'c'] - ] + 'd' => ['a', 'b', 'c'], + ], ])); $this->assertFalse(Migration::hasDifference([ 'bool' => true, @@ -83,15 +83,15 @@ abstract class MigrationTest extends TestCase 'a' => true, 'b' => 'abc', 'c' => 123, - 'd' => ['a', 'b', 'c'] - ] + 'd' => ['a', 'b', 'c'], + ], ], [ 'string' => 'abc', 'assoc' => [ 'a' => true, 'b' => 'abc', 'c' => 123, - 'd' => ['a', 'b', 'c'] + 'd' => ['a', 'b', 'c'], ], 'int' => 123, 'array' => ['a', 'b', 'c'], @@ -99,40 +99,40 @@ abstract class MigrationTest extends TestCase ])); $this->assertTrue(Migration::hasDifference([ - 'a' => true + 'a' => true, ], [ - 'b' => true + 'b' => true, ])); $this->assertTrue(Migration::hasDifference([ - 'a' => 'true' + 'a' => 'true', ], [ - 'a' => true + 'a' => true, ])); $this->assertTrue(Migration::hasDifference([ - 'a' => true + 'a' => true, ], [ - 'a' => false + 'a' => false, ])); $this->assertTrue(Migration::hasDifference([ 'nested' => [ - 'a' => true - ] + 'a' => true, + ], ], [ - 'nested' => [] + 'nested' => [], ])); $this->assertTrue(Migration::hasDifference([ 'assoc' => [ 'bool' => true, 'string' => 'abc', 'int' => 123, - 'array' => ['a', 'b', 'c'] - ] + 'array' => ['a', 'b', 'c'], + ], ], [ 'nested' => [ 'a' => true, 'int' => '123', - 'array' => ['a', 'b', 'c'] - ] + 'array' => ['a', 'b', 'c'], + ], ])); } } diff --git a/tests/unit/Network/Validators/EmailTest.php b/tests/unit/Network/Validators/EmailTest.php index f629ed6ddc..d74f2c30fc 100755 --- a/tests/unit/Network/Validators/EmailTest.php +++ b/tests/unit/Network/Validators/EmailTest.php @@ -3,12 +3,13 @@ /** * Utopia PHP Framework * - * @package Framework - * @subpackage Tests * * @link https://github.com/utopia-php/framework + * * @author Appwrite Team + * * @version 1.0 RC4 + * * @license The MIT License (MIT) */ diff --git a/tests/unit/Template/TemplateTest.php b/tests/unit/Template/TemplateTest.php index 1ca1595ca3..ab4cb49742 100644 --- a/tests/unit/Template/TemplateTest.php +++ b/tests/unit/Template/TemplateTest.php @@ -14,10 +14,9 @@ class TemplateTest extends TestCase public function setUp(): void { - $this->object = new Template(__DIR__ . '/../../resources/template.tpl'); + $this->object = new Template(__DIR__.'/../../resources/template.tpl'); $this->object - ->setParam('{{world}}', 'WORLD') - ; + ->setParam('{{world}}', 'WORLD'); } public function tearDown(): void diff --git a/tests/unit/Usage/StatsTest.php b/tests/unit/Usage/StatsTest.php index 0c9914f4bd..72fadab70e 100644 --- a/tests/unit/Usage/StatsTest.php +++ b/tests/unit/Usage/StatsTest.php @@ -13,25 +13,26 @@ use Utopia\Queue\Connection; class StatsTest extends TestCase { protected ?Connection $connection = null; + protected ?Client $client = null; protected const QUEUE_NAME = 'usage-test-q'; public function setUp(): void { - $env = App::getEnv('_APP_CONNECTIONS_QUEUE', AppwriteURL::unparse([ - 'scheme' => 'redis', - 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), - 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), - 'user' => App::getEnv('_APP_REDIS_USER', ''), - 'pass' => App::getEnv('_APP_REDIS_PASS', ''), - ])); + $env = App::getEnv('_APP_CONNECTIONS_QUEUE', AppwriteURL::unparse([ + 'scheme' => 'redis', + 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), + 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), + 'user' => App::getEnv('_APP_REDIS_USER', ''), + 'pass' => App::getEnv('_APP_REDIS_PASS', ''), + ])); $dsn = explode('=', $env); $dsn = $dsn[1] ?? ''; $dsn = new DSN($dsn); $this->connection = new Queue\Connection\Redis($dsn->getHost(), $dsn->getPort()); - $this->client = new Client(self::QUEUE_NAME, $this->connection); + $this->client = new Client(self::QUEUE_NAME, $this->connection); } public function tearDown(): void @@ -41,13 +42,13 @@ class StatsTest extends TestCase public function testSamePayload(): void { $inToQueue = [ - 'key_1' => 'value_1', - 'key_2' => 'value_2', + 'key_1' => 'value_1', + 'key_2' => 'value_2', ]; $result = $this->client->enqueue($inToQueue); $this->assertTrue($result); - $outFromQueue = $this->connection->leftPopArray('utopia-queue.queue.' . self::QUEUE_NAME, 0)['payload']; + $outFromQueue = $this->connection->leftPopArray('utopia-queue.queue.'.self::QUEUE_NAME, 0)['payload']; $this->assertNotEmpty($outFromQueue); $this->assertSame($inToQueue, $outFromQueue); } diff --git a/tests/unit/Utopia/Lists.php b/tests/unit/Utopia/Lists.php index 8f003cc2ae..ac54a293a5 100644 --- a/tests/unit/Utopia/Lists.php +++ b/tests/unit/Utopia/Lists.php @@ -12,7 +12,7 @@ class Lists extends Model ->addRule('singles', [ 'type' => 'single', 'default' => '', - 'array' => true + 'array' => true, ]); } diff --git a/tests/unit/Utopia/Nested.php b/tests/unit/Utopia/Nested.php index 2be0e85762..b18f73977e 100644 --- a/tests/unit/Utopia/Nested.php +++ b/tests/unit/Utopia/Nested.php @@ -15,7 +15,7 @@ class Nested extends Model ]) ->addRule('single', [ 'type' => 'single', - 'default' => '' + 'default' => '', ]); } diff --git a/tests/unit/Utopia/Request/Filters/V15Test.php b/tests/unit/Utopia/Request/Filters/V15Test.php index 70bf71d4cb..7a37213d44 100644 --- a/tests/unit/Utopia/Request/Filters/V15Test.php +++ b/tests/unit/Utopia/Request/Filters/V15Test.php @@ -28,7 +28,7 @@ class V15Test extends TestCase return [ 'basic test' => [ ['limit' => '12', 'offset' => '0'], - ['queries' => ['limit(12)', 'offset(0)']] + ['queries' => ['limit(12)', 'offset(0)']], ], ]; } @@ -72,8 +72,8 @@ class V15Test extends TestCase 'limit(12)', 'offset(0)', 'cursorBefore("abcd")', - 'orderAsc("")' - ] + 'orderAsc("")', + ], ], ], ]; @@ -90,7 +90,7 @@ class V15Test extends TestCase [ 'queries' => [ 'cursorAfter("abcd")', - ] + ], ], ], 'cursorDirection invalid' => [ @@ -101,7 +101,7 @@ class V15Test extends TestCase [ 'queries' => [ 'cursorAfter("abcd")', - ] + ], ], ], ]; @@ -117,7 +117,7 @@ class V15Test extends TestCase [ 'queries' => [ 'orderDesc("")', - ] + ], ], ], 'orderType invalid' => [ @@ -127,7 +127,7 @@ class V15Test extends TestCase [ 'queries' => [ 'orderAsc("")', - ] + ], ], ], ]; @@ -239,7 +239,7 @@ class V15Test extends TestCase 'write invalid' => [ ['write' => ['invalid', 'invalid:a']], ['permissions' => ['write("invalid:a")']], - ] + ], ]; } @@ -320,7 +320,7 @@ class V15Test extends TestCase 'queries' => [ 'orderDesc("lastName")', 'orderAsc("firstName")', - ] + ], ], ], 'orderType only' => [ @@ -330,7 +330,7 @@ class V15Test extends TestCase [ 'queries' => [ 'orderDesc("")', - ] + ], ], ], 'orderType invalid' => [ @@ -341,7 +341,7 @@ class V15Test extends TestCase [ 'queries' => [ 'orderAsc("lastName")', - ] + ], ], ], ]; @@ -371,7 +371,7 @@ class V15Test extends TestCase 'greaterThan("age", [20])', 'greaterThanEqual("age", [21])', 'search("address", ["pla"])', - ] + ], ], ], ]; @@ -439,7 +439,7 @@ class V15Test extends TestCase 'team:b', 'team:c/member', 'member:z', - ] + ], ], ], ]; diff --git a/tests/unit/Utopia/Response/Filters/V15Test.php b/tests/unit/Utopia/Response/Filters/V15Test.php index fc38e5320b..cf08d9bb70 100644 --- a/tests/unit/Utopia/Response/Filters/V15Test.php +++ b/tests/unit/Utopia/Response/Filters/V15Test.php @@ -2,11 +2,11 @@ namespace Tests\Unit\Utopia\Response\Filters; -use Appwrite\Utopia\Response\Filters\V15; use Appwrite\Utopia\Response; +use Appwrite\Utopia\Response\Filters\V15; +use PHPUnit\Framework\TestCase; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use PHPUnit\Framework\TestCase; class V15Test extends TestCase { @@ -196,7 +196,7 @@ class V15Test extends TestCase 'maximumFileSize' => 100, 'allowedFileExtensions' => [ 'jpg', - 'png' + 'png', ], 'encryption' => false, 'antivirus' => false, @@ -213,7 +213,7 @@ class V15Test extends TestCase 'maximumFileSize' => 100, 'allowedFileExtensions' => [ 'jpg', - 'png' + 'png', ], 'encryption' => false, 'antivirus' => false, @@ -275,8 +275,8 @@ class V15Test extends TestCase [ 'startTime' => 1592981250, 'endTime' => 1592981250, - ] - ] + ], + ], ]; } @@ -346,14 +346,14 @@ class V15Test extends TestCase 'status' => 'available', 'required' => true, 'array' => false, - 'default' => false + 'default' => false, ], 'indexes' => [ 'key' => 'index1', 'type' => 'primary', 'status' => 'available', 'attributes' => [], - 'orders' => [] + 'orders' => [], ], ], [ @@ -361,10 +361,10 @@ class V15Test extends TestCase '$createdAt' => 1592981250, '$updatedAt' => 1592981250, '$read' => [ - 'role:all' + 'role:all', ], '$write' => [ - 'user:608f9da25e7e1' + 'user:608f9da25e7e1', ], 'databaseId' => '5e5ea5c16897e', 'name' => 'My Collection', @@ -376,14 +376,14 @@ class V15Test extends TestCase 'status' => 'available', 'required' => true, 'array' => false, - 'default' => false + 'default' => false, ], 'indexes' => [ 'key' => 'index1', 'type' => 'primary', 'status' => 'available', 'attributes' => [], - 'orders' => [] + 'orders' => [], ], ], ], @@ -511,7 +511,7 @@ class V15Test extends TestCase '$databaseId' => '5e5ea5c15117e', '$createdAt' => '2020-06-24T06:47:30.000Z', '$updatedAt' => '2020-06-24T06:47:30.000Z', - '$permissions' => [Permission::read(Role::any())] + '$permissions' => [Permission::read(Role::any())], ], [ '$id' => '5e5ea5c16897e', @@ -605,7 +605,7 @@ class V15Test extends TestCase '$createdAt' => '2020-06-24T06:47:30.000Z', '$updatedAt' => '2020-06-24T06:47:30.000Z', '$permissions' => [ - "any" + 'any', ], 'functionId' => '5e5ea6g16897e', 'trigger' => 'http', @@ -614,14 +614,14 @@ class V15Test extends TestCase 'response' => '', 'stdout' => '', 'stderr' => '', - 'duration' => 0.4 + 'duration' => 0.4, ], [ '$id' => '5e5ea5c16897e', '$createdAt' => 1592981250, '$updatedAt' => 1592981250, '$read' => [ - "role:all" + 'role:all', ], 'functionId' => '5e5ea6g16897e', 'trigger' => 'http', @@ -629,7 +629,7 @@ class V15Test extends TestCase 'statusCode' => 0, 'response' => '', 'stderr' => '', - 'time' => 0.4 + 'time' => 0.4, ], ], ]; @@ -730,37 +730,37 @@ class V15Test extends TestCase 'key' => 'key', 'value' => 'value', 'functionId' => '5e5ea5c16897e', - ] + ], ], 'events' => [ - 'account.create' + 'account.create', ], 'schedule' => '5 4 * * *', 'scheduleNext' => '2020-06-24T06:48:12.000Z', 'schedulePrevious' => '2020-06-24T06:47:17.000Z', - 'timeout' => 1592981237 + 'timeout' => 1592981237, ], [ '$id' => '5e5ea5c16897e', '$createdAt' => 1592981250, '$updatedAt' => 1592981250, 'execute' => [ - 'role:member' + 'role:member', ], 'name' => 'My Function', 'status' => 'enabled', 'runtime' => 'python-3.8', 'deployment' => '5e5ea5c16897e', 'vars' => [ - 'key' => 'value' + 'key' => 'value', ], 'events' => [ - 'account.create' + 'account.create', ], 'schedule' => '5 4 * * *', 'scheduleNext' => 1592981292, 'schedulePrevious' => 1592981237, - 'timeout' => 1592981237 + 'timeout' => 1592981237, ], ], 'enabled false' => [ @@ -877,7 +877,7 @@ class V15Test extends TestCase 'deviceBrand' => 'Google', 'deviceModel' => 'Nexus 5', 'countryCode' => 'US', - 'countryName' => 'United States' + 'countryName' => 'United States', ], [ 'event' => 'account.sessions.create', @@ -900,8 +900,8 @@ class V15Test extends TestCase 'deviceBrand' => 'Google', 'deviceModel' => 'Nexus 5', 'countryCode' => 'US', - 'countryName' => 'United States' - ] + 'countryName' => 'United States', + ], ], ]; } diff --git a/tests/unit/Utopia/ResponseTest.php b/tests/unit/Utopia/ResponseTest.php index e4389b3953..f7be5a03a4 100644 --- a/tests/unit/Utopia/ResponseTest.php +++ b/tests/unit/Utopia/ResponseTest.php @@ -2,9 +2,9 @@ namespace Tests\Unit\Utopia; -use Exception; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Filters\V11; +use Exception; use PHPUnit\Framework\TestCase; use Swoole\Http\Response as SwooleResponse; use Utopia\Database\Document; @@ -80,8 +80,8 @@ class ResponseTest extends TestCase 'string' => 'lorem ipsum', 'integer' => 123, 'boolean' => true, - 'hidden' => 'secret' - ]) + 'hidden' => 'secret', + ]), ], 'hidden' => 'secret', ]), 'lists'); @@ -107,8 +107,8 @@ class ResponseTest extends TestCase 'string' => 'lorem ipsum', 'integer' => 123, 'boolean' => true, - 'hidden' => 'secret' - ]) + 'hidden' => 'secret', + ]), ], 'hidden' => 'secret', ]), @@ -116,7 +116,7 @@ class ResponseTest extends TestCase 'string' => 'lorem ipsum', 'integer' => 123, 'boolean' => true, - 'hidden' => 'secret' + 'hidden' => 'secret', ]), 'hidden' => 'secret', ]), 'nested'); @@ -126,7 +126,6 @@ class ResponseTest extends TestCase $this->assertArrayNotHasKey('hidden', $output); $this->assertCount(1, $output['lists']['singles']); - $single = $output['single']; $this->assertArrayHasKey('string', $single); $this->assertArrayHasKey('integer', $single); diff --git a/tests/unit/Utopia/Single.php b/tests/unit/Utopia/Single.php index 3bd09ef6da..6e9fd3c9ec 100644 --- a/tests/unit/Utopia/Single.php +++ b/tests/unit/Utopia/Single.php @@ -12,7 +12,7 @@ class Single extends Model ->addRule('string', [ 'type' => self::TYPE_STRING, 'example' => '5e5ea5c16897e', - 'required' => true + 'required' => true, ]) ->addRule('integer', [ 'type' => self::TYPE_INTEGER, @@ -27,7 +27,7 @@ class Single extends Model ->addRule('required', [ 'type' => self::TYPE_STRING, 'default' => 'default', - 'required' => true + 'required' => true, ]); } From ac33d7828f0079169a461b7e931ad8830ce1772c Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 24 Aug 2023 01:53:52 +0530 Subject: [PATCH 033/196] Revert "Pint linter ran" This reverts commit bf5f0a841921920e3a2cca09875fa9946d73ce89. --- app/cli.php | 31 +- app/config/authProviders.php | 14 +- app/config/avatars/browsers.php | 29 +- app/config/avatars/credit-cards.php | 34 +- app/config/avatars/flags.php | 388 +++--- app/config/avatars/os.php | 6 +- app/config/collections.php | 48 +- app/config/errors.php | 8 +- app/config/events.php | 66 +- app/config/locale/codes.php | 525 ++++---- app/config/locale/languages.php | 1106 ++++++++--------- app/config/locale/templates.php | 4 +- app/config/messagingProviders.php | 586 ++++----- app/config/platforms.php | 44 +- app/config/regions.php | 2 +- app/config/roles.php | 4 +- app/config/runtimes.php | 2 +- app/config/scopes.php | 4 +- app/config/services.php | 6 +- app/config/usage.php | 40 +- app/config/variables.php | 196 +-- app/controllers/api/account.php | 527 ++++---- app/controllers/api/avatars.php | 169 +-- app/controllers/api/console.php | 3 + app/controllers/api/databases.php | 642 +++++----- app/controllers/api/functions.php | 205 +-- app/controllers/api/graphql.php | 23 +- app/controllers/api/health.php | 98 +- app/controllers/api/locale.php | 27 +- app/controllers/api/messaging.php | 788 ++++++------ app/controllers/api/migrations.php | 40 +- app/controllers/api/project.php | 28 +- app/controllers/api/projects.php | 178 ++- app/controllers/api/storage.php | 306 ++--- app/controllers/api/teams.php | 175 +-- app/controllers/api/users.php | 141 ++- app/controllers/general.php | 157 +-- app/controllers/mock.php | 67 +- app/controllers/shared/api.php | 107 +- app/controllers/shared/api/auth.php | 3 +- app/controllers/web/console.php | 24 +- app/controllers/web/home.php | 4 +- app/http.php | 76 +- app/init.php | 303 +++-- app/preload.php | 40 +- app/realtime.php | 147 +-- app/worker.php | 40 +- app/workers/audits.php | 6 +- app/workers/builds.php | 39 +- app/workers/certificates.php | 144 ++- app/workers/databases.php | 104 +- app/workers/deletes.php | 275 ++-- app/workers/functions.php | 40 +- app/workers/mails.php | 18 +- app/workers/messaging.php | 35 +- app/workers/migrations.php | 4 +- app/workers/usage.php | 92 +- app/workers/webhooks.php | 30 +- src/Appwrite/Auth/Auth.php | 117 +- src/Appwrite/Auth/Hash.php | 25 +- src/Appwrite/Auth/Hash/Argon2.php | 10 +- src/Appwrite/Auth/Hash/Bcrypt.php | 12 +- src/Appwrite/Auth/Hash/Md5.php | 10 +- src/Appwrite/Auth/Hash/Phpass.php | 61 +- src/Appwrite/Auth/Hash/Scrypt.php | 12 +- src/Appwrite/Auth/Hash/Scryptmodified.php | 14 +- src/Appwrite/Auth/Hash/Sha.php | 12 +- src/Appwrite/Auth/OAuth2.php | 56 +- src/Appwrite/Auth/OAuth2/Amazon.php | 40 +- src/Appwrite/Auth/OAuth2/Apple.php | 47 +- src/Appwrite/Auth/OAuth2/Auth0.php | 41 +- src/Appwrite/Auth/OAuth2/Authentik.php | 47 +- src/Appwrite/Auth/OAuth2/Autodesk.php | 29 +- src/Appwrite/Auth/OAuth2/Bitbucket.php | 32 +- src/Appwrite/Auth/OAuth2/Bitly.php | 57 +- src/Appwrite/Auth/OAuth2/Box.php | 53 +- src/Appwrite/Auth/OAuth2/Dailymotion.php | 50 +- src/Appwrite/Auth/OAuth2/Discord.php | 39 +- src/Appwrite/Auth/OAuth2/Disqus.php | 36 +- src/Appwrite/Auth/OAuth2/Dropbox.php | 31 +- src/Appwrite/Auth/OAuth2/Etsy.php | 33 +- src/Appwrite/Auth/OAuth2/Exception.php | 6 +- src/Appwrite/Auth/OAuth2/Facebook.php | 39 +- src/Appwrite/Auth/OAuth2/Firebase.php | 75 +- src/Appwrite/Auth/OAuth2/Github.php | 40 +- src/Appwrite/Auth/OAuth2/Gitlab.php | 40 +- src/Appwrite/Auth/OAuth2/Google.php | 37 +- src/Appwrite/Auth/OAuth2/Linkedin.php | 33 +- src/Appwrite/Auth/OAuth2/Microsoft.php | 40 +- src/Appwrite/Auth/OAuth2/Mock.php | 38 +- src/Appwrite/Auth/OAuth2/Notion.php | 43 +- src/Appwrite/Auth/OAuth2/Oidc.php | 82 +- src/Appwrite/Auth/OAuth2/Okta.php | 41 +- src/Appwrite/Auth/OAuth2/Paypal.php | 41 +- src/Appwrite/Auth/OAuth2/PaypalSandbox.php | 2 + src/Appwrite/Auth/OAuth2/Podio.php | 41 +- src/Appwrite/Auth/OAuth2/Salesforce.php | 42 +- src/Appwrite/Auth/OAuth2/Slack.php | 39 +- src/Appwrite/Auth/OAuth2/Spotify.php | 47 +- src/Appwrite/Auth/OAuth2/Stripe.php | 37 +- src/Appwrite/Auth/OAuth2/Tradeshift.php | 52 +- src/Appwrite/Auth/OAuth2/TradeshiftBox.php | 2 + src/Appwrite/Auth/OAuth2/Twitch.php | 53 +- src/Appwrite/Auth/OAuth2/WordPress.php | 31 +- src/Appwrite/Auth/OAuth2/Yahoo.php | 49 +- src/Appwrite/Auth/OAuth2/Yammer.php | 37 +- src/Appwrite/Auth/OAuth2/Yandex.php | 43 +- src/Appwrite/Auth/OAuth2/Zoom.php | 39 +- src/Appwrite/Auth/Validator/Password.php | 5 +- .../Auth/Validator/PasswordDictionary.php | 7 +- .../Auth/Validator/PasswordHistory.php | 6 +- src/Appwrite/Auth/Validator/PersonalData.php | 7 +- src/Appwrite/Auth/Validator/Phone.php | 5 +- src/Appwrite/Detector/Detector.php | 8 +- src/Appwrite/Docker/Compose.php | 4 +- src/Appwrite/Docker/Compose/Service.php | 5 +- src/Appwrite/Docker/Env.php | 14 +- src/Appwrite/Event/Audit.php | 12 +- src/Appwrite/Event/Build.php | 11 +- src/Appwrite/Event/Certificate.php | 8 +- src/Appwrite/Event/Database.php | 17 +- src/Appwrite/Event/Delete.php | 19 +- src/Appwrite/Event/Event.php | 78 +- src/Appwrite/Event/Func.php | 20 +- src/Appwrite/Event/Mail.php | 37 +- src/Appwrite/Event/Migration.php | 14 +- src/Appwrite/Event/Phone.php | 8 +- src/Appwrite/Event/Usage.php | 13 +- src/Appwrite/Event/Validator/Event.php | 24 +- src/Appwrite/Extend/Exception.php | 371 ++---- src/Appwrite/GraphQL/Promises/Adapter.php | 21 +- src/Appwrite/GraphQL/Resolvers.php | 129 +- src/Appwrite/GraphQL/Schema.php | 68 +- src/Appwrite/GraphQL/Types.php | 3 - src/Appwrite/GraphQL/Types/Assoc.php | 8 +- src/Appwrite/GraphQL/Types/InputFile.php | 3 +- src/Appwrite/GraphQL/Types/Json.php | 4 +- src/Appwrite/GraphQL/Types/Mapper.php | 49 +- src/Appwrite/GraphQL/Types/Registry.php | 8 +- src/Appwrite/Messaging/Adapter.php | 2 - src/Appwrite/Messaging/Adapter/Realtime.php | 84 +- src/Appwrite/Migration/Migration.php | 80 +- src/Appwrite/Migration/Version/V15.php | 47 +- src/Appwrite/Migration/Version/V16.php | 14 +- src/Appwrite/Migration/Version/V17.php | 12 +- src/Appwrite/Migration/Version/V18.php | 6 +- src/Appwrite/Migration/Version/V19.php | 11 +- src/Appwrite/Network/Validator/CNAME.php | 9 +- src/Appwrite/Network/Validator/Email.php | 6 +- src/Appwrite/Network/Validator/Origin.php | 39 +- src/Appwrite/OpenSSL/OpenSSL.php | 26 +- src/Appwrite/Platform/Services/Tasks.php | 20 +- src/Appwrite/Platform/Tasks/CalcTierStats.php | 54 +- .../Platform/Tasks/CalcUsersStats.php | 27 +- .../Platform/Tasks/ClearCardCache.php | 14 +- src/Appwrite/Platform/Tasks/Doctor.php | 93 +- src/Appwrite/Platform/Tasks/Hamster.php | 95 +- src/Appwrite/Platform/Tasks/Install.php | 68 +- src/Appwrite/Platform/Tasks/Maintenance.php | 18 +- src/Appwrite/Platform/Tasks/Migrate.php | 21 +- .../Tasks/PatchCreateMissingSchedules.php | 16 +- .../Tasks/PatchDeleteProjectCollections.php | 22 +- .../PatchDeleteScheduleUpdatedAtAttribute.php | 12 +- src/Appwrite/Platform/Tasks/SDKs.php | 86 +- src/Appwrite/Platform/Tasks/SSL.php | 6 +- src/Appwrite/Platform/Tasks/Schedule.php | 37 +- src/Appwrite/Platform/Tasks/Specs.php | 50 +- src/Appwrite/Platform/Tasks/Vars.php | 4 +- src/Appwrite/Platform/Tasks/VolumeSync.php | 16 +- src/Appwrite/Promises/Promise.php | 35 +- src/Appwrite/Promises/Swoole.php | 4 +- src/Appwrite/Resque/Worker.php | 84 +- src/Appwrite/Specification/Format.php | 31 +- .../Specification/Format/OpenAPI3.php | 92 +- .../Specification/Format/Swagger2.php | 82 +- src/Appwrite/Task/Validator/Cron.php | 5 +- src/Appwrite/Template/Template.php | 37 +- src/Appwrite/URL/URL.php | 34 +- .../Utopia/Database/Validator/CustomId.php | 2 + .../Utopia/Database/Validator/ProjectId.php | 1 + .../Database/Validator/Queries/Attributes.php | 5 +- .../Database/Validator/Queries/Base.php | 20 +- .../Database/Validator/Queries/Buckets.php | 3 +- .../Validator/Queries/Collections.php | 3 +- .../Database/Validator/Queries/Databases.php | 3 +- .../Validator/Queries/Deployments.php | 1 + .../Database/Validator/Queries/Executions.php | 3 +- .../Database/Validator/Queries/Files.php | 3 +- .../Database/Validator/Queries/Functions.php | 3 +- .../Database/Validator/Queries/Identities.php | 1 + .../Database/Validator/Queries/Indexes.php | 1 + .../Validator/Queries/Memberships.php | 3 +- .../Database/Validator/Queries/Migrations.php | 3 +- .../Database/Validator/Queries/Projects.php | 5 +- .../Database/Validator/Queries/Providers.php | 1 + .../Database/Validator/Queries/Teams.php | 3 +- .../Database/Validator/Queries/Users.php | 3 +- .../Database/Validator/Queries/Variables.php | 5 +- src/Appwrite/Utopia/Request.php | 11 +- src/Appwrite/Utopia/Request/Filter.php | 5 +- src/Appwrite/Utopia/Request/Filters/V12.php | 45 +- src/Appwrite/Utopia/Request/Filters/V13.php | 16 +- src/Appwrite/Utopia/Request/Filters/V14.php | 12 +- src/Appwrite/Utopia/Request/Filters/V15.php | 25 +- src/Appwrite/Utopia/Response.php | 246 +--- src/Appwrite/Utopia/Response/Filter.php | 5 +- src/Appwrite/Utopia/Response/Filters/V11.php | 35 +- src/Appwrite/Utopia/Response/Filters/V12.php | 12 - src/Appwrite/Utopia/Response/Filters/V13.php | 3 - src/Appwrite/Utopia/Response/Filters/V15.php | 18 +- src/Appwrite/Utopia/Response/Model.php | 16 +- .../Utopia/Response/Model/AlgoArgon2.php | 3 +- .../Utopia/Response/Model/AlgoScrypt.php | 3 +- .../Response/Model/AlgoScryptModified.php | 3 +- .../Utopia/Response/Model/Attribute.php | 3 +- .../Response/Model/AttributeBoolean.php | 7 +- .../Response/Model/AttributeDatetime.php | 5 +- .../Utopia/Response/Model/AttributeEmail.php | 5 +- .../Utopia/Response/Model/AttributeEnum.php | 5 +- .../Utopia/Response/Model/AttributeFloat.php | 3 +- .../Utopia/Response/Model/AttributeIP.php | 5 +- .../Response/Model/AttributeInteger.php | 4 +- .../Utopia/Response/Model/AttributeList.php | 7 +- .../Response/Model/AttributeRelationship.php | 6 +- .../Utopia/Response/Model/AttributeString.php | 3 +- .../Utopia/Response/Model/AttributeURL.php | 5 +- .../Utopia/Response/Model/AuthProvider.php | 3 +- .../Utopia/Response/Model/BaseList.php | 20 +- src/Appwrite/Utopia/Response/Model/Bucket.php | 9 +- src/Appwrite/Utopia/Response/Model/Build.php | 3 +- .../Utopia/Response/Model/Collection.php | 7 +- .../Utopia/Response/Model/Continent.php | 3 +- .../Utopia/Response/Model/Country.php | 3 +- .../Utopia/Response/Model/Currency.php | 3 +- .../Utopia/Response/Model/Database.php | 3 +- .../Utopia/Response/Model/Deployment.php | 3 +- src/Appwrite/Utopia/Response/Model/Domain.php | 3 +- src/Appwrite/Utopia/Response/Model/Error.php | 3 +- .../Utopia/Response/Model/ErrorDev.php | 3 +- .../Utopia/Response/Model/Execution.php | 3 +- src/Appwrite/Utopia/Response/Model/File.php | 3 +- src/Appwrite/Utopia/Response/Model/Func.php | 7 +- .../Utopia/Response/Model/HealthAntivirus.php | 3 +- .../Utopia/Response/Model/HealthQueue.php | 3 +- .../Utopia/Response/Model/HealthStatus.php | 3 +- .../Utopia/Response/Model/HealthTime.php | 3 +- .../Utopia/Response/Model/HealthVersion.php | 3 +- .../Utopia/Response/Model/Identity.php | 3 +- src/Appwrite/Utopia/Response/Model/Index.php | 3 +- src/Appwrite/Utopia/Response/Model/JWT.php | 3 +- src/Appwrite/Utopia/Response/Model/Key.php | 9 +- .../Utopia/Response/Model/Language.php | 3 +- src/Appwrite/Utopia/Response/Model/Locale.php | 3 +- .../Utopia/Response/Model/LocaleCode.php | 3 +- src/Appwrite/Utopia/Response/Model/Log.php | 3 +- .../Utopia/Response/Model/Membership.php | 3 +- src/Appwrite/Utopia/Response/Model/Metric.php | 2 +- .../Utopia/Response/Model/Migration.php | 5 +- src/Appwrite/Utopia/Response/Model/Mock.php | 3 +- src/Appwrite/Utopia/Response/Model/Phone.php | 3 +- .../Utopia/Response/Model/Platform.php | 3 +- .../Utopia/Response/Model/Project.php | 37 +- .../Utopia/Response/Model/Runtime.php | 5 +- .../Utopia/Response/Model/Session.php | 3 +- src/Appwrite/Utopia/Response/Model/Team.php | 4 +- .../Utopia/Response/Model/Template.php | 3 +- .../Utopia/Response/Model/TemplateEmail.php | 3 +- .../Utopia/Response/Model/TemplateSMS.php | 1 - src/Appwrite/Utopia/Response/Model/Token.php | 3 +- .../Utopia/Response/Model/UsageBuckets.php | 7 +- .../Utopia/Response/Model/UsageCollection.php | 5 +- .../Utopia/Response/Model/UsageDatabase.php | 7 +- .../Utopia/Response/Model/UsageDatabases.php | 9 +- .../Utopia/Response/Model/UsageFunction.php | 17 +- .../Utopia/Response/Model/UsageFunctions.php | 19 +- .../Utopia/Response/Model/UsageProject.php | 19 +- .../Utopia/Response/Model/UsageStorage.php | 9 +- .../Utopia/Response/Model/UsageUsers.php | 7 +- src/Appwrite/Utopia/Response/Model/User.php | 6 +- .../Utopia/Response/Model/Variable.php | 3 +- .../Utopia/Response/Model/Webhook.php | 3 +- src/Appwrite/Utopia/View.php | 3 +- src/Executor/Executor.php | 104 +- tests/e2e/Client.php | 66 +- tests/e2e/General/AbuseTest.php | 42 +- tests/e2e/General/HTTPTest.php | 8 +- tests/e2e/General/UsageTest.php | 111 +- tests/e2e/Scopes/ProjectCustom.php | 23 +- tests/e2e/Scopes/Scope.php | 11 +- tests/e2e/Scopes/SideClient.php | 2 +- tests/e2e/Scopes/SideConsole.php | 4 +- tests/e2e/Scopes/SideServer.php | 2 +- tests/e2e/Services/Account/AccountBase.php | 197 +-- .../Account/AccountConsoleClientTest.php | 14 +- .../Account/AccountCustomClientTest.php | 141 ++- .../Account/AccountCustomServerTest.php | 2 +- tests/e2e/Services/Avatars/AvatarsBase.php | 17 +- .../Avatars/AvatarsConsoleClientTest.php | 2 +- .../Avatars/AvatarsCustomClientTest.php | 2 +- .../e2e/Services/Databases/DatabasesBase.php | 900 +++++++------- .../Databases/DatabasesConsoleClientTest.php | 84 +- .../Databases/DatabasesCustomClientTest.php | 269 ++-- .../Databases/DatabasesCustomServerTest.php | 1088 ++++++++-------- .../DatabasesPermissionsGuestTest.php | 48 +- .../DatabasesPermissionsMemberTest.php | 40 +- .../Databases/DatabasesPermissionsScope.php | 15 +- .../DatabasesPermissionsTeamTest.php | 27 +- .../e2e/Services/Functions/FunctionsBase.php | 3 +- .../Functions/FunctionsConsoleClientTest.php | 125 +- .../Functions/FunctionsCustomClientTest.php | 105 +- .../Functions/FunctionsCustomServerTest.php | 231 ++-- tests/e2e/Services/GraphQL/AbuseTest.php | 8 +- tests/e2e/Services/GraphQL/AccountTest.php | 36 +- tests/e2e/Services/GraphQL/AuthTest.php | 49 +- tests/e2e/Services/GraphQL/Base.php | 155 +-- tests/e2e/Services/GraphQL/BatchTest.php | 39 +- .../e2e/Services/GraphQL/ContentTypeTest.php | 8 +- .../Services/GraphQL/DatabaseClientTest.php | 22 +- .../Services/GraphQL/DatabaseServerTest.php | 137 +- .../Services/GraphQL/FunctionsClientTest.php | 26 +- .../Services/GraphQL/FunctionsServerTest.php | 54 +- .../e2e/Services/GraphQL/LocalizationTest.php | 2 +- tests/e2e/Services/GraphQL/ScopeTest.php | 5 +- .../Services/GraphQL/StorageClientTest.php | 36 +- .../Services/GraphQL/StorageServerTest.php | 49 +- .../e2e/Services/GraphQL/TeamsServerTest.php | 8 +- tests/e2e/Services/GraphQL/UsersTest.php | 39 +- tests/e2e/Services/Health/HealthBase.php | 2 + .../Health/HealthCustomServerTest.php | 3 +- tests/e2e/Services/Locale/LocaleBase.php | 16 +- .../Locale/LocaleConsoleClientTest.php | 2 +- .../Locale/LocaleCustomClientTest.php | 2 +- .../Locale/LocaleCustomServerTest.php | 1 + .../Messaging/MessagingServerTest.php | 9 +- tests/e2e/Services/Projects/ProjectsBase.php | 2 + .../Projects/ProjectsConsoleClientTest.php | 485 ++++---- .../Projects/ProjectsCustomClientTest.php | 3 +- .../Projects/ProjectsCustomServerTest.php | 1 + tests/e2e/Services/Realtime/RealtimeBase.php | 12 +- .../Realtime/RealtimeConsoleClientTest.php | 53 +- .../Realtime/RealtimeCustomClientTest.php | 331 ++--- tests/e2e/Services/Storage/StorageBase.php | 161 +-- .../Storage/StorageConsoleClientTest.php | 29 +- .../Storage/StorageCustomClientTest.php | 419 +++---- .../Storage/StorageCustomServerTest.php | 46 +- .../Storage/StoragePermissionsScope.php | 16 +- tests/e2e/Services/Teams/TeamsBase.php | 47 +- tests/e2e/Services/Teams/TeamsBaseClient.php | 155 +-- tests/e2e/Services/Teams/TeamsBaseServer.php | 52 +- .../Services/Teams/TeamsConsoleClientTest.php | 34 +- .../Services/Teams/TeamsCustomClientTest.php | 2 +- .../Services/Teams/TeamsCustomServerTest.php | 1 + tests/e2e/Services/Users/UsersBase.php | 134 +- .../Services/Users/UsersConsoleClientTest.php | 9 +- .../Services/Users/UsersCustomServerTest.php | 1 + tests/e2e/Services/Webhooks/WebhooksBase.php | 136 +- .../Webhooks/WebhooksCustomClientTest.php | 102 +- .../Webhooks/WebhooksCustomServerTest.php | 77 +- tests/extensions/Retryable.php | 13 +- tests/extensions/TestHook.php | 2 +- tests/resources/functions/php-fn/index.php | 2 +- tests/resources/functions/php-large/index.php | 2 +- tests/resources/functions/php/index.php | 2 +- tests/unit/Auth/AuthTest.php | 62 +- .../Auth/Validator/PasswordDictionaryTest.php | 1 + tests/unit/Docker/ComposeTest.php | 2 +- tests/unit/Docker/EnvTest.php | 6 +- tests/unit/Event/EventTest.php | 12 +- tests/unit/General/CollectionsTest.php | 2 +- .../unit/Messaging/MessagingChannelsTest.php | 53 +- tests/unit/Messaging/MessagingGuestTest.php | 4 +- tests/unit/Messaging/MessagingTest.php | 28 +- tests/unit/Migration/MigrationTest.php | 50 +- tests/unit/Network/Validators/EmailTest.php | 5 +- tests/unit/Template/TemplateTest.php | 5 +- tests/unit/Usage/StatsTest.php | 23 +- tests/unit/Utopia/Lists.php | 2 +- tests/unit/Utopia/Nested.php | 2 +- tests/unit/Utopia/Request/Filters/V15Test.php | 26 +- .../unit/Utopia/Response/Filters/V15Test.php | 54 +- tests/unit/Utopia/ResponseTest.php | 13 +- tests/unit/Utopia/Single.php | 4 +- 382 files changed, 10328 insertions(+), 10216 deletions(-) diff --git a/app/cli.php b/app/cli.php index 2614e00e11..d1dd885775 100644 --- a/app/cli.php +++ b/app/cli.php @@ -1,27 +1,27 @@ $register); +CLI::setResource('register', fn()=>$register); CLI::setResource('cache', function ($pools) { $list = Config::getParam('pools-cache', []); @@ -31,7 +31,8 @@ CLI::setResource('cache', function ($pools) { $adapters[] = $pools ->get($value) ->pop() - ->getResource(); + ->getResource() + ; } return new Cache(new Sharding($adapters)); @@ -63,7 +64,7 @@ CLI::setResource('dbForConsole', function ($pools, $cache) { $collections = Config::getParam('collections', [])['console']; $last = \array_key_last($collections); - if (! ($dbForConsole->exists($dbForConsole->getDefaultDatabase(), $last))) { /** TODO cache ready variable using registry */ + if (!($dbForConsole->exists($dbForConsole->getDefaultDatabase(), $last))) { /** TODO cache ready variable using registry */ throw new Exception('Tables not ready yet.'); } @@ -75,8 +76,8 @@ CLI::setResource('dbForConsole', function ($pools, $cache) { } } while ($attempts < $maxAttempts); - if (! $ready) { - throw new Exception('Console is not ready yet. Please try again later.'); + if (!$ready) { + throw new Exception("Console is not ready yet. Please try again later."); } return $dbForConsole; @@ -94,8 +95,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, if (isset($databases[$databaseName])) { $database = $databases[$databaseName]; - $database->setNamespace('_'.$project->getInternalId()); - + $database->setNamespace('_' . $project->getInternalId()); return $database; } @@ -108,7 +108,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, $databases[$databaseName] = $database; - $database->setNamespace('_'.$project->getInternalId()); + $database->setNamespace('_' . $project->getInternalId()); return $database; }; @@ -116,6 +116,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, return $getProjectDB; }, ['pools', 'dbForConsole', 'cache']); + CLI::setResource('queueForFunctions', function (Group $pools) { return new Func($pools->get('queue')->pop()->getResource()); }, ['pools']); @@ -148,7 +149,7 @@ CLI::setResource('logError', function (Registry $register) { $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); $responseCode = $logger->addLog($log); - Console::info('Usage stats log pushed with status code: '.$responseCode); + Console::info('Usage stats log pushed with status code: ' . $responseCode); } Console::warning("Failed: {$error->getMessage()}"); diff --git a/app/config/authProviders.php b/app/config/authProviders.php index cf9ad052c3..dedb4ec665 100644 --- a/app/config/authProviders.php +++ b/app/config/authProviders.php @@ -69,7 +69,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false, + 'mock' => false ], 'box' => [ 'name' => 'Box', @@ -79,7 +79,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false, + 'mock' => false ], 'dailymotion' => [ 'name' => 'Dailymotion', @@ -89,7 +89,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false, + 'mock' => false ], 'discord' => [ 'name' => 'Discord', @@ -229,7 +229,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false, + 'mock' => false ], 'paypalSandbox' => [ 'name' => 'PayPal Sandbox', @@ -239,7 +239,7 @@ return [ // Ordered by ABC. 'sandbox' => true, 'form' => false, 'beta' => false, - 'mock' => false, + 'mock' => false ], 'podio' => [ 'name' => 'Podio', @@ -289,7 +289,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false, + 'mock' => false ], 'tradeshift' => [ 'name' => 'Tradeshift', @@ -329,7 +329,7 @@ return [ // Ordered by ABC. 'sandbox' => false, 'form' => false, 'beta' => false, - 'mock' => false, + 'mock' => false ], 'yahoo' => [ 'name' => 'Yahoo', diff --git a/app/config/avatars/browsers.php b/app/config/avatars/browsers.php index 7d80937bd3..e7d31c7443 100644 --- a/app/config/avatars/browsers.php +++ b/app/config/avatars/browsers.php @@ -2,20 +2,21 @@ return [ // Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php - 'aa' => ['name' => 'Avant Browser', 'path' => __DIR__.'/browsers/avant.png'], - 'an' => ['name' => 'Android WebView Beta', 'path' => __DIR__.'/browsers/android-webview-beta.png'], - 'ch' => ['name' => 'Google Chrome', 'path' => __DIR__.'/browsers/chrome.png'], - 'ci' => ['name' => 'Google Chrome (iOS)', 'path' => __DIR__.'/browsers/chrome.png'], - 'cm' => ['name' => 'Google Chrome (Mobile)', 'path' => __DIR__.'/browsers/chrome.png'], - 'cr' => ['name' => 'Chromium', 'path' => __DIR__.'/browsers/chromium.png'], - 'ff' => ['name' => 'Mozilla Firefox', 'path' => __DIR__.'/browsers/firefox.png'], - 'sf' => ['name' => 'Safari', 'path' => __DIR__.'/browsers/safari.png'], - 'mf' => ['name' => 'Mobile Safari', 'path' => __DIR__.'/browsers/safari.png'], - 'ps' => ['name' => 'Microsoft Edge', 'path' => __DIR__.'/browsers/edge.png'], - 'oi' => ['name' => 'Microsoft Edge (iOS)', 'path' => __DIR__.'/browsers/edge.png'], - 'om' => ['name' => 'Opera Mini', 'path' => __DIR__.'/browsers/opera-mini.png'], - 'op' => ['name' => 'Opera', 'path' => __DIR__.'/browsers/opera.png'], - 'on' => ['name' => 'Opera (Next)', 'path' => __DIR__.'/browsers/opera.png'], + 'aa' => ['name' => 'Avant Browser', 'path' => __DIR__ . '/browsers/avant.png'], + 'an' => ['name' => 'Android WebView Beta', 'path' => __DIR__ . '/browsers/android-webview-beta.png'], + 'ch' => ['name' => 'Google Chrome', 'path' => __DIR__ . '/browsers/chrome.png'], + 'ci' => ['name' => 'Google Chrome (iOS)', 'path' => __DIR__ . '/browsers/chrome.png'], + 'cm' => ['name' => 'Google Chrome (Mobile)', 'path' => __DIR__ . '/browsers/chrome.png'], + 'cr' => ['name' => 'Chromium', 'path' => __DIR__ . '/browsers/chromium.png'], + 'ff' => ['name' => 'Mozilla Firefox', 'path' => __DIR__ . '/browsers/firefox.png'], + 'sf' => ['name' => 'Safari', 'path' => __DIR__ . '/browsers/safari.png'], + 'mf' => ['name' => 'Mobile Safari', 'path' => __DIR__ . '/browsers/safari.png'], + 'ps' => ['name' => 'Microsoft Edge', 'path' => __DIR__ . '/browsers/edge.png'], + 'oi' => ['name' => 'Microsoft Edge (iOS)', 'path' => __DIR__ . '/browsers/edge.png'], + 'om' => ['name' => 'Opera Mini', 'path' => __DIR__ . '/browsers/opera-mini.png'], + 'op' => ['name' => 'Opera', 'path' => __DIR__ . '/browsers/opera.png'], + 'on' => ['name' => 'Opera (Next)', 'path' => __DIR__ . '/browsers/opera.png'], + /* '36' => '360 Phone Browser', diff --git a/app/config/avatars/credit-cards.php b/app/config/avatars/credit-cards.php index 0655c6fcda..aaef17ee3f 100644 --- a/app/config/avatars/credit-cards.php +++ b/app/config/avatars/credit-cards.php @@ -1,20 +1,20 @@ ['name' => 'American Express', 'path' => __DIR__.'/credit-cards/amex.png'], - 'argencard' => ['name' => 'Argencard', 'path' => __DIR__.'/credit-cards/argencard.png'], - 'cabal' => ['name' => 'Cabal', 'path' => __DIR__.'/credit-cards/cabal.png'], - 'censosud' => ['name' => 'Consosud', 'path' => __DIR__.'/credit-cards/consosud.png'], - 'diners' => ['name' => 'Diners Club', 'path' => __DIR__.'/credit-cards/diners.png'], - 'discover' => ['name' => 'Discover', 'path' => __DIR__.'/credit-cards/discover.png'], - 'elo' => ['name' => 'Elo', 'path' => __DIR__.'/credit-cards/elo.png'], - 'hipercard' => ['name' => 'Hipercard', 'path' => __DIR__.'/credit-cards/hipercard.png'], - 'jcb' => ['name' => 'JCB', 'path' => __DIR__.'/credit-cards/jcb.png'], - 'mastercard' => ['name' => 'Mastercard', 'path' => __DIR__.'/credit-cards/mastercard.png'], - 'naranja' => ['name' => 'Naranja', 'path' => __DIR__.'/credit-cards/naranja.png'], - 'targeta-shopping' => ['name' => 'Tarjeta Shopping', 'path' => __DIR__.'/credit-cards/tarjeta-shopping.png'], - 'union-china-pay' => ['name' => 'Union China Pay', 'path' => __DIR__.'/credit-cards/union-china-pay.png'], - 'visa' => ['name' => 'Visa', 'path' => __DIR__.'/credit-cards/visa.png'], - 'mir' => ['name' => 'MIR', 'path' => __DIR__.'/credit-cards/mir.png'], - 'maestro' => ['name' => 'Maestro', 'path' => __DIR__.'/credit-cards/maestro.png'], -]; + 'amex' => ['name' => 'American Express', 'path' => __DIR__ . '/credit-cards/amex.png'], + 'argencard' => ['name' => 'Argencard', 'path' => __DIR__ . '/credit-cards/argencard.png'], + 'cabal' => ['name' => 'Cabal', 'path' => __DIR__ . '/credit-cards/cabal.png'], + 'censosud' => ['name' => 'Consosud', 'path' => __DIR__ . '/credit-cards/consosud.png'], + 'diners' => ['name' => 'Diners Club', 'path' => __DIR__ . '/credit-cards/diners.png'], + 'discover' => ['name' => 'Discover', 'path' => __DIR__ . '/credit-cards/discover.png'], + 'elo' => ['name' => 'Elo', 'path' => __DIR__ . '/credit-cards/elo.png'], + 'hipercard' => ['name' => 'Hipercard', 'path' => __DIR__ . '/credit-cards/hipercard.png'], + 'jcb' => ['name' => 'JCB', 'path' => __DIR__ . '/credit-cards/jcb.png'], + 'mastercard' => ['name' => 'Mastercard', 'path' => __DIR__ . '/credit-cards/mastercard.png'], + 'naranja' => ['name' => 'Naranja', 'path' => __DIR__ . '/credit-cards/naranja.png'], + 'targeta-shopping' => ['name' => 'Tarjeta Shopping', 'path' => __DIR__ . '/credit-cards/tarjeta-shopping.png'], + 'union-china-pay' => ['name' => 'Union China Pay', 'path' => __DIR__ . '/credit-cards/union-china-pay.png'], + 'visa' => ['name' => 'Visa', 'path' => __DIR__ . '/credit-cards/visa.png'], + 'mir' => ['name' => 'MIR', 'path' => __DIR__ . '/credit-cards/mir.png'], + 'maestro' => ['name' => 'Maestro', 'path' => __DIR__ . '/credit-cards/maestro.png'] + ]; diff --git a/app/config/avatars/flags.php b/app/config/avatars/flags.php index 144a8bfd31..696656738e 100644 --- a/app/config/avatars/flags.php +++ b/app/config/avatars/flags.php @@ -1,198 +1,198 @@ ['name' => 'Afghanistan', 'path' => __DIR__.'/flags/af.png'], - 'ao' => ['name' => 'Angola', 'path' => __DIR__.'/flags/ao.png'], - 'al' => ['name' => 'Albania', 'path' => __DIR__.'/flags/al.png'], - 'ad' => ['name' => 'Andorra', 'path' => __DIR__.'/flags/ad.png'], - 'ae' => ['name' => 'United Arab Emirates', 'path' => __DIR__.'/flags/ae.png'], - 'ar' => ['name' => 'Argentina', 'path' => __DIR__.'/flags/ar.png'], - 'am' => ['name' => 'Armenia', 'path' => __DIR__.'/flags/am.png'], - 'ag' => ['name' => 'Antigua and Barbuda', 'path' => __DIR__.'/flags/ag.png'], - 'au' => ['name' => 'Australia', 'path' => __DIR__.'/flags/au.png'], - 'at' => ['name' => 'Austria', 'path' => __DIR__.'/flags/at.png'], - 'az' => ['name' => 'Azerbaijan', 'path' => __DIR__.'/flags/az.png'], - 'bi' => ['name' => 'Burundi', 'path' => __DIR__.'/flags/bi.png'], - 'be' => ['name' => 'Belgium', 'path' => __DIR__.'/flags/be.png'], - 'bj' => ['name' => 'Benin', 'path' => __DIR__.'/flags/bj.png'], - 'bf' => ['name' => 'Burkina Faso', 'path' => __DIR__.'/flags/bf.png'], - 'bd' => ['name' => 'Bangladesh', 'path' => __DIR__.'/flags/bd.png'], - 'bg' => ['name' => 'Bulgaria', 'path' => __DIR__.'/flags/bg.png'], - 'bh' => ['name' => 'Bahrain', 'path' => __DIR__.'/flags/bh.png'], - 'bs' => ['name' => 'Bahamas', 'path' => __DIR__.'/flags/bs.png'], - 'ba' => ['name' => 'Bosnia and Herzegovina', 'path' => __DIR__.'/flags/ba.png'], - 'by' => ['name' => 'Belarus', 'path' => __DIR__.'/flags/by.png'], - 'bz' => ['name' => 'Belize', 'path' => __DIR__.'/flags/bz.png'], - 'bo' => ['name' => 'Bolivia', 'path' => __DIR__.'/flags/bo.png'], - 'br' => ['name' => 'Brazil', 'path' => __DIR__.'/flags/br.png'], - 'bb' => ['name' => 'Barbados', 'path' => __DIR__.'/flags/bb.png'], - 'bn' => ['name' => 'Brunei Darussalam', 'path' => __DIR__.'/flags/bn.png'], - 'bt' => ['name' => 'Bhutan', 'path' => __DIR__.'/flags/bt.png'], - 'bw' => ['name' => 'Botswana', 'path' => __DIR__.'/flags/bw.png'], - 'cf' => ['name' => 'Central African Republic', 'path' => __DIR__.'/flags/cf.png'], - 'ca' => ['name' => 'Canada', 'path' => __DIR__.'/flags/ca.png'], - 'ch' => ['name' => 'Switzerland', 'path' => __DIR__.'/flags/ch.png'], - 'cl' => ['name' => 'Chile', 'path' => __DIR__.'/flags/cl.png'], - 'cn' => ['name' => 'China', 'path' => __DIR__.'/flags/cn.png'], - 'ci' => ['name' => 'Côte d\'Ivoire', 'path' => __DIR__.'/flags/ci.png'], - 'cm' => ['name' => 'Cameroon', 'path' => __DIR__.'/flags/cm.png'], - 'cd' => ['name' => 'Democratic Republic of the Congo', 'path' => __DIR__.'/flags/cd.png'], - 'cg' => ['name' => 'Republic of the Congo', 'path' => __DIR__.'/flags/cg.png'], - 'co' => ['name' => 'Colombia', 'path' => __DIR__.'/flags/co.png'], - 'km' => ['name' => 'Comoros', 'path' => __DIR__.'/flags/km.png'], - 'cv' => ['name' => 'Cape Verde', 'path' => __DIR__.'/flags/cv.png'], - 'cr' => ['name' => 'Costa Rica', 'path' => __DIR__.'/flags/cr.png'], - 'cu' => ['name' => 'Cuba', 'path' => __DIR__.'/flags/cu.png'], - 'cy' => ['name' => 'Cyprus', 'path' => __DIR__.'/flags/cy.png'], - 'cz' => ['name' => 'Czech Republic', 'path' => __DIR__.'/flags/cz.png'], - 'de' => ['name' => 'Germany', 'path' => __DIR__.'/flags/de.png'], - 'dj' => ['name' => 'Djibouti', 'path' => __DIR__.'/flags/dj.png'], - 'dm' => ['name' => 'Dominica', 'path' => __DIR__.'/flags/dm.png'], - 'dk' => ['name' => 'Denmark', 'path' => __DIR__.'/flags/dk.png'], - 'do' => ['name' => 'Dominican Republic', 'path' => __DIR__.'/flags/do.png'], - 'dz' => ['name' => 'Algeria', 'path' => __DIR__.'/flags/dz.png'], - 'ec' => ['name' => 'Ecuador', 'path' => __DIR__.'/flags/ec.png'], - 'eg' => ['name' => 'Egypt', 'path' => __DIR__.'/flags/eg.png'], - 'er' => ['name' => 'Eritrea', 'path' => __DIR__.'/flags/er.png'], - 'es' => ['name' => 'Spain', 'path' => __DIR__.'/flags/es.png'], - 'ee' => ['name' => 'Estonia', 'path' => __DIR__.'/flags/ee.png'], - 'et' => ['name' => 'Ethiopia', 'path' => __DIR__.'/flags/et.png'], - 'fi' => ['name' => 'Finland', 'path' => __DIR__.'/flags/fi.png'], - 'fj' => ['name' => 'Fiji', 'path' => __DIR__.'/flags/fj.png'], - 'fr' => ['name' => 'France', 'path' => __DIR__.'/flags/fr.png'], - 'fm' => ['name' => 'Micronesia (Federated States of)', 'path' => __DIR__.'/flags/fm.png'], - 'ga' => ['name' => 'Gabon', 'path' => __DIR__.'/flags/ga.png'], - 'gb' => ['name' => 'United Kingdom', 'path' => __DIR__.'/flags/gb.png'], - 'ge' => ['name' => 'Georgia', 'path' => __DIR__.'/flags/ge.png'], - 'gh' => ['name' => 'Ghana', 'path' => __DIR__.'/flags/gh.png'], - 'gn' => ['name' => 'Guinea', 'path' => __DIR__.'/flags/gn.png'], - 'gm' => ['name' => 'Gambia', 'path' => __DIR__.'/flags/gm.png'], - 'gw' => ['name' => 'Guinea-Bissau', 'path' => __DIR__.'/flags/gw.png'], - 'gq' => ['name' => 'Equatorial Guinea', 'path' => __DIR__.'/flags/gq.png'], - 'gr' => ['name' => 'Greece', 'path' => __DIR__.'/flags/gr.png'], - 'gd' => ['name' => 'Grenada', 'path' => __DIR__.'/flags/gd.png'], - 'gt' => ['name' => 'Guatemala', 'path' => __DIR__.'/flags/gt.png'], - 'gy' => ['name' => 'Guyana', 'path' => __DIR__.'/flags/gy.png'], - 'hn' => ['name' => 'Honduras', 'path' => __DIR__.'/flags/hn.png'], - 'hr' => ['name' => 'Croatia', 'path' => __DIR__.'/flags/hr.png'], - 'ht' => ['name' => 'Haiti', 'path' => __DIR__.'/flags/ht.png'], - 'hu' => ['name' => 'Hungary', 'path' => __DIR__.'/flags/hu.png'], - 'id' => ['name' => 'Indonesia', 'path' => __DIR__.'/flags/id.png'], - 'in' => ['name' => 'India', 'path' => __DIR__.'/flags/in.png'], - 'ie' => ['name' => 'Ireland', 'path' => __DIR__.'/flags/ie.png'], - 'ir' => ['name' => 'Iran (Islamic Republic of)', 'path' => __DIR__.'/flags/ir.png'], - 'iq' => ['name' => 'Iraq', 'path' => __DIR__.'/flags/iq.png'], - 'is' => ['name' => 'Iceland', 'path' => __DIR__.'/flags/is.png'], - 'il' => ['name' => 'Israel', 'path' => __DIR__.'/flags/il.png'], - 'it' => ['name' => 'Italy', 'path' => __DIR__.'/flags/it.png'], - 'jm' => ['name' => 'Jamaica', 'path' => __DIR__.'/flags/jm.png'], - 'jo' => ['name' => 'Jordan', 'path' => __DIR__.'/flags/jo.png'], - 'jp' => ['name' => 'Japan', 'path' => __DIR__.'/flags/jp.png'], - 'kz' => ['name' => 'Kazakhstan', 'path' => __DIR__.'/flags/kz.png'], - 'ke' => ['name' => 'Kenya', 'path' => __DIR__.'/flags/ke.png'], - 'kg' => ['name' => 'Kyrgyzstan', 'path' => __DIR__.'/flags/kg.png'], - 'kh' => ['name' => 'Cambodia', 'path' => __DIR__.'/flags/kh.png'], - 'ki' => ['name' => 'Kiribati', 'path' => __DIR__.'/flags/ki.png'], - 'kn' => ['name' => 'Saint Kitts and Nevis', 'path' => __DIR__.'/flags/kn.png'], - 'kr' => ['name' => 'South Korea', 'path' => __DIR__.'/flags/kr.png'], - 'kw' => ['name' => 'Kuwait', 'path' => __DIR__.'/flags/kw.png'], - 'la' => ['name' => 'Lao People\'s Democratic Republic', 'path' => __DIR__.'/flags/la.png'], - 'lb' => ['name' => 'Lebanon', 'path' => __DIR__.'/flags/lb.png'], - 'lr' => ['name' => 'Liberia', 'path' => __DIR__.'/flags/lr.png'], - 'ly' => ['name' => 'Libya', 'path' => __DIR__.'/flags/ly.png'], - 'lc' => ['name' => 'Saint Lucia', 'path' => __DIR__.'/flags/lc.png'], - 'li' => ['name' => 'Liechtenstein', 'path' => __DIR__.'/flags/li.png'], - 'lk' => ['name' => 'Sri Lanka', 'path' => __DIR__.'/flags/lk.png'], - 'ls' => ['name' => 'Lesotho', 'path' => __DIR__.'/flags/ls.png'], - 'lt' => ['name' => 'Lithuania', 'path' => __DIR__.'/flags/lt.png'], - 'lu' => ['name' => 'Luxembourg', 'path' => __DIR__.'/flags/lu.png'], - 'lv' => ['name' => 'Latvia', 'path' => __DIR__.'/flags/lv.png'], - 'ma' => ['name' => 'Morocco', 'path' => __DIR__.'/flags/ma.png'], - 'mc' => ['name' => 'Monaco', 'path' => __DIR__.'/flags/mc.png'], - 'md' => ['name' => 'Moldova', 'path' => __DIR__.'/flags/md.png'], - 'mg' => ['name' => 'Madagascar', 'path' => __DIR__.'/flags/mg.png'], - 'mv' => ['name' => 'Maldives', 'path' => __DIR__.'/flags/mv.png'], - 'mx' => ['name' => 'Mexico', 'path' => __DIR__.'/flags/mx.png'], - 'mh' => ['name' => 'Marshall Islands', 'path' => __DIR__.'/flags/mh.png'], - 'mk' => ['name' => 'North Macedonia', 'path' => __DIR__.'/flags/mk.png'], - 'ml' => ['name' => 'Mali', 'path' => __DIR__.'/flags/ml.png'], - 'mt' => ['name' => 'Malta', 'path' => __DIR__.'/flags/mt.png'], - 'mm' => ['name' => 'Myanmar', 'path' => __DIR__.'/flags/mm.png'], - 'me' => ['name' => 'Montenegro', 'path' => __DIR__.'/flags/me.png'], - 'mn' => ['name' => 'Mongolia', 'path' => __DIR__.'/flags/mn.png'], - 'mz' => ['name' => 'Mozambique', 'path' => __DIR__.'/flags/mz.png'], - 'mr' => ['name' => 'Mauritania', 'path' => __DIR__.'/flags/mr.png'], - 'mu' => ['name' => 'Mauritius', 'path' => __DIR__.'/flags/mu.png'], - 'mw' => ['name' => 'Malawi', 'path' => __DIR__.'/flags/mw.png'], - 'my' => ['name' => 'Malaysia', 'path' => __DIR__.'/flags/my.png'], - 'na' => ['name' => 'Namibia', 'path' => __DIR__.'/flags/na.png'], - 'ne' => ['name' => 'Niger', 'path' => __DIR__.'/flags/ne.png'], - 'ng' => ['name' => 'Nigeria', 'path' => __DIR__.'/flags/ng.png'], - 'ni' => ['name' => 'Nicaragua', 'path' => __DIR__.'/flags/ni.png'], - 'nl' => ['name' => 'Netherlands', 'path' => __DIR__.'/flags/nl.png'], - 'no' => ['name' => 'Norway', 'path' => __DIR__.'/flags/no.png'], - 'np' => ['name' => 'Nepal', 'path' => __DIR__.'/flags/np.png'], - 'nr' => ['name' => 'Nauru', 'path' => __DIR__.'/flags/nr.png'], - 'nz' => ['name' => 'New Zealand', 'path' => __DIR__.'/flags/nz.png'], - 'om' => ['name' => 'Oman', 'path' => __DIR__.'/flags/om.png'], - 'pk' => ['name' => 'Pakistan', 'path' => __DIR__.'/flags/pk.png'], - 'pa' => ['name' => 'Panama', 'path' => __DIR__.'/flags/pa.png'], - 'pe' => ['name' => 'Peru', 'path' => __DIR__.'/flags/pe.png'], - 'ph' => ['name' => 'Philippines', 'path' => __DIR__.'/flags/ph.png'], - 'pw' => ['name' => 'Palau', 'path' => __DIR__.'/flags/pw.png'], - 'pg' => ['name' => 'Papua New Guinea', 'path' => __DIR__.'/flags/pg.png'], - 'pl' => ['name' => 'Poland', 'path' => __DIR__.'/flags/pl.png'], - 'kp' => ['name' => 'North Korea', 'path' => __DIR__.'/flags/kp.png'], - 'pt' => ['name' => 'Portugal', 'path' => __DIR__.'/flags/pt.png'], - 'py' => ['name' => 'Paraguay', 'path' => __DIR__.'/flags/py.png'], - 'qa' => ['name' => 'Qatar', 'path' => __DIR__.'/flags/qa.png'], - 'ro' => ['name' => 'Romania', 'path' => __DIR__.'/flags/ro.png'], - 'ru' => ['name' => 'Russia', 'path' => __DIR__.'/flags/ru.png'], - 'rw' => ['name' => 'Rwanda', 'path' => __DIR__.'/flags/rw.png'], - 'sa' => ['name' => 'Saudi Arabia', 'path' => __DIR__.'/flags/sa.png'], - 'sd' => ['name' => 'Sudan', 'path' => __DIR__.'/flags/sd.png'], - 'sn' => ['name' => 'Senegal', 'path' => __DIR__.'/flags/sn.png'], - 'sg' => ['name' => 'Singapore', 'path' => __DIR__.'/flags/sg.png'], - 'sb' => ['name' => 'Solomon Islands', 'path' => __DIR__.'/flags/sb.png'], - 'sl' => ['name' => 'Sierra Leone', 'path' => __DIR__.'/flags/sl.png'], - 'sv' => ['name' => 'El Salvador', 'path' => __DIR__.'/flags/sv.png'], - 'sm' => ['name' => 'San Marino', 'path' => __DIR__.'/flags/sm.png'], - 'so' => ['name' => 'Somalia', 'path' => __DIR__.'/flags/so.png'], - 'rs' => ['name' => 'Serbia', 'path' => __DIR__.'/flags/rs.png'], - 'ss' => ['name' => 'South Sudan', 'path' => __DIR__.'/flags/ss.png'], - 'st' => ['name' => 'Sao Tome and Principe', 'path' => __DIR__.'/flags/st.png'], - 'sr' => ['name' => 'Suriname', 'path' => __DIR__.'/flags/sr.png'], - 'sk' => ['name' => 'Slovakia', 'path' => __DIR__.'/flags/sk.png'], - 'si' => ['name' => 'Slovenia', 'path' => __DIR__.'/flags/si.png'], - 'se' => ['name' => 'Sweden', 'path' => __DIR__.'/flags/se.png'], - 'sz' => ['name' => 'Eswatini', 'path' => __DIR__.'/flags/sz.png'], - 'sc' => ['name' => 'Seychelles', 'path' => __DIR__.'/flags/sc.png'], - 'sy' => ['name' => 'Syria', 'path' => __DIR__.'/flags/sy.png'], - 'td' => ['name' => 'Chad', 'path' => __DIR__.'/flags/td.png'], - 'tg' => ['name' => 'Togo', 'path' => __DIR__.'/flags/tg.png'], - 'th' => ['name' => 'Thailand', 'path' => __DIR__.'/flags/th.png'], - 'tj' => ['name' => 'Tajikistan', 'path' => __DIR__.'/flags/tj.png'], - 'tm' => ['name' => 'Turkmenistan', 'path' => __DIR__.'/flags/tm.png'], - 'tl' => ['name' => 'Timor-Leste', 'path' => __DIR__.'/flags/tl.png'], - 'to' => ['name' => 'Tonga', 'path' => __DIR__.'/flags/to.png'], - 'tt' => ['name' => 'Trinidad and Tobago', 'path' => __DIR__.'/flags/tt.png'], - 'tn' => ['name' => 'Tunisia', 'path' => __DIR__.'/flags/tn.png'], - 'tr' => ['name' => 'Turkey', 'path' => __DIR__.'/flags/tr.png'], - 'tv' => ['name' => 'Tuvalu', 'path' => __DIR__.'/flags/tv.png'], - 'tz' => ['name' => 'Tanzania', 'path' => __DIR__.'/flags/tz.png'], - 'ug' => ['name' => 'Uganda', 'path' => __DIR__.'/flags/ug.png'], - 'ua' => ['name' => 'Ukraine', 'path' => __DIR__.'/flags/ua.png'], - 'uy' => ['name' => 'Uruguay', 'path' => __DIR__.'/flags/uy.png'], - 'us' => ['name' => 'United States', 'path' => __DIR__.'/flags/us.png'], - 'uz' => ['name' => 'Uzbekistan', 'path' => __DIR__.'/flags/uz.png'], - 'va' => ['name' => 'Vatican City', 'path' => __DIR__.'/flags/va.png'], - 'vc' => ['name' => 'Saint Vincent and the Grenadines', 'path' => __DIR__.'/flags/vc.png'], - 've' => ['name' => 'Venezuela', 'path' => __DIR__.'/flags/ve.png'], - 'vn' => ['name' => 'Vietnam', 'path' => __DIR__.'/flags/vn.png'], - 'vu' => ['name' => 'Vanuatu', 'path' => __DIR__.'/flags/vu.png'], - 'ws' => ['name' => 'Samoa', 'path' => __DIR__.'/flags/ws.png'], - 'ye' => ['name' => 'Yemen', 'path' => __DIR__.'/flags/ye.png'], - 'za' => ['name' => 'South Africa', 'path' => __DIR__.'/flags/za.png'], - 'zm' => ['name' => 'Zambia', 'path' => __DIR__.'/flags/zm.png'], - 'zw' => ['name' => 'Zimbabwe', 'path' => __DIR__.'/flags/zw.png'], + 'af' => ['name' => 'Afghanistan', 'path' => __DIR__ . '/flags/af.png'], + 'ao' => ['name' => 'Angola', 'path' => __DIR__ . '/flags/ao.png'], + 'al' => ['name' => 'Albania', 'path' => __DIR__ . '/flags/al.png'], + 'ad' => ['name' => 'Andorra', 'path' => __DIR__ . '/flags/ad.png'], + 'ae' => ['name' => 'United Arab Emirates', 'path' => __DIR__ . '/flags/ae.png'], + 'ar' => ['name' => 'Argentina', 'path' => __DIR__ . '/flags/ar.png'], + 'am' => ['name' => 'Armenia', 'path' => __DIR__ . '/flags/am.png'], + 'ag' => ['name' => 'Antigua and Barbuda', 'path' => __DIR__ . '/flags/ag.png'], + 'au' => ['name' => 'Australia', 'path' => __DIR__ . '/flags/au.png'], + 'at' => ['name' => 'Austria', 'path' => __DIR__ . '/flags/at.png'], + 'az' => ['name' => 'Azerbaijan', 'path' => __DIR__ . '/flags/az.png'], + 'bi' => ['name' => 'Burundi', 'path' => __DIR__ . '/flags/bi.png'], + 'be' => ['name' => 'Belgium', 'path' => __DIR__ . '/flags/be.png'], + 'bj' => ['name' => 'Benin', 'path' => __DIR__ . '/flags/bj.png'], + 'bf' => ['name' => 'Burkina Faso', 'path' => __DIR__ . '/flags/bf.png'], + 'bd' => ['name' => 'Bangladesh', 'path' => __DIR__ . '/flags/bd.png'], + 'bg' => ['name' => 'Bulgaria', 'path' => __DIR__ . '/flags/bg.png'], + 'bh' => ['name' => 'Bahrain', 'path' => __DIR__ . '/flags/bh.png'], + 'bs' => ['name' => 'Bahamas', 'path' => __DIR__ . '/flags/bs.png'], + 'ba' => ['name' => 'Bosnia and Herzegovina', 'path' => __DIR__ . '/flags/ba.png'], + 'by' => ['name' => 'Belarus', 'path' => __DIR__ . '/flags/by.png'], + 'bz' => ['name' => 'Belize', 'path' => __DIR__ . '/flags/bz.png'], + 'bo' => ['name' => 'Bolivia', 'path' => __DIR__ . '/flags/bo.png'], + 'br' => ['name' => 'Brazil', 'path' => __DIR__ . '/flags/br.png'], + 'bb' => ['name' => 'Barbados', 'path' => __DIR__ . '/flags/bb.png'], + 'bn' => ['name' => 'Brunei Darussalam', 'path' => __DIR__ . '/flags/bn.png'], + 'bt' => ['name' => 'Bhutan', 'path' => __DIR__ . '/flags/bt.png'], + 'bw' => ['name' => 'Botswana', 'path' => __DIR__ . '/flags/bw.png'], + 'cf' => ['name' => 'Central African Republic', 'path' => __DIR__ . '/flags/cf.png'], + 'ca' => ['name' => 'Canada', 'path' => __DIR__ . '/flags/ca.png'], + 'ch' => ['name' => 'Switzerland', 'path' => __DIR__ . '/flags/ch.png'], + 'cl' => ['name' => 'Chile', 'path' => __DIR__ . '/flags/cl.png'], + 'cn' => ['name' => 'China', 'path' => __DIR__ . '/flags/cn.png'], + 'ci' => ['name' => 'Côte d\'Ivoire', 'path' => __DIR__ . '/flags/ci.png'], + 'cm' => ['name' => 'Cameroon', 'path' => __DIR__ . '/flags/cm.png'], + 'cd' => ['name' => 'Democratic Republic of the Congo', 'path' => __DIR__ . '/flags/cd.png'], + 'cg' => ['name' => 'Republic of the Congo', 'path' => __DIR__ . '/flags/cg.png'], + 'co' => ['name' => 'Colombia', 'path' => __DIR__ . '/flags/co.png'], + 'km' => ['name' => 'Comoros', 'path' => __DIR__ . '/flags/km.png'], + 'cv' => ['name' => 'Cape Verde', 'path' => __DIR__ . '/flags/cv.png'], + 'cr' => ['name' => 'Costa Rica', 'path' => __DIR__ . '/flags/cr.png'], + 'cu' => ['name' => 'Cuba', 'path' => __DIR__ . '/flags/cu.png'], + 'cy' => ['name' => 'Cyprus', 'path' => __DIR__ . '/flags/cy.png'], + 'cz' => ['name' => 'Czech Republic', 'path' => __DIR__ . '/flags/cz.png'], + 'de' => ['name' => 'Germany', 'path' => __DIR__ . '/flags/de.png'], + 'dj' => ['name' => 'Djibouti', 'path' => __DIR__ . '/flags/dj.png'], + 'dm' => ['name' => 'Dominica', 'path' => __DIR__ . '/flags/dm.png'], + 'dk' => ['name' => 'Denmark', 'path' => __DIR__ . '/flags/dk.png'], + 'do' => ['name' => 'Dominican Republic', 'path' => __DIR__ . '/flags/do.png'], + 'dz' => ['name' => 'Algeria', 'path' => __DIR__ . '/flags/dz.png'], + 'ec' => ['name' => 'Ecuador', 'path' => __DIR__ . '/flags/ec.png'], + 'eg' => ['name' => 'Egypt', 'path' => __DIR__ . '/flags/eg.png'], + 'er' => ['name' => 'Eritrea', 'path' => __DIR__ . '/flags/er.png'], + 'es' => ['name' => 'Spain', 'path' => __DIR__ . '/flags/es.png'], + 'ee' => ['name' => 'Estonia', 'path' => __DIR__ . '/flags/ee.png'], + 'et' => ['name' => 'Ethiopia', 'path' => __DIR__ . '/flags/et.png'], + 'fi' => ['name' => 'Finland', 'path' => __DIR__ . '/flags/fi.png'], + 'fj' => ['name' => 'Fiji', 'path' => __DIR__ . '/flags/fj.png'], + 'fr' => ['name' => 'France', 'path' => __DIR__ . '/flags/fr.png'], + 'fm' => ['name' => 'Micronesia (Federated States of)', 'path' => __DIR__ . '/flags/fm.png'], + 'ga' => ['name' => 'Gabon', 'path' => __DIR__ . '/flags/ga.png'], + 'gb' => ['name' => 'United Kingdom', 'path' => __DIR__ . '/flags/gb.png'], + 'ge' => ['name' => 'Georgia', 'path' => __DIR__ . '/flags/ge.png'], + 'gh' => ['name' => 'Ghana', 'path' => __DIR__ . '/flags/gh.png'], + 'gn' => ['name' => 'Guinea', 'path' => __DIR__ . '/flags/gn.png'], + 'gm' => ['name' => 'Gambia', 'path' => __DIR__ . '/flags/gm.png'], + 'gw' => ['name' => 'Guinea-Bissau', 'path' => __DIR__ . '/flags/gw.png'], + 'gq' => ['name' => 'Equatorial Guinea', 'path' => __DIR__ . '/flags/gq.png'], + 'gr' => ['name' => 'Greece', 'path' => __DIR__ . '/flags/gr.png'], + 'gd' => ['name' => 'Grenada', 'path' => __DIR__ . '/flags/gd.png'], + 'gt' => ['name' => 'Guatemala', 'path' => __DIR__ . '/flags/gt.png'], + 'gy' => ['name' => 'Guyana', 'path' => __DIR__ . '/flags/gy.png'], + 'hn' => ['name' => 'Honduras', 'path' => __DIR__ . '/flags/hn.png'], + 'hr' => ['name' => 'Croatia', 'path' => __DIR__ . '/flags/hr.png'], + 'ht' => ['name' => 'Haiti', 'path' => __DIR__ . '/flags/ht.png'], + 'hu' => ['name' => 'Hungary', 'path' => __DIR__ . '/flags/hu.png'], + 'id' => ['name' => 'Indonesia', 'path' => __DIR__ . '/flags/id.png'], + 'in' => ['name' => 'India', 'path' => __DIR__ . '/flags/in.png'], + 'ie' => ['name' => 'Ireland', 'path' => __DIR__ . '/flags/ie.png'], + 'ir' => ['name' => 'Iran (Islamic Republic of)', 'path' => __DIR__ . '/flags/ir.png'], + 'iq' => ['name' => 'Iraq', 'path' => __DIR__ . '/flags/iq.png'], + 'is' => ['name' => 'Iceland', 'path' => __DIR__ . '/flags/is.png'], + 'il' => ['name' => 'Israel', 'path' => __DIR__ . '/flags/il.png'], + 'it' => ['name' => 'Italy', 'path' => __DIR__ . '/flags/it.png'], + 'jm' => ['name' => 'Jamaica', 'path' => __DIR__ . '/flags/jm.png'], + 'jo' => ['name' => 'Jordan', 'path' => __DIR__ . '/flags/jo.png'], + 'jp' => ['name' => 'Japan', 'path' => __DIR__ . '/flags/jp.png'], + 'kz' => ['name' => 'Kazakhstan', 'path' => __DIR__ . '/flags/kz.png'], + 'ke' => ['name' => 'Kenya', 'path' => __DIR__ . '/flags/ke.png'], + 'kg' => ['name' => 'Kyrgyzstan', 'path' => __DIR__ . '/flags/kg.png'], + 'kh' => ['name' => 'Cambodia', 'path' => __DIR__ . '/flags/kh.png'], + 'ki' => ['name' => 'Kiribati', 'path' => __DIR__ . '/flags/ki.png'], + 'kn' => ['name' => 'Saint Kitts and Nevis', 'path' => __DIR__ . '/flags/kn.png'], + 'kr' => ['name' => 'South Korea', 'path' => __DIR__ . '/flags/kr.png'], + 'kw' => ['name' => 'Kuwait', 'path' => __DIR__ . '/flags/kw.png'], + 'la' => ['name' => 'Lao People\'s Democratic Republic', 'path' => __DIR__ . '/flags/la.png'], + 'lb' => ['name' => 'Lebanon', 'path' => __DIR__ . '/flags/lb.png'], + 'lr' => ['name' => 'Liberia', 'path' => __DIR__ . '/flags/lr.png'], + 'ly' => ['name' => 'Libya', 'path' => __DIR__ . '/flags/ly.png'], + 'lc' => ['name' => 'Saint Lucia', 'path' => __DIR__ . '/flags/lc.png'], + 'li' => ['name' => 'Liechtenstein', 'path' => __DIR__ . '/flags/li.png'], + 'lk' => ['name' => 'Sri Lanka', 'path' => __DIR__ . '/flags/lk.png'], + 'ls' => ['name' => 'Lesotho', 'path' => __DIR__ . '/flags/ls.png'], + 'lt' => ['name' => 'Lithuania', 'path' => __DIR__ . '/flags/lt.png'], + 'lu' => ['name' => 'Luxembourg', 'path' => __DIR__ . '/flags/lu.png'], + 'lv' => ['name' => 'Latvia', 'path' => __DIR__ . '/flags/lv.png'], + 'ma' => ['name' => 'Morocco', 'path' => __DIR__ . '/flags/ma.png'], + 'mc' => ['name' => 'Monaco', 'path' => __DIR__ . '/flags/mc.png'], + 'md' => ['name' => 'Moldova', 'path' => __DIR__ . '/flags/md.png'], + 'mg' => ['name' => 'Madagascar', 'path' => __DIR__ . '/flags/mg.png'], + 'mv' => ['name' => 'Maldives', 'path' => __DIR__ . '/flags/mv.png'], + 'mx' => ['name' => 'Mexico', 'path' => __DIR__ . '/flags/mx.png'], + 'mh' => ['name' => 'Marshall Islands', 'path' => __DIR__ . '/flags/mh.png'], + 'mk' => ['name' => 'North Macedonia', 'path' => __DIR__ . '/flags/mk.png'], + 'ml' => ['name' => 'Mali', 'path' => __DIR__ . '/flags/ml.png'], + 'mt' => ['name' => 'Malta', 'path' => __DIR__ . '/flags/mt.png'], + 'mm' => ['name' => 'Myanmar', 'path' => __DIR__ . '/flags/mm.png'], + 'me' => ['name' => 'Montenegro', 'path' => __DIR__ . '/flags/me.png'], + 'mn' => ['name' => 'Mongolia', 'path' => __DIR__ . '/flags/mn.png'], + 'mz' => ['name' => 'Mozambique', 'path' => __DIR__ . '/flags/mz.png'], + 'mr' => ['name' => 'Mauritania', 'path' => __DIR__ . '/flags/mr.png'], + 'mu' => ['name' => 'Mauritius', 'path' => __DIR__ . '/flags/mu.png'], + 'mw' => ['name' => 'Malawi', 'path' => __DIR__ . '/flags/mw.png'], + 'my' => ['name' => 'Malaysia', 'path' => __DIR__ . '/flags/my.png'], + 'na' => ['name' => 'Namibia', 'path' => __DIR__ . '/flags/na.png'], + 'ne' => ['name' => 'Niger', 'path' => __DIR__ . '/flags/ne.png'], + 'ng' => ['name' => 'Nigeria', 'path' => __DIR__ . '/flags/ng.png'], + 'ni' => ['name' => 'Nicaragua', 'path' => __DIR__ . '/flags/ni.png'], + 'nl' => ['name' => 'Netherlands', 'path' => __DIR__ . '/flags/nl.png'], + 'no' => ['name' => 'Norway', 'path' => __DIR__ . '/flags/no.png'], + 'np' => ['name' => 'Nepal', 'path' => __DIR__ . '/flags/np.png'], + 'nr' => ['name' => 'Nauru', 'path' => __DIR__ . '/flags/nr.png'], + 'nz' => ['name' => 'New Zealand', 'path' => __DIR__ . '/flags/nz.png'], + 'om' => ['name' => 'Oman', 'path' => __DIR__ . '/flags/om.png'], + 'pk' => ['name' => 'Pakistan', 'path' => __DIR__ . '/flags/pk.png'], + 'pa' => ['name' => 'Panama', 'path' => __DIR__ . '/flags/pa.png'], + 'pe' => ['name' => 'Peru', 'path' => __DIR__ . '/flags/pe.png'], + 'ph' => ['name' => 'Philippines', 'path' => __DIR__ . '/flags/ph.png'], + 'pw' => ['name' => 'Palau', 'path' => __DIR__ . '/flags/pw.png'], + 'pg' => ['name' => 'Papua New Guinea', 'path' => __DIR__ . '/flags/pg.png'], + 'pl' => ['name' => 'Poland', 'path' => __DIR__ . '/flags/pl.png'], + 'kp' => ['name' => 'North Korea', 'path' => __DIR__ . '/flags/kp.png'], + 'pt' => ['name' => 'Portugal', 'path' => __DIR__ . '/flags/pt.png'], + 'py' => ['name' => 'Paraguay', 'path' => __DIR__ . '/flags/py.png'], + 'qa' => ['name' => 'Qatar', 'path' => __DIR__ . '/flags/qa.png'], + 'ro' => ['name' => 'Romania', 'path' => __DIR__ . '/flags/ro.png'], + 'ru' => ['name' => 'Russia', 'path' => __DIR__ . '/flags/ru.png'], + 'rw' => ['name' => 'Rwanda', 'path' => __DIR__ . '/flags/rw.png'], + 'sa' => ['name' => 'Saudi Arabia', 'path' => __DIR__ . '/flags/sa.png'], + 'sd' => ['name' => 'Sudan', 'path' => __DIR__ . '/flags/sd.png'], + 'sn' => ['name' => 'Senegal', 'path' => __DIR__ . '/flags/sn.png'], + 'sg' => ['name' => 'Singapore', 'path' => __DIR__ . '/flags/sg.png'], + 'sb' => ['name' => 'Solomon Islands', 'path' => __DIR__ . '/flags/sb.png'], + 'sl' => ['name' => 'Sierra Leone', 'path' => __DIR__ . '/flags/sl.png'], + 'sv' => ['name' => 'El Salvador', 'path' => __DIR__ . '/flags/sv.png'], + 'sm' => ['name' => 'San Marino', 'path' => __DIR__ . '/flags/sm.png'], + 'so' => ['name' => 'Somalia', 'path' => __DIR__ . '/flags/so.png'], + 'rs' => ['name' => 'Serbia', 'path' => __DIR__ . '/flags/rs.png'], + 'ss' => ['name' => 'South Sudan', 'path' => __DIR__ . '/flags/ss.png'], + 'st' => ['name' => 'Sao Tome and Principe', 'path' => __DIR__ . '/flags/st.png'], + 'sr' => ['name' => 'Suriname', 'path' => __DIR__ . '/flags/sr.png'], + 'sk' => ['name' => 'Slovakia', 'path' => __DIR__ . '/flags/sk.png'], + 'si' => ['name' => 'Slovenia', 'path' => __DIR__ . '/flags/si.png'], + 'se' => ['name' => 'Sweden', 'path' => __DIR__ . '/flags/se.png'], + 'sz' => ['name' => 'Eswatini', 'path' => __DIR__ . '/flags/sz.png'], + 'sc' => ['name' => 'Seychelles', 'path' => __DIR__ . '/flags/sc.png'], + 'sy' => ['name' => 'Syria', 'path' => __DIR__ . '/flags/sy.png'], + 'td' => ['name' => 'Chad', 'path' => __DIR__ . '/flags/td.png'], + 'tg' => ['name' => 'Togo', 'path' => __DIR__ . '/flags/tg.png'], + 'th' => ['name' => 'Thailand', 'path' => __DIR__ . '/flags/th.png'], + 'tj' => ['name' => 'Tajikistan', 'path' => __DIR__ . '/flags/tj.png'], + 'tm' => ['name' => 'Turkmenistan', 'path' => __DIR__ . '/flags/tm.png'], + 'tl' => ['name' => 'Timor-Leste', 'path' => __DIR__ . '/flags/tl.png'], + 'to' => ['name' => 'Tonga', 'path' => __DIR__ . '/flags/to.png'], + 'tt' => ['name' => 'Trinidad and Tobago', 'path' => __DIR__ . '/flags/tt.png'], + 'tn' => ['name' => 'Tunisia', 'path' => __DIR__ . '/flags/tn.png'], + 'tr' => ['name' => 'Turkey', 'path' => __DIR__ . '/flags/tr.png'], + 'tv' => ['name' => 'Tuvalu', 'path' => __DIR__ . '/flags/tv.png'], + 'tz' => ['name' => 'Tanzania', 'path' => __DIR__ . '/flags/tz.png'], + 'ug' => ['name' => 'Uganda', 'path' => __DIR__ . '/flags/ug.png'], + 'ua' => ['name' => 'Ukraine', 'path' => __DIR__ . '/flags/ua.png'], + 'uy' => ['name' => 'Uruguay', 'path' => __DIR__ . '/flags/uy.png'], + 'us' => ['name' => 'United States', 'path' => __DIR__ . '/flags/us.png'], + 'uz' => ['name' => 'Uzbekistan', 'path' => __DIR__ . '/flags/uz.png'], + 'va' => ['name' => 'Vatican City', 'path' => __DIR__ . '/flags/va.png'], + 'vc' => ['name' => 'Saint Vincent and the Grenadines', 'path' => __DIR__ . '/flags/vc.png'], + 've' => ['name' => 'Venezuela', 'path' => __DIR__ . '/flags/ve.png'], + 'vn' => ['name' => 'Vietnam', 'path' => __DIR__ . '/flags/vn.png'], + 'vu' => ['name' => 'Vanuatu', 'path' => __DIR__ . '/flags/vu.png'], + 'ws' => ['name' => 'Samoa', 'path' => __DIR__ . '/flags/ws.png'], + 'ye' => ['name' => 'Yemen', 'path' => __DIR__ . '/flags/ye.png'], + 'za' => ['name' => 'South Africa', 'path' => __DIR__ . '/flags/za.png'], + 'zm' => ['name' => 'Zambia', 'path' => __DIR__ . '/flags/zm.png'], + 'zw' => ['name' => 'Zimbabwe', 'path' => __DIR__ . '/flags/zw.png'], ]; diff --git a/app/config/avatars/os.php b/app/config/avatars/os.php index ba5ee0e1fc..f500eed759 100644 --- a/app/config/avatars/os.php +++ b/app/config/avatars/os.php @@ -2,9 +2,9 @@ return [ // Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php - 'AND' => __DIR__.'/os/android.png', - 'ATV' => __DIR__.'/os/apple-tv.png', - 'COS' => __DIR__.'/os/chrome-os.png', + 'AND' => __DIR__ . '/os/android.png', + 'ATV' => __DIR__ . '/os/apple-tv.png', + 'COS' => __DIR__ . '/os/chrome-os.png', /* 'AIX' => 'AIX', diff --git a/app/config/collections.php b/app/config/collections.php index af68b4174e..c9005f8217 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -16,6 +16,7 @@ $auth = Config::getParam('auth', []); * attributes => list of attributes * indexes => list of indexes */ + $commonCollections = [ 'users' => [ '$collection' => ID::custom(Database::METADATA), @@ -252,7 +253,7 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => ['datetime'], - ], + ] ], 'indexes' => [ [ @@ -409,7 +410,7 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => [], - ], + ] ], 'indexes' => [ [ @@ -1277,7 +1278,7 @@ $commonCollections = [ 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], - ], + ] ], 'stats' => [ @@ -1453,7 +1454,7 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => ['json', 'encrypt'], - ], + ] ], 'indexes' => [ [ @@ -1469,7 +1470,7 @@ $commonCollections = [ 'attributes' => ['name'], 'lengths' => [128], 'orders' => [Database::ORDER_ASC], - ], + ] ], ], @@ -1810,7 +1811,7 @@ $commonCollections = [ 'attributes' => ['topicInternalId'], 'lengths' => [], 'orders' => [], - ], + ] ], ], @@ -1923,7 +1924,7 @@ $commonCollections = [ 'orders' => [], ], ], - ], + ] ]; $projectCollections = array_merge([ @@ -2666,7 +2667,7 @@ $projectCollections = array_merge([ 'default' => false, 'array' => false, 'filters' => [], - ], + ] ], 'indexes' => [ [ @@ -2857,7 +2858,7 @@ $projectCollections = array_merge([ 'default' => '', 'array' => false, 'filters' => [], - ], + ] ], 'indexes' => [ [ @@ -2866,7 +2867,7 @@ $projectCollections = array_merge([ 'attributes' => ['deploymentId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], - ], + ] ], ], @@ -3101,7 +3102,7 @@ $projectCollections = array_merge([ 'required' => true, 'default' => null, 'array' => false, - 'filters' => ['encrypt'], + 'filters' => [ 'encrypt' ] ], [ '$id' => ID::custom('search'), @@ -3185,7 +3186,7 @@ $projectCollections = array_merge([ 'array' => false, 'filters' => [], ], - ], + ], 'indexes' => [ [ '$id' => '_key_accessedAt', @@ -3307,7 +3308,7 @@ $projectCollections = array_merge([ 'default' => null, 'array' => false, 'filters' => [], - ], + ] ], 'indexes' => [ [ @@ -3337,7 +3338,7 @@ $projectCollections = array_merge([ 'attributes' => ['search'], 'lengths' => [], 'orders' => [], - ], + ] ], ], ], $commonCollections); @@ -3747,7 +3748,7 @@ $consoleCollections = array_merge([ [ '$id' => ID::custom('_key_region_resourceType_resourceUpdatedAt'), 'type' => Database::INDEX_KEY, - 'attributes' => ['region', 'resourceType', 'resourceUpdatedAt'], + 'attributes' => ['region', 'resourceType','resourceUpdatedAt'], 'lengths' => [], 'orders' => [], ], @@ -3842,7 +3843,7 @@ $consoleCollections = array_merge([ 'default' => null, 'array' => false, 'filters' => [], - ], + ] ], 'indexes' => [ [ @@ -4184,7 +4185,7 @@ $consoleCollections = array_merge([ 'attributes' => ['projectInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], - ], + ] ], ], @@ -4311,7 +4312,7 @@ $consoleCollections = array_merge([ 'default' => null, 'array' => false, 'filters' => [], //TODO: use json filter - ], + ] ], 'indexes' => [ [ @@ -4321,7 +4322,7 @@ $consoleCollections = array_merge([ 'lengths' => [], 'orders' => [Database::ORDER_DESC], ], - ], + ] ], ], $commonCollections); @@ -4587,7 +4588,7 @@ $bucketCollections = [ 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], - ], + ] ], ]; @@ -4710,14 +4711,15 @@ $dbCollections = [ 'orders' => [Database::ORDER_ASC], ], ], - ], + ] ]; + $collections = [ 'projects' => $projectCollections, - 'console' => $consoleCollections, + 'console' => $consoleCollections, 'buckets' => $bucketCollections, - 'databases' => $dbCollections, + 'databases' => $dbCollections ]; return $collections; diff --git a/app/config/errors.php b/app/config/errors.php index 8b11410996..5942c6027c 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -299,7 +299,7 @@ return [ Exception::AVATAR_SET_NOT_FOUND => [ 'name' => Exception::AVATAR_SET_NOT_FOUND, 'description' => 'The requested avatar set could not be found.', - 'code' => 404, + 'code' => 404 ], Exception::AVATAR_NOT_FOUND => [ 'name' => Exception::AVATAR_NOT_FOUND, @@ -426,13 +426,13 @@ return [ Exception::DATABASE_NOT_FOUND => [ 'name' => Exception::DATABASE_NOT_FOUND, 'description' => 'Database not found', - 'code' => 404, + 'code' => 404 ], Exception::DATABASE_ALREADY_EXISTS => [ 'name' => Exception::DATABASE_ALREADY_EXISTS, 'description' => 'Database already exists', - 'code' => 409, + 'code' => 409 ], /** Collections */ @@ -702,5 +702,5 @@ return [ 'name' => Exception::PROVIDER_INCORRECT_TYPE, 'description' => 'Provider with the request ID is of incorrect type: ', 'code' => 400, - ], + ] ]; diff --git a/app/config/events.php b/app/config/events.php index 4ecc651240..45bb45fbf8 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -19,7 +19,7 @@ return [ '$description' => 'This event triggers when a session for a user is created.', ], 'delete' => [ - '$description' => 'This event triggers when a session for a user is deleted.', + '$description' => 'This event triggers when a session for a user is deleted.' ], ], 'recovery' => [ @@ -30,7 +30,7 @@ return [ '$description' => 'This event triggers when a recovery token for a user is created.', ], 'update' => [ - '$description' => 'This event triggers when a recovery token for a user is validated.', + '$description' => 'This event triggers when a recovery token for a user is validated.' ], ], 'verification' => [ @@ -41,7 +41,7 @@ return [ '$description' => 'This event triggers when a verification token for a user is created.', ], 'update' => [ - '$description' => 'This event triggers when a verification token for a user is validated.', + '$description' => 'This event triggers when a verification token for a user is validated.' ], ], 'targets' => [ @@ -59,7 +59,7 @@ return [ ], ], 'create' => [ - '$description' => 'This event triggers when a user is created.', + '$description' => 'This event triggers when a user is created.' ], 'delete' => [ '$description' => 'This event triggers when a user is deleted.', @@ -81,7 +81,7 @@ return [ 'prefs' => [ '$description' => 'This event triggers when a user\'s preferences is updated.', ], - ], + ] ], 'databases' => [ '$model' => Response::MODEL_DATABASE, @@ -99,10 +99,10 @@ return [ '$description' => 'This event triggers when a document is created.', ], 'delete' => [ - '$description' => 'This event triggers when a document is deleted.', + '$description' => 'This event triggers when a document is deleted.' ], 'update' => [ - '$description' => 'This event triggers when a document is updated.', + '$description' => 'This event triggers when a document is updated.' ], ], 'indexes' => [ @@ -113,8 +113,8 @@ return [ '$description' => 'This event triggers when an index is created.', ], 'delete' => [ - '$description' => 'This event triggers when an index is deleted.', - ], + '$description' => 'This event triggers when an index is deleted.' + ] ], 'attributes' => [ '$model' => Response::MODEL_ATTRIBUTE, @@ -124,28 +124,28 @@ return [ '$description' => 'This event triggers when an attribute is created.', ], 'delete' => [ - '$description' => 'This event triggers when an attribute is deleted.', - ], + '$description' => 'This event triggers when an attribute is deleted.' + ] ], 'create' => [ - '$description' => 'This event triggers when a collection is created.', + '$description' => 'This event triggers when a collection is created.' ], 'delete' => [ '$description' => 'This event triggers when a collection is deleted.', ], 'update' => [ '$description' => 'This event triggers when a collection is updated.', - ], + ] ], 'create' => [ - '$description' => 'This event triggers when a database is created.', + '$description' => 'This event triggers when a database is created.' ], 'delete' => [ '$description' => 'This event triggers when a database is deleted.', ], 'update' => [ '$description' => 'This event triggers when a database is updated.', - ], + ] ], 'buckets' => [ '$model' => Response::MODEL_BUCKET, @@ -159,21 +159,21 @@ return [ '$description' => 'This event triggers when a file is created.', ], 'delete' => [ - '$description' => 'This event triggers when a file is deleted.', + '$description' => 'This event triggers when a file is deleted.' ], 'update' => [ - '$description' => 'This event triggers when a file is updated.', + '$description' => 'This event triggers when a file is updated.' ], ], 'create' => [ - '$description' => 'This event triggers when a bucket is created.', + '$description' => 'This event triggers when a bucket is created.' ], 'delete' => [ '$description' => 'This event triggers when a bucket is deleted.', ], 'update' => [ '$description' => 'This event triggers when a bucket is updated.', - ], + ] ], 'teams' => [ '$model' => Response::MODEL_TEAM, @@ -187,17 +187,17 @@ return [ '$description' => 'This event triggers when a membership is created.', ], 'delete' => [ - '$description' => 'This event triggers when a membership is deleted.', + '$description' => 'This event triggers when a membership is deleted.' ], 'update' => [ '$description' => 'This event triggers when a membership is updated.', 'status' => [ - '$description' => 'This event triggers when a team memberships status is updated.', - ], + '$description' => 'This event triggers when a team memberships status is updated.' + ] ], ], 'create' => [ - '$description' => 'This event triggers when a team is created.', + '$description' => 'This event triggers when a team is created.' ], 'delete' => [ '$description' => 'This event triggers when a team is deleted.', @@ -207,7 +207,7 @@ return [ 'prefs' => [ '$description' => 'This event triggers when a team\'s preferences are updated.', ], - ], + ] ], 'functions' => [ '$model' => Response::MODEL_FUNCTION, @@ -221,10 +221,10 @@ return [ '$description' => 'This event triggers when a deployment is created.', ], 'delete' => [ - '$description' => 'This event triggers when a deployment is deleted.', + '$description' => 'This event triggers when a deployment is deleted.' ], 'update' => [ - '$description' => 'This event triggers when a deployment is updated.', + '$description' => 'This event triggers when a deployment is updated.' ], ], 'executions' => [ @@ -235,21 +235,21 @@ return [ '$description' => 'This event triggers when an execution is created.', ], 'delete' => [ - '$description' => 'This event triggers when an execution is deleted.', + '$description' => 'This event triggers when an execution is deleted.' ], 'update' => [ - '$description' => 'This event triggers when an execution is updated.', + '$description' => 'This event triggers when an execution is updated.' ], ], 'create' => [ - '$description' => 'This event triggers when a function is created.', + '$description' => 'This event triggers when a function is created.' ], 'delete' => [ '$description' => 'This event triggers when a function is deleted.', ], 'update' => [ '$description' => 'This event triggers when a function is updated.', - ], + ] ], 'messages' => [ '$model' => Response::MODEL_MESSAGE, @@ -269,7 +269,7 @@ return [ '$description' => 'This event triggers when a provider is updated.', ], 'delete' => [ - '$description' => 'This event triggers when a provider is deleted.', + '$description' => 'This event triggers when a provider is deleted.' ], ], 'topics' => [ @@ -280,7 +280,7 @@ return [ '$description' => 'This event triggers when a provider is created.', ], 'delete' => [ - '$description' => 'This event triggers when a provider is deleted.', + '$description' => 'This event triggers when a provider is deleted.' ], 'subscribers' => [ '$model' => Response::MODEL_SUBSCRIBER, @@ -290,7 +290,7 @@ return [ '$description' => 'This event triggers when a subscriber is created.', ], 'delete' => [ - '$description' => 'This event triggers when a subscriber is deleted.', + '$description' => 'This event triggers when a subscriber is deleted.' ], ], ], diff --git a/app/config/locale/codes.php b/app/config/locale/codes.php index ed878887ca..641a2a6220 100644 --- a/app/config/locale/codes.php +++ b/app/config/locale/codes.php @@ -6,531 +6,532 @@ * * Source: * https://www.andiamo.co.uk/resources/iso-language-codes/ + * */ return [ [ - 'code' => 'af', - 'name' => 'Afrikaans', + "code" => "af", + "name" => "Afrikaans", ], [ - 'code' => 'ar-ae', - 'name' => 'Arabic (U.A.E.)', + "code" => "ar-ae", + "name" => "Arabic (U.A.E.)", ], [ - 'code' => 'ar-bh', - 'name' => 'Arabic (Bahrain)', + "code" => "ar-bh", + "name" => "Arabic (Bahrain)", ], [ - 'code' => 'ar-dz', - 'name' => 'Arabic (Algeria)', + "code" => "ar-dz", + "name" => "Arabic (Algeria)", ], [ - 'code' => 'ar-eg', - 'name' => 'Arabic (Egypt)', + "code" => "ar-eg", + "name" => "Arabic (Egypt)", ], [ - 'code' => 'ar-iq', - 'name' => 'Arabic (Iraq)', + "code" => "ar-iq", + "name" => "Arabic (Iraq)", ], [ - 'code' => 'ar-jo', - 'name' => 'Arabic (Jordan)', + "code" => "ar-jo", + "name" => "Arabic (Jordan)", ], [ - 'code' => 'ar-kw', - 'name' => 'Arabic (Kuwait)', + "code" => "ar-kw", + "name" => "Arabic (Kuwait)", ], [ - 'code' => 'ar-lb', - 'name' => 'Arabic (Lebanon)', + "code" => "ar-lb", + "name" => "Arabic (Lebanon)", ], [ - 'code' => 'ar-ly', - 'name' => 'Arabic (Libya)', + "code" => "ar-ly", + "name" => "Arabic (Libya)", ], [ - 'code' => 'ar-ma', - 'name' => 'Arabic (Morocco)', + "code" => "ar-ma", + "name" => "Arabic (Morocco)", ], [ - 'code' => 'ar-om', - 'name' => 'Arabic (Oman)', + "code" => "ar-om", + "name" => "Arabic (Oman)", ], [ - 'code' => 'ar-qa', - 'name' => 'Arabic (Qatar)', + "code" => "ar-qa", + "name" => "Arabic (Qatar)", ], [ - 'code' => 'ar-sa', - 'name' => 'Arabic (Saudi Arabia)', + "code" => "ar-sa", + "name" => "Arabic (Saudi Arabia)", ], [ - 'code' => 'ar-sy', - 'name' => 'Arabic (Syria)', + "code" => "ar-sy", + "name" => "Arabic (Syria)", ], [ - 'code' => 'ar-tn', - 'name' => 'Arabic (Tunisia)', + "code" => "ar-tn", + "name" => "Arabic (Tunisia)", ], [ - 'code' => 'ar-ye', - 'name' => 'Arabic (Yemen)', + "code" => "ar-ye", + "name" => "Arabic (Yemen)", ], [ - 'code' => 'as', - 'name' => 'Assamese', + "code" => "as", + "name" => "Assamese", ], [ - 'code' => 'az', - 'name' => 'Azerbaijani', + "code" => "az", + "name" => "Azerbaijani", ], [ - 'code' => 'be', - 'name' => 'Belarusian', + "code" => "be", + "name" => "Belarusian", ], [ - 'code' => 'bg', - 'name' => 'Bulgarian', + "code" => "bg", + "name" => "Bulgarian", ], [ - 'code' => 'bh', - 'name' => 'Bihari', + "code" => "bh", + "name" => "Bihari", ], [ - 'code' => 'bn', - 'name' => 'Bengali', + "code" => "bn", + "name" => "Bengali", ], [ - 'code' => 'bs', - 'name' => 'Bosnian', + "code" => "bs", + "name" => "Bosnian", ], [ - 'code' => 'ca', - 'name' => 'Catalan', + "code" => "ca", + "name" => "Catalan", ], [ - 'code' => 'cs', - 'name' => 'Czech', + "code" => "cs", + "name" => "Czech", ], [ - 'code' => 'cy', - 'name' => 'Welsh', + "code" => "cy", + "name" => "Welsh", ], [ - 'code' => 'da', - 'name' => 'Danish', + "code" => "da", + "name" => "Danish", ], [ - 'code' => 'de', - 'name' => 'German (Standard)', + "code" => "de", + "name" => "German (Standard)", ], [ - 'code' => 'de-at', - 'name' => 'German (Austria)', + "code" => "de-at", + "name" => "German (Austria)", ], [ - 'code' => 'de-ch', - 'name' => 'German (Switzerland)', + "code" => "de-ch", + "name" => "German (Switzerland)", ], [ - 'code' => 'de-li', - 'name' => 'German (Liechtenstein)', + "code" => "de-li", + "name" => "German (Liechtenstein)", ], [ - 'code' => 'de-lu', - 'name' => 'German (Luxembourg)', + "code" => "de-lu", + "name" => "German (Luxembourg)", ], [ - 'code' => 'el', - 'name' => 'Greek', + "code" => "el", + "name" => "Greek", ], [ - 'code' => 'en', - 'name' => 'English', + "code" => "en", + "name" => "English", ], [ - 'code' => 'en-au', - 'name' => 'English (Australia)', + "code" => "en-au", + "name" => "English (Australia)", ], [ - 'code' => 'en-bz', - 'name' => 'English (Belize)', + "code" => "en-bz", + "name" => "English (Belize)", ], [ - 'code' => 'en-ca', - 'name' => 'English (Canada)', + "code" => "en-ca", + "name" => "English (Canada)", ], [ - 'code' => 'en-gb', - 'name' => 'English (United Kingdom)', + "code" => "en-gb", + "name" => "English (United Kingdom)", ], [ - 'code' => 'en-ie', - 'name' => 'English (Ireland)', + "code" => "en-ie", + "name" => "English (Ireland)", ], [ - 'code' => 'en-jm', - 'name' => 'English (Jamaica)', + "code" => "en-jm", + "name" => "English (Jamaica)", ], [ - 'code' => 'en-nz', - 'name' => 'English (New Zealand)', + "code" => "en-nz", + "name" => "English (New Zealand)", ], [ - 'code' => 'en-tt', - 'name' => 'English (Trinidad)', + "code" => "en-tt", + "name" => "English (Trinidad)", ], [ - 'code' => 'en-us', - 'name' => 'English (United States)', + "code" => "en-us", + "name" => "English (United States)", ], [ - 'code' => 'en-za', - 'name' => 'English (South Africa)', + "code" => "en-za", + "name" => "English (South Africa)", ], [ - 'code' => 'eo', - 'name' => 'Esperanto', + "code" => "eo", + "name" => "Esperanto", ], [ - 'code' => 'es', - 'name' => 'Spanish (Spain)', + "code" => "es", + "name" => "Spanish (Spain)", ], [ - 'code' => 'es-ar', - 'name' => 'Spanish (Argentina)', + "code" => "es-ar", + "name" => "Spanish (Argentina)", ], [ - 'code' => 'es-bo', - 'name' => 'Spanish (Bolivia)', + "code" => "es-bo", + "name" => "Spanish (Bolivia)", ], [ - 'code' => 'es-cl', - 'name' => 'Spanish (Chile)', + "code" => "es-cl", + "name" => "Spanish (Chile)", ], [ - 'code' => 'es-co', - 'name' => 'Spanish (Colombia)', + "code" => "es-co", + "name" => "Spanish (Colombia)", ], [ - 'code' => 'es-cr', - 'name' => 'Spanish (Costa Rica)', + "code" => "es-cr", + "name" => "Spanish (Costa Rica)", ], [ - 'code' => 'es-do', - 'name' => 'Spanish (Dominican Republic)', + "code" => "es-do", + "name" => "Spanish (Dominican Republic)", ], [ - 'code' => 'es-ec', - 'name' => 'Spanish (Ecuador)', + "code" => "es-ec", + "name" => "Spanish (Ecuador)", ], [ - 'code' => 'es-gt', - 'name' => 'Spanish (Guatemala)', + "code" => "es-gt", + "name" => "Spanish (Guatemala)", ], [ - 'code' => 'es-hn', - 'name' => 'Spanish (Honduras)', + "code" => "es-hn", + "name" => "Spanish (Honduras)", ], [ - 'code' => 'es-mx', - 'name' => 'Spanish (Mexico)', + "code" => "es-mx", + "name" => "Spanish (Mexico)", ], [ - 'code' => 'es-ni', - 'name' => 'Spanish (Nicaragua)', + "code" => "es-ni", + "name" => "Spanish (Nicaragua)", ], [ - 'code' => 'es-pa', - 'name' => 'Spanish (Panama)', + "code" => "es-pa", + "name" => "Spanish (Panama)", ], [ - 'code' => 'es-pe', - 'name' => 'Spanish (Peru)', + "code" => "es-pe", + "name" => "Spanish (Peru)", ], [ - 'code' => 'es-pr', - 'name' => 'Spanish (Puerto Rico)', + "code" => "es-pr", + "name" => "Spanish (Puerto Rico)", ], [ - 'code' => 'es-py', - 'name' => 'Spanish (Paraguay)', + "code" => "es-py", + "name" => "Spanish (Paraguay)", ], [ - 'code' => 'es-sv', - 'name' => 'Spanish (El Salvador)', + "code" => "es-sv", + "name" => "Spanish (El Salvador)", ], [ - 'code' => 'es-uy', - 'name' => 'Spanish (Uruguay)', + "code" => "es-uy", + "name" => "Spanish (Uruguay)", ], [ - 'code' => 'es-ve', - 'name' => 'Spanish (Venezuela)', + "code" => "es-ve", + "name" => "Spanish (Venezuela)", ], [ - 'code' => 'et', - 'name' => 'Estonian', + "code" => "et", + "name" => "Estonian", ], [ - 'code' => 'eu', - 'name' => 'Basque', + "code" => "eu", + "name" => "Basque", ], [ - 'code' => 'fa', - 'name' => 'Farsi', + "code" => "fa", + "name" => "Farsi", ], [ - 'code' => 'fi', - 'name' => 'Finnish', + "code" => "fi", + "name" => "Finnish", ], [ - 'code' => 'fo', - 'name' => 'Faeroese', + "code" => "fo", + "name" => "Faeroese", ], [ - 'code' => 'fr', - 'name' => 'French (Standard)', + "code" => "fr", + "name" => "French (Standard)", ], [ - 'code' => 'fr-be', - 'name' => 'French (Belgium)', + "code" => "fr-be", + "name" => "French (Belgium)", ], [ - 'code' => 'fr-ca', - 'name' => 'French (Canada)', + "code" => "fr-ca", + "name" => "French (Canada)", ], [ - 'code' => 'fr-ch', - 'name' => 'French (Switzerland)', + "code" => "fr-ch", + "name" => "French (Switzerland)", ], [ - 'code' => 'fr-lu', - 'name' => 'French (Luxembourg)', + "code" => "fr-lu", + "name" => "French (Luxembourg)", ], [ - 'code' => 'ga', - 'name' => 'Irish', + "code" => "ga", + "name" => "Irish", ], [ - 'code' => 'gd', - 'name' => 'Gaelic (Scotland)', + "code" => "gd", + "name" => "Gaelic (Scotland)", ], [ - 'code' => 'he', - 'name' => 'Hebrew', + "code" => "he", + "name" => "Hebrew", ], [ - 'code' => 'hi', - 'name' => 'Hindi', + "code" => "hi", + "name" => "Hindi", ], [ - 'code' => 'hr', - 'name' => 'Croatian', + "code" => "hr", + "name" => "Croatian", ], [ - 'code' => 'hu', - 'name' => 'Hungarian', + "code" => "hu", + "name" => "Hungarian", ], [ - 'code' => 'id', - 'name' => 'Indonesian', + "code" => "id", + "name" => "Indonesian", ], [ - 'code' => 'is', - 'name' => 'Icelandic', + "code" => "is", + "name" => "Icelandic", ], [ - 'code' => 'it', - 'name' => 'Italian (Standard)', + "code" => "it", + "name" => "Italian (Standard)", ], [ - 'code' => 'it-ch', - 'name' => 'Italian (Switzerland)', + "code" => "it-ch", + "name" => "Italian (Switzerland)", ], [ - 'code' => 'ja', - 'name' => 'Japanese', + "code" => "ja", + "name" => "Japanese", ], [ - 'code' => 'ji', - 'name' => 'Yiddish', + "code" => "ji", + "name" => "Yiddish", ], [ - 'code' => 'ko', - 'name' => 'Korean', + "code" => "ko", + "name" => "Korean", ], [ - 'code' => 'ku', - 'name' => 'Kurdish', + "code" => "ku", + "name" => "Kurdish", ], [ - 'code' => 'lt', - 'name' => 'Lithuanian', + "code" => "lt", + "name" => "Lithuanian", ], [ - 'code' => 'lv', - 'name' => 'Latvian', + "code" => "lv", + "name" => "Latvian", ], [ - 'code' => 'mk', - 'name' => 'Macedonian (FYROM)', + "code" => "mk", + "name" => "Macedonian (FYROM)", ], [ - 'code' => 'ml', - 'name' => 'Malayalam', + "code" => "ml", + "name" => "Malayalam", ], [ - 'code' => 'ms', - 'name' => 'Malaysian', + "code" => "ms", + "name" => "Malaysian", ], [ - 'code' => 'mt', - 'name' => 'Maltese', + "code" => "mt", + "name" => "Maltese", ], [ - 'code' => 'nb', - 'name' => 'Norwegian (Bokmål)', + "code" => "nb", + "name" => "Norwegian (Bokmål)", ], [ - 'code' => 'ne', - 'name' => 'Nepali', + "code" => "ne", + "name" => "Nepali", ], [ - 'code' => 'nl', - 'name' => 'Dutch (Standard)', + "code" => "nl", + "name" => "Dutch (Standard)", ], [ - 'code' => 'nl-be', - 'name' => 'Dutch (Belgium)', + "code" => "nl-be", + "name" => "Dutch (Belgium)", ], [ - 'code' => 'nn', - 'name' => 'Norwegian (Nynorsk)', + "code" => "nn", + "name" => "Norwegian (Nynorsk)", ], [ - 'code' => 'no', - 'name' => 'Norwegian', + "code" => "no", + "name" => "Norwegian", ], [ - 'code' => 'pa', - 'name' => 'Punjabi', + "code" => "pa", + "name" => "Punjabi", ], [ - 'code' => 'pl', - 'name' => 'Polish', + "code" => "pl", + "name" => "Polish", ], [ - 'code' => 'pt', - 'name' => 'Portuguese (Portugal)', + "code" => "pt", + "name" => "Portuguese (Portugal)", ], [ - 'code' => 'pt-br', - 'name' => 'Portuguese (Brazil)', + "code" => "pt-br", + "name" => "Portuguese (Brazil)", ], [ - 'code' => 'rm', - 'name' => 'Rhaeto-Romanic', + "code" => "rm", + "name" => "Rhaeto-Romanic", ], [ - 'code' => 'ro', - 'name' => 'Romanian', + "code" => "ro", + "name" => "Romanian", ], [ - 'code' => 'ro-md', - 'name' => 'Romanian (Republic of Moldova)', + "code" => "ro-md", + "name" => "Romanian (Republic of Moldova)", ], [ - 'code' => 'ru', - 'name' => 'Russian', + "code" => "ru", + "name" => "Russian", ], [ - 'code' => 'ru-md', - 'name' => 'Russian (Republic of Moldova)', + "code" => "ru-md", + "name" => "Russian (Republic of Moldova)", ], [ - 'code' => 'sb', - 'name' => 'Sorbian', + "code" => "sb", + "name" => "Sorbian", ], [ - 'code' => 'sk', - 'name' => 'Slovak', + "code" => "sk", + "name" => "Slovak", ], [ - 'code' => 'sl', - 'name' => 'Slovenian', + "code" => "sl", + "name" => "Slovenian", ], [ - 'code' => 'sq', - 'name' => 'Albanian', + "code" => "sq", + "name" => "Albanian", ], [ - 'code' => 'sr', - 'name' => 'Serbian', + "code" => "sr", + "name" => "Serbian", ], [ - 'code' => 'sv', - 'name' => 'Swedish', + "code" => "sv", + "name" => "Swedish", ], [ - 'code' => 'sv-fi', - 'name' => 'Swedish (Finland)', + "code" => "sv-fi", + "name" => "Swedish (Finland)", ], [ - 'code' => 'th', - 'name' => 'Thai', + "code" => "th", + "name" => "Thai", ], [ - 'code' => 'tn', - 'name' => 'Tswana', + "code" => "tn", + "name" => "Tswana", ], [ - 'code' => 'tr', - 'name' => 'Turkish', + "code" => "tr", + "name" => "Turkish", ], [ - 'code' => 'ts', - 'name' => 'Tsonga', + "code" => "ts", + "name" => "Tsonga", ], [ - 'code' => 'ua', - 'name' => 'Ukrainian', + "code" => "ua", + "name" => "Ukrainian", ], [ - 'code' => 'ur', - 'name' => 'Urdu', + "code" => "ur", + "name" => "Urdu", ], [ - 'code' => 've', - 'name' => 'Venda', + "code" => "ve", + "name" => "Venda", ], [ - 'code' => 'vi', - 'name' => 'Vietnamese', + "code" => "vi", + "name" => "Vietnamese", ], [ - 'code' => 'xh', - 'name' => 'Xhosa', + "code" => "xh", + "name" => "Xhosa", ], [ - 'code' => 'zh-cn', - 'name' => 'Chinese (PRC)', + "code" => "zh-cn", + "name" => "Chinese (PRC)", ], [ - 'code' => 'zh-hk', - 'name' => 'Chinese (Hong Kong)', + "code" => "zh-hk", + "name" => "Chinese (Hong Kong)", ], [ - 'code' => 'zh-sg', - 'name' => 'Chinese (Singapore)', + "code" => "zh-sg", + "name" => "Chinese (Singapore)", ], [ - 'code' => 'zh-tw', - 'name' => 'Chinese (Taiwan)', + "code" => "zh-tw", + "name" => "Chinese (Taiwan)", ], [ - 'code' => 'zu', - 'name' => 'Zulu', + "code" => "zu", + "name" => "Zulu", ], ]; diff --git a/app/config/locale/languages.php b/app/config/locale/languages.php index 318ec27492..6272bd02a6 100644 --- a/app/config/locale/languages.php +++ b/app/config/locale/languages.php @@ -9,923 +9,923 @@ return [ [ - 'code' => 'aa', - 'name' => 'Afar', - 'nativeName' => 'Afar', + "code" => "aa", + "name" => "Afar", + "nativeName" => "Afar" ], [ - 'code' => 'ab', - 'name' => 'Abkhazian', - 'nativeName' => 'Аҧсуа', + "code" => "ab", + "name" => "Abkhazian", + "nativeName" => "Аҧсуа" ], [ - 'code' => 'af', - 'name' => 'Afrikaans', - 'nativeName' => 'Afrikaans', + "code" => "af", + "name" => "Afrikaans", + "nativeName" => "Afrikaans" ], [ - 'code' => 'ak', - 'name' => 'Akan', - 'nativeName' => 'Akana', + "code" => "ak", + "name" => "Akan", + "nativeName" => "Akana" ], [ - 'code' => 'am', - 'name' => 'Amharic', - 'nativeName' => 'አማርኛ', + "code" => "am", + "name" => "Amharic", + "nativeName" => "አማርኛ" ], [ - 'code' => 'an', - 'name' => 'Aragonese', - 'nativeName' => 'Aragonés', + "code" => "an", + "name" => "Aragonese", + "nativeName" => "Aragonés" ], [ - 'code' => 'ar', - 'name' => 'Arabic', - 'nativeName' => 'العربية', + "code" => "ar", + "name" => "Arabic", + "nativeName" => "العربية" ], [ - 'code' => 'as', - 'name' => 'Assamese', - 'nativeName' => 'অসমীয়া', + "code" => "as", + "name" => "Assamese", + "nativeName" => "অসমীয়া" ], [ - 'code' => 'av', - 'name' => 'Avar', - 'nativeName' => 'Авар', + "code" => "av", + "name" => "Avar", + "nativeName" => "Авар" ], [ - 'code' => 'ay', - 'name' => 'Aymara', - 'nativeName' => 'Aymar', + "code" => "ay", + "name" => "Aymara", + "nativeName" => "Aymar" ], [ - 'code' => 'az', - 'name' => 'Azerbaijani', - 'nativeName' => 'Azərbaycanca / آذربايجان', + "code" => "az", + "name" => "Azerbaijani", + "nativeName" => "Azərbaycanca / آذربايجان" ], [ - 'code' => 'ba', - 'name' => 'Bashkir', - 'nativeName' => 'Башҡорт', + "code" => "ba", + "name" => "Bashkir", + "nativeName" => "Башҡорт" ], [ - 'code' => 'be', - 'name' => 'Belarusian', - 'nativeName' => 'Беларуская', + "code" => "be", + "name" => "Belarusian", + "nativeName" => "Беларуская" ], [ - 'code' => 'bg', - 'name' => 'Bulgarian', - 'nativeName' => 'Български', + "code" => "bg", + "name" => "Bulgarian", + "nativeName" => "Български" ], [ - 'code' => 'bh', - 'name' => 'Bihari', - 'nativeName' => 'भोजपुरी', + "code" => "bh", + "name" => "Bihari", + "nativeName" => "भोजपुरी" ], [ - 'code' => 'bi', - 'name' => 'Bislama', - 'nativeName' => 'Bislama', + "code" => "bi", + "name" => "Bislama", + "nativeName" => "Bislama" ], [ - 'code' => 'bm', - 'name' => 'Bambara', - 'nativeName' => 'Bamanankan', + "code" => "bm", + "name" => "Bambara", + "nativeName" => "Bamanankan" ], [ - 'code' => 'bn', - 'name' => 'Bengali', - 'nativeName' => 'বাংলা', + "code" => "bn", + "name" => "Bengali", + "nativeName" => "বাংলা" ], [ - 'code' => 'bo', - 'name' => 'Tibetan', - 'nativeName' => 'བོད་ཡིག / Bod skad', + "code" => "bo", + "name" => "Tibetan", + "nativeName" => "བོད་ཡིག / Bod skad" ], [ - 'code' => 'br', - 'name' => 'Breton', - 'nativeName' => 'Brezhoneg', + "code" => "br", + "name" => "Breton", + "nativeName" => "Brezhoneg" ], [ - 'code' => 'bs', - 'name' => 'Bosnian', - 'nativeName' => 'Bosanski', + "code" => "bs", + "name" => "Bosnian", + "nativeName" => "Bosanski" ], [ - 'code' => 'ca', - 'name' => 'Catalan', - 'nativeName' => 'Català', + "code" => "ca", + "name" => "Catalan", + "nativeName" => "Català" ], [ - 'code' => 'ce', - 'name' => 'Chechen', - 'nativeName' => 'Нохчийн', + "code" => "ce", + "name" => "Chechen", + "nativeName" => "Нохчийн" ], [ - 'code' => 'ch', - 'name' => 'Chamorro', - 'nativeName' => 'Chamoru', + "code" => "ch", + "name" => "Chamorro", + "nativeName" => "Chamoru" ], [ - 'code' => 'co', - 'name' => 'Corsican', - 'nativeName' => 'Corsu', + "code" => "co", + "name" => "Corsican", + "nativeName" => "Corsu" ], [ - 'code' => 'cr', - 'name' => 'Cree', - 'nativeName' => 'Nehiyaw', + "code" => "cr", + "name" => "Cree", + "nativeName" => "Nehiyaw" ], [ - 'code' => 'cs', - 'name' => 'Czech', - 'nativeName' => 'Česky', + "code" => "cs", + "name" => "Czech", + "nativeName" => "Česky" ], [ - 'code' => 'cu', - 'name' => 'Old Church Slavonic / Old Bulgarian', - 'nativeName' => 'словѣньскъ / slověnĭskŭ', + "code" => "cu", + "name" => "Old Church Slavonic / Old Bulgarian", + "nativeName" => "словѣньскъ / slověnĭskŭ" ], [ - 'code' => 'cv', - 'name' => 'Chuvash', - 'nativeName' => 'Чăваш', + "code" => "cv", + "name" => "Chuvash", + "nativeName" => "Чăваш" ], [ - 'code' => 'cy', - 'name' => 'Welsh', - 'nativeName' => 'Cymraeg', + "code" => "cy", + "name" => "Welsh", + "nativeName" => "Cymraeg" ], [ - 'code' => 'da', - 'name' => 'Danish', - 'nativeName' => 'Dansk', + "code" => "da", + "name" => "Danish", + "nativeName" => "Dansk" ], [ - 'code' => 'de', - 'name' => 'German', - 'nativeName' => 'Deutsch', + "code" => "de", + "name" => "German", + "nativeName" => "Deutsch" ], [ - 'code' => 'dv', - 'name' => 'Divehi', - 'nativeName' => 'ދިވެހިބަސް', + "code" => "dv", + "name" => "Divehi", + "nativeName" => "ދިވެހިބަސް" ], [ - 'code' => 'dz', - 'name' => 'Dzongkha', - 'nativeName' => 'ཇོང་ཁ', + "code" => "dz", + "name" => "Dzongkha", + "nativeName" => "ཇོང་ཁ" ], [ - 'code' => 'ee', - 'name' => 'Ewe', - 'nativeName' => 'Ɛʋɛ', + "code" => "ee", + "name" => "Ewe", + "nativeName" => "Ɛʋɛ" ], [ - 'code' => 'el', - 'name' => 'Greek', - 'nativeName' => 'Ελληνικά', + "code" => "el", + "name" => "Greek", + "nativeName" => "Ελληνικά" ], [ - 'code' => 'en', - 'name' => 'English', - 'nativeName' => 'English', + "code" => "en", + "name" => "English", + "nativeName" => "English" ], [ - 'code' => 'eo', - 'name' => 'Esperanto', - 'nativeName' => 'Esperanto', + "code" => "eo", + "name" => "Esperanto", + "nativeName" => "Esperanto" ], [ - 'code' => 'es', - 'name' => 'Spanish', - 'nativeName' => 'Español', + "code" => "es", + "name" => "Spanish", + "nativeName" => "Español" ], [ - 'code' => 'et', - 'name' => 'Estonian', - 'nativeName' => 'Eesti', + "code" => "et", + "name" => "Estonian", + "nativeName" => "Eesti" ], [ - 'code' => 'eu', - 'name' => 'Basque', - 'nativeName' => 'Euskara', + "code" => "eu", + "name" => "Basque", + "nativeName" => "Euskara" ], [ - 'code' => 'fa', - 'name' => 'Persian', - 'nativeName' => 'فارسی', + "code" => "fa", + "name" => "Persian", + "nativeName" => "فارسی" ], [ - 'code' => 'ff', - 'name' => 'Peul', - 'nativeName' => 'Fulfulde', + "code" => "ff", + "name" => "Peul", + "nativeName" => "Fulfulde" ], [ - 'code' => 'fi', - 'name' => 'Finnish', - 'nativeName' => 'Suomi', + "code" => "fi", + "name" => "Finnish", + "nativeName" => "Suomi" ], [ - 'code' => 'fj', - 'name' => 'Fijian', - 'nativeName' => 'Na Vosa Vakaviti', + "code" => "fj", + "name" => "Fijian", + "nativeName" => "Na Vosa Vakaviti" ], [ - 'code' => 'fo', - 'name' => 'Faroese', - 'nativeName' => 'Føroyskt', + "code" => "fo", + "name" => "Faroese", + "nativeName" => "Føroyskt" ], [ - 'code' => 'fr', - 'name' => 'French', - 'nativeName' => 'Français', + "code" => "fr", + "name" => "French", + "nativeName" => "Français" ], [ - 'code' => 'fy', - 'name' => 'West Frisian', - 'nativeName' => 'Frysk', + "code" => "fy", + "name" => "West Frisian", + "nativeName" => "Frysk" ], [ - 'code' => 'ga', - 'name' => 'Irish', - 'nativeName' => 'Gaeilge', + "code" => "ga", + "name" => "Irish", + "nativeName" => "Gaeilge" ], [ - 'code' => 'gd', - 'name' => 'Scottish Gaelic', - 'nativeName' => 'Gàidhlig', + "code" => "gd", + "name" => "Scottish Gaelic", + "nativeName" => "Gàidhlig" ], [ - 'code' => 'gl', - 'name' => 'Galician', - 'nativeName' => 'Galego', + "code" => "gl", + "name" => "Galician", + "nativeName" => "Galego" ], [ - 'code' => 'gn', - 'name' => 'Guarani', - 'nativeName' => "Avañe'ẽ", + "code" => "gn", + "name" => "Guarani", + "nativeName" => "Avañe'ẽ" ], [ - 'code' => 'gu', - 'name' => 'Gujarati', - 'nativeName' => 'ગુજરાતી', + "code" => "gu", + "name" => "Gujarati", + "nativeName" => "ગુજરાતી" ], [ - 'code' => 'gv', - 'name' => 'Manx', - 'nativeName' => 'Gaelg', + "code" => "gv", + "name" => "Manx", + "nativeName" => "Gaelg" ], [ - 'code' => 'ha', - 'name' => 'Hausa', - 'nativeName' => 'هَوُسَ', + "code" => "ha", + "name" => "Hausa", + "nativeName" => "هَوُسَ" ], [ - 'code' => 'he', - 'name' => 'Hebrew', - 'nativeName' => 'עברית', + "code" => "he", + "name" => "Hebrew", + "nativeName" => "עברית" ], [ - 'code' => 'hi', - 'name' => 'Hindi', - 'nativeName' => 'हिन्दी / हिंदी ', + "code" => "hi", + "name" => "Hindi", + "nativeName" => "हिन्दी / हिंदी " ], [ - 'code' => 'ho', - 'name' => 'Hiri Motu', - 'nativeName' => 'Hiri Motu', + "code" => "ho", + "name" => "Hiri Motu", + "nativeName" => "Hiri Motu" ], [ - 'code' => 'hr', - 'name' => 'Croatian', - 'nativeName' => 'Hrvatski', + "code" => "hr", + "name" => "Croatian", + "nativeName" => "Hrvatski" ], [ - 'code' => 'ht', - 'name' => 'Haitian', - 'nativeName' => 'Krèyol ayisyen', + "code" => "ht", + "name" => "Haitian", + "nativeName" => "Krèyol ayisyen" ], [ - 'code' => 'hu', - 'name' => 'Hungarian', - 'nativeName' => 'Magyar', + "code" => "hu", + "name" => "Hungarian", + "nativeName" => "Magyar" ], [ - 'code' => 'hy', - 'name' => 'Armenian', - 'nativeName' => 'Հայերեն', + "code" => "hy", + "name" => "Armenian", + "nativeName" => "Հայերեն" ], [ - 'code' => 'hz', - 'name' => 'Herero', - 'nativeName' => 'Otsiherero', + "code" => "hz", + "name" => "Herero", + "nativeName" => "Otsiherero" ], [ - 'code' => 'ia', - 'name' => 'Interlingua', - 'nativeName' => 'Interlingua', + "code" => "ia", + "name" => "Interlingua", + "nativeName" => "Interlingua" ], [ - 'code' => 'id', - 'name' => 'Indonesian', - 'nativeName' => 'Bahasa Indonesia', + "code" => "id", + "name" => "Indonesian", + "nativeName" => "Bahasa Indonesia" ], [ - 'code' => 'ie', - 'name' => 'Interlingue', - 'nativeName' => 'Interlingue', + "code" => "ie", + "name" => "Interlingue", + "nativeName" => "Interlingue" ], [ - 'code' => 'ig', - 'name' => 'Igbo', - 'nativeName' => 'Igbo', + "code" => "ig", + "name" => "Igbo", + "nativeName" => "Igbo" ], [ - 'code' => 'ii', - 'name' => 'Sichuan Yi', - 'nativeName' => 'ꆇꉙ / 四川彝语', + "code" => "ii", + "name" => "Sichuan Yi", + "nativeName" => "ꆇꉙ / 四川彝语" ], [ - 'code' => 'ik', - 'name' => 'Inupiak', - 'nativeName' => 'Iñupiak', + "code" => "ik", + "name" => "Inupiak", + "nativeName" => "Iñupiak" ], [ - 'code' => 'io', - 'name' => 'Ido', - 'nativeName' => 'Ido', + "code" => "io", + "name" => "Ido", + "nativeName" => "Ido" ], [ - 'code' => 'is', - 'name' => 'Icelandic', - 'nativeName' => 'Íslenska', + "code" => "is", + "name" => "Icelandic", + "nativeName" => "Íslenska" ], [ - 'code' => 'it', - 'name' => 'Italian', - 'nativeName' => 'Italiano', + "code" => "it", + "name" => "Italian", + "nativeName" => "Italiano" ], [ - 'code' => 'iu', - 'name' => 'Inuktitut', - 'nativeName' => 'ᐃᓄᒃᑎᑐᑦ', + "code" => "iu", + "name" => "Inuktitut", + "nativeName" => "ᐃᓄᒃᑎᑐᑦ" ], [ - 'code' => 'ja', - 'name' => 'Japanese', - 'nativeName' => '日本語', + "code" => "ja", + "name" => "Japanese", + "nativeName" => "日本語" ], [ - 'code' => 'jv', - 'name' => 'Javanese', - 'nativeName' => 'Basa Jawa', + "code" => "jv", + "name" => "Javanese", + "nativeName" => "Basa Jawa" ], [ - 'code' => 'ka', - 'name' => 'Georgian', - 'nativeName' => 'ქართული', + "code" => "ka", + "name" => "Georgian", + "nativeName" => "ქართული" ], [ - 'code' => 'kg', - 'name' => 'Kongo', - 'nativeName' => 'KiKongo', + "code" => "kg", + "name" => "Kongo", + "nativeName" => "KiKongo" ], [ - 'code' => 'ki', - 'name' => 'Kikuyu', - 'nativeName' => 'Gĩkũyũ', + "code" => "ki", + "name" => "Kikuyu", + "nativeName" => "Gĩkũyũ" ], [ - 'code' => 'kj', - 'name' => 'Kuanyama', - 'nativeName' => 'Kuanyama', + "code" => "kj", + "name" => "Kuanyama", + "nativeName" => "Kuanyama" ], [ - 'code' => 'kk', - 'name' => 'Kazakh', - 'nativeName' => 'Қазақша', + "code" => "kk", + "name" => "Kazakh", + "nativeName" => "Қазақша" ], [ - 'code' => 'kl', - 'name' => 'Greenlandic', - 'nativeName' => 'Kalaallisut', + "code" => "kl", + "name" => "Greenlandic", + "nativeName" => "Kalaallisut" ], [ - 'code' => 'km', - 'name' => 'Khmer', - 'nativeName' => 'ភាសាខ្មែរ', + "code" => "km", + "name" => "Khmer", + "nativeName" => "ភាសាខ្មែរ" ], [ - 'code' => 'kn', - 'name' => 'Kannada', - 'nativeName' => 'ಕನ್ನಡ', + "code" => "kn", + "name" => "Kannada", + "nativeName" => "ಕನ್ನಡ" ], [ - 'code' => 'ko', - 'name' => 'Korean', - 'nativeName' => '한국어', + "code" => "ko", + "name" => "Korean", + "nativeName" => "한국어" ], [ - 'code' => 'kr', - 'name' => 'Kanuri', - 'nativeName' => 'Kanuri', + "code" => "kr", + "name" => "Kanuri", + "nativeName" => "Kanuri" ], [ - 'code' => 'ks', - 'name' => 'Kashmiri', - 'nativeName' => 'कश्मीरी / كشميري', + "code" => "ks", + "name" => "Kashmiri", + "nativeName" => "कश्मीरी / كشميري" ], [ - 'code' => 'ku', - 'name' => 'Kurdish', - 'nativeName' => 'Kurdî / كوردی', + "code" => "ku", + "name" => "Kurdish", + "nativeName" => "Kurdî / كوردی" ], [ - 'code' => 'kv', - 'name' => 'Komi', - 'nativeName' => 'Коми', + "code" => "kv", + "name" => "Komi", + "nativeName" => "Коми" ], [ - 'code' => 'kw', - 'name' => 'Cornish', - 'nativeName' => 'Kernewek', + "code" => "kw", + "name" => "Cornish", + "nativeName" => "Kernewek" ], [ - 'code' => 'ky', - 'name' => 'Kirghiz', - 'nativeName' => 'Kırgızca / Кыргызча', + "code" => "ky", + "name" => "Kirghiz", + "nativeName" => "Kırgızca / Кыргызча" ], [ - 'code' => 'la', - 'name' => 'Latin', - 'nativeName' => 'Latina', + "code" => "la", + "name" => "Latin", + "nativeName" => "Latina" ], [ - 'code' => 'lb', - 'name' => 'Luxembourgish', - 'nativeName' => 'Lëtzebuergesch', + "code" => "lb", + "name" => "Luxembourgish", + "nativeName" => "Lëtzebuergesch" ], [ - 'code' => 'lg', - 'name' => 'Ganda', - 'nativeName' => 'Luganda', + "code" => "lg", + "name" => "Ganda", + "nativeName" => "Luganda" ], [ - 'code' => 'li', - 'name' => 'Limburgian', - 'nativeName' => 'Limburgs', + "code" => "li", + "name" => "Limburgian", + "nativeName" => "Limburgs" ], [ - 'code' => 'ln', - 'name' => 'Lingala', - 'nativeName' => 'Lingála', + "code" => "ln", + "name" => "Lingala", + "nativeName" => "Lingála" ], [ - 'code' => 'lo', - 'name' => 'Laotian', - 'nativeName' => 'ລາວ / Pha xa lao', + "code" => "lo", + "name" => "Laotian", + "nativeName" => "ລາວ / Pha xa lao" ], [ - 'code' => 'lt', - 'name' => 'Lithuanian', - 'nativeName' => 'Lietuvių', + "code" => "lt", + "name" => "Lithuanian", + "nativeName" => "Lietuvių" ], [ - 'code' => 'lu', - 'name' => 'Luba-Katanga', - 'nativeName' => 'Tshiluba', + "code" => "lu", + "name" => "Luba-Katanga", + "nativeName" => "Tshiluba" ], [ - 'code' => 'lv', - 'name' => 'Latvian', - 'nativeName' => 'Latviešu', + "code" => "lv", + "name" => "Latvian", + "nativeName" => "Latviešu" ], [ - 'code' => 'mg', - 'name' => 'Malagasy', - 'nativeName' => 'Malagasy', + "code" => "mg", + "name" => "Malagasy", + "nativeName" => "Malagasy" ], [ - 'code' => 'mh', - 'name' => 'Marshallese', - 'nativeName' => 'Kajin Majel / Ebon', + "code" => "mh", + "name" => "Marshallese", + "nativeName" => "Kajin Majel / Ebon" ], [ - 'code' => 'mi', - 'name' => 'Maori', - 'nativeName' => 'Māori', + "code" => "mi", + "name" => "Maori", + "nativeName" => "Māori" ], [ - 'code' => 'mk', - 'name' => 'Macedonian', - 'nativeName' => 'Македонски', + "code" => "mk", + "name" => "Macedonian", + "nativeName" => "Македонски" ], [ - 'code' => 'ml', - 'name' => 'Malayalam', - 'nativeName' => 'മലയാളം', + "code" => "ml", + "name" => "Malayalam", + "nativeName" => "മലയാളം" ], [ - 'code' => 'mn', - 'name' => 'Mongolian', - 'nativeName' => 'Монгол', + "code" => "mn", + "name" => "Mongolian", + "nativeName" => "Монгол" ], [ - 'code' => 'mo', - 'name' => 'Moldovan', - 'nativeName' => 'Moldovenească', + "code" => "mo", + "name" => "Moldovan", + "nativeName" => "Moldovenească" ], [ - 'code' => 'mr', - 'name' => 'Marathi', - 'nativeName' => 'मराठी', + "code" => "mr", + "name" => "Marathi", + "nativeName" => "मराठी" ], [ - 'code' => 'ms', - 'name' => 'Malay', - 'nativeName' => 'Bahasa Melayu', + "code" => "ms", + "name" => "Malay", + "nativeName" => "Bahasa Melayu" ], [ - 'code' => 'mt', - 'name' => 'Maltese', - 'nativeName' => 'bil-Malti', + "code" => "mt", + "name" => "Maltese", + "nativeName" => "bil-Malti" ], [ - 'code' => 'my', - 'name' => 'Burmese', - 'nativeName' => 'မြန်မာစာ', + "code" => "my", + "name" => "Burmese", + "nativeName" => "မြန်မာစာ" ], [ - 'code' => 'na', - 'name' => 'Nauruan', - 'nativeName' => 'Dorerin Naoero', + "code" => "na", + "name" => "Nauruan", + "nativeName" => "Dorerin Naoero" ], [ - 'code' => 'nb', - 'name' => 'Norwegian Bokmål', - 'nativeName' => 'Norsk bokmål', + "code" => "nb", + "name" => "Norwegian Bokmål", + "nativeName" => "Norsk bokmål" ], [ - 'code' => 'nd', - 'name' => 'North Ndebele', - 'nativeName' => 'Sindebele', + "code" => "nd", + "name" => "North Ndebele", + "nativeName" => "Sindebele" ], [ - 'code' => 'ne', - 'name' => 'Nepali', - 'nativeName' => 'नेपाली', + "code" => "ne", + "name" => "Nepali", + "nativeName" => "नेपाली" ], [ - 'code' => 'ng', - 'name' => 'Ndonga', - 'nativeName' => 'Oshiwambo', + "code" => "ng", + "name" => "Ndonga", + "nativeName" => "Oshiwambo" ], [ - 'code' => 'nl', - 'name' => 'Dutch', - 'nativeName' => 'Nederlands', + "code" => "nl", + "name" => "Dutch", + "nativeName" => "Nederlands" ], [ - 'code' => 'nn', - 'name' => 'Norwegian Nynorsk', - 'nativeName' => 'Norsk nynorsk', + "code" => "nn", + "name" => "Norwegian Nynorsk", + "nativeName" => "Norsk nynorsk" ], [ - 'code' => 'nr', - 'name' => 'South Ndebele', - 'nativeName' => 'isiNdebele', + "code" => "nr", + "name" => "South Ndebele", + "nativeName" => "isiNdebele" ], [ - 'code' => 'nv', - 'name' => 'Navajo', - 'nativeName' => 'Diné bizaad', + "code" => "nv", + "name" => "Navajo", + "nativeName" => "Diné bizaad" ], [ - 'code' => 'ny', - 'name' => 'Chichewa', - 'nativeName' => 'Chi-Chewa', + "code" => "ny", + "name" => "Chichewa", + "nativeName" => "Chi-Chewa" ], [ - 'code' => 'oc', - 'name' => 'Occitan', - 'nativeName' => 'Occitan', + "code" => "oc", + "name" => "Occitan", + "nativeName" => "Occitan" ], [ - 'code' => 'oj', - 'name' => 'Ojibwa', - 'nativeName' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ / Anishinaabemowin', + "code" => "oj", + "name" => "Ojibwa", + "nativeName" => "ᐊᓂᔑᓈᐯᒧᐎᓐ / Anishinaabemowin" ], [ - 'code' => 'om', - 'name' => 'Oromo', - 'nativeName' => 'Oromoo', + "code" => "om", + "name" => "Oromo", + "nativeName" => "Oromoo" ], [ - 'code' => 'or', - 'name' => 'Oriya', - 'nativeName' => 'ଓଡ଼ିଆ', + "code" => "or", + "name" => "Oriya", + "nativeName" => "ଓଡ଼ିଆ" ], [ - 'code' => 'os', - 'name' => 'Ossetian / Ossetic', - 'nativeName' => 'Иронау', + "code" => "os", + "name" => "Ossetian / Ossetic", + "nativeName" => "Иронау" ], [ - 'code' => 'pa', - 'name' => 'Panjabi / Punjabi', - 'nativeName' => 'ਪੰਜਾਬੀ / पंजाबी / پنجابي', + "code" => "pa", + "name" => "Panjabi / Punjabi", + "nativeName" => "ਪੰਜਾਬੀ / पंजाबी / پنجابي" ], [ - 'code' => 'pi', - 'name' => 'Pali', - 'nativeName' => 'Pāli / पाऴि', + "code" => "pi", + "name" => "Pali", + "nativeName" => "Pāli / पाऴि" ], [ - 'code' => 'pl', - 'name' => 'Polish', - 'nativeName' => 'Polski', + "code" => "pl", + "name" => "Polish", + "nativeName" => "Polski" ], [ - 'code' => 'ps', - 'name' => 'Pashto', - 'nativeName' => 'پښتو', + "code" => "ps", + "name" => "Pashto", + "nativeName" => "پښتو" ], [ - 'code' => 'pt', - 'name' => 'Portuguese', - 'nativeName' => 'Português', + "code" => "pt", + "name" => "Portuguese", + "nativeName" => "Português" ], [ - 'code' => 'qu', - 'name' => 'Quechua', - 'nativeName' => 'Runa Simi', + "code" => "qu", + "name" => "Quechua", + "nativeName" => "Runa Simi" ], [ - 'code' => 'rm', - 'name' => 'Raeto Romance', - 'nativeName' => 'Rumantsch', + "code" => "rm", + "name" => "Raeto Romance", + "nativeName" => "Rumantsch" ], [ - 'code' => 'rn', - 'name' => 'Kirundi', - 'nativeName' => 'Kirundi', + "code" => "rn", + "name" => "Kirundi", + "nativeName" => "Kirundi" ], [ - 'code' => 'ro', - 'name' => 'Romanian', - 'nativeName' => 'Română', + "code" => "ro", + "name" => "Romanian", + "nativeName" => "Română" ], [ - 'code' => 'ru', - 'name' => 'Russian', - 'nativeName' => 'Русский', + "code" => "ru", + "name" => "Russian", + "nativeName" => "Русский" ], [ - 'code' => 'rw', - 'name' => 'Rwandi', - 'nativeName' => 'Kinyarwandi', + "code" => "rw", + "name" => "Rwandi", + "nativeName" => "Kinyarwandi" ], [ - 'code' => 'sa', - 'name' => 'Sanskrit', - 'nativeName' => 'संस्कृतम्', + "code" => "sa", + "name" => "Sanskrit", + "nativeName" => "संस्कृतम्" ], [ - 'code' => 'sc', - 'name' => 'Sardinian', - 'nativeName' => 'Sardu', + "code" => "sc", + "name" => "Sardinian", + "nativeName" => "Sardu" ], [ - 'code' => 'sd', - 'name' => 'Sindhi', - 'nativeName' => 'सिन्धी / सिंधी ', + "code" => "sd", + "name" => "Sindhi", + "nativeName" => "सिन्धी / सिंधी " ], [ - 'code' => 'se', - 'name' => 'Northern Sami', - 'nativeName' => 'Sámegiella', + "code" => "se", + "name" => "Northern Sami", + "nativeName" => "Sámegiella" ], [ - 'code' => 'sg', - 'name' => 'Sango', - 'nativeName' => 'Sängö', + "code" => "sg", + "name" => "Sango", + "nativeName" => "Sängö" ], [ - 'code' => 'sh', - 'name' => 'Serbo-Croatian', - 'nativeName' => 'Srpskohrvatski / Српскохрватски', + "code" => "sh", + "name" => "Serbo-Croatian", + "nativeName" => "Srpskohrvatski / Српскохрватски" ], [ - 'code' => 'si', - 'name' => 'Sinhalese', - 'nativeName' => 'සිංහල', + "code" => "si", + "name" => "Sinhalese", + "nativeName" => "සිංහල" ], [ - 'code' => 'sk', - 'name' => 'Slovak', - 'nativeName' => 'Slovenčina', + "code" => "sk", + "name" => "Slovak", + "nativeName" => "Slovenčina" ], [ - 'code' => 'sl', - 'name' => 'Slovenian', - 'nativeName' => 'Slovenščina', + "code" => "sl", + "name" => "Slovenian", + "nativeName" => "Slovenščina" ], [ - 'code' => 'sm', - 'name' => 'Samoan', - 'nativeName' => 'Gagana Samoa', + "code" => "sm", + "name" => "Samoan", + "nativeName" => "Gagana Samoa" ], [ - 'code' => 'sn', - 'name' => 'Shona', - 'nativeName' => 'chiShona', + "code" => "sn", + "name" => "Shona", + "nativeName" => "chiShona" ], [ - 'code' => 'so', - 'name' => 'Somalia', - 'nativeName' => 'Soomaaliga', + "code" => "so", + "name" => "Somalia", + "nativeName" => "Soomaaliga" ], [ - 'code' => 'sq', - 'name' => 'Albanian', - 'nativeName' => 'Shqip', + "code" => "sq", + "name" => "Albanian", + "nativeName" => "Shqip" ], [ - 'code' => 'sr', - 'name' => 'Serbian', - 'nativeName' => 'Српски', + "code" => "sr", + "name" => "Serbian", + "nativeName" => "Српски" ], [ - 'code' => 'ss', - 'name' => 'Swati', - 'nativeName' => 'SiSwati', + "code" => "ss", + "name" => "Swati", + "nativeName" => "SiSwati" ], [ - 'code' => 'st', - 'name' => 'Southern Sotho', - 'nativeName' => 'Sesotho', + "code" => "st", + "name" => "Southern Sotho", + "nativeName" => "Sesotho" ], [ - 'code' => 'su', - 'name' => 'Sundanese', - 'nativeName' => 'Basa Sunda', + "code" => "su", + "name" => "Sundanese", + "nativeName" => "Basa Sunda" ], [ - 'code' => 'sv', - 'name' => 'Swedish', - 'nativeName' => 'Svenska', + "code" => "sv", + "name" => "Swedish", + "nativeName" => "Svenska" ], [ - 'code' => 'sw', - 'name' => 'Swahili', - 'nativeName' => 'Kiswahili', + "code" => "sw", + "name" => "Swahili", + "nativeName" => "Kiswahili" ], [ - 'code' => 'ta', - 'name' => 'Tamil', - 'nativeName' => 'தமிழ்', + "code" => "ta", + "name" => "Tamil", + "nativeName" => "தமிழ்" ], [ - 'code' => 'te', - 'name' => 'Telugu', - 'nativeName' => 'తెలుగు', + "code" => "te", + "name" => "Telugu", + "nativeName" => "తెలుగు" ], [ - 'code' => 'tg', - 'name' => 'Tajik', - 'nativeName' => 'Тоҷикӣ', + "code" => "tg", + "name" => "Tajik", + "nativeName" => "Тоҷикӣ" ], [ - 'code' => 'th', - 'name' => 'Thai', - 'nativeName' => 'ไทย / Phasa Thai', + "code" => "th", + "name" => "Thai", + "nativeName" => "ไทย / Phasa Thai" ], [ - 'code' => 'ti', - 'name' => 'Tigrinya', - 'nativeName' => 'ትግርኛ', + "code" => "ti", + "name" => "Tigrinya", + "nativeName" => "ትግርኛ" ], [ - 'code' => 'tk', - 'name' => 'Turkmen', - 'nativeName' => 'Туркмен / تركمن', + "code" => "tk", + "name" => "Turkmen", + "nativeName" => "Туркмен / تركمن" ], [ - 'code' => 'tl', - 'name' => 'Tagalog / Filipino', - 'nativeName' => 'Tagalog', + "code" => "tl", + "name" => "Tagalog / Filipino", + "nativeName" => "Tagalog" ], [ - 'code' => 'tn', - 'name' => 'Tswana', - 'nativeName' => 'Setswana', + "code" => "tn", + "name" => "Tswana", + "nativeName" => "Setswana" ], [ - 'code' => 'to', - 'name' => 'Tonga', - 'nativeName' => 'Lea Faka-Tonga', + "code" => "to", + "name" => "Tonga", + "nativeName" => "Lea Faka-Tonga" ], [ - 'code' => 'tr', - 'name' => 'Turkish', - 'nativeName' => 'Türkçe', + "code" => "tr", + "name" => "Turkish", + "nativeName" => "Türkçe" ], [ - 'code' => 'ts', - 'name' => 'Tsonga', - 'nativeName' => 'Xitsonga', + "code" => "ts", + "name" => "Tsonga", + "nativeName" => "Xitsonga" ], [ - 'code' => 'tt', - 'name' => 'Tatar', - 'nativeName' => 'Tatarça', + "code" => "tt", + "name" => "Tatar", + "nativeName" => "Tatarça" ], [ - 'code' => 'tw', - 'name' => 'Twi', - 'nativeName' => 'Twi', + "code" => "tw", + "name" => "Twi", + "nativeName" => "Twi" ], [ - 'code' => 'ty', - 'name' => 'Tahitian', - 'nativeName' => 'Reo Mā`ohi', + "code" => "ty", + "name" => "Tahitian", + "nativeName" => "Reo Mā`ohi" ], [ - 'code' => 'ug', - 'name' => 'Uyghur', - 'nativeName' => 'Uyƣurqə / ئۇيغۇرچە', + "code" => "ug", + "name" => "Uyghur", + "nativeName" => "Uyƣurqə / ئۇيغۇرچە" ], [ - 'code' => 'uk', - 'name' => 'Ukrainian', - 'nativeName' => 'Українська', + "code" => "uk", + "name" => "Ukrainian", + "nativeName" => "Українська" ], [ - 'code' => 'ur', - 'name' => 'Urdu', - 'nativeName' => 'اردو', + "code" => "ur", + "name" => "Urdu", + "nativeName" => "اردو" ], [ - 'code' => 'uz', - 'name' => 'Uzbek', - 'nativeName' => 'Ўзбек', + "code" => "uz", + "name" => "Uzbek", + "nativeName" => "Ўзбек" ], [ - 'code' => 've', - 'name' => 'Venda', - 'nativeName' => 'Tshivenḓa', + "code" => "ve", + "name" => "Venda", + "nativeName" => "Tshivenḓa" ], [ - 'code' => 'vi', - 'name' => 'Vietnamese', - 'nativeName' => 'Tiếng Việt', + "code" => "vi", + "name" => "Vietnamese", + "nativeName" => "Tiếng Việt" ], [ - 'code' => 'vo', - 'name' => 'Volapük', - 'nativeName' => 'Volapük', + "code" => "vo", + "name" => "Volapük", + "nativeName" => "Volapük" ], [ - 'code' => 'wa', - 'name' => 'Walloon', - 'nativeName' => 'Walon', + "code" => "wa", + "name" => "Walloon", + "nativeName" => "Walon" ], [ - 'code' => 'wo', - 'name' => 'Wolof', - 'nativeName' => 'Wollof', + "code" => "wo", + "name" => "Wolof", + "nativeName" => "Wollof" ], [ - 'code' => 'xh', - 'name' => 'Xhosa', - 'nativeName' => 'isiXhosa', + "code" => "xh", + "name" => "Xhosa", + "nativeName" => "isiXhosa" ], [ - 'code' => 'yi', - 'name' => 'Yiddish', - 'nativeName' => 'ייִדיש', + "code" => "yi", + "name" => "Yiddish", + "nativeName" => "ייִדיש" ], [ - 'code' => 'yo', - 'name' => 'Yoruba', - 'nativeName' => 'Yorùbá', + "code" => "yo", + "name" => "Yoruba", + "nativeName" => "Yorùbá" ], [ - 'code' => 'za', - 'name' => 'Zhuang', - 'nativeName' => 'Cuengh / Tôô / 壮语', + "code" => "za", + "name" => "Zhuang", + "nativeName" => "Cuengh / Tôô / 壮语" ], [ - 'code' => 'zh', - 'name' => 'Chinese', - 'nativeName' => '中文', + "code" => "zh", + "name" => "Chinese", + "nativeName" => "中文" ], [ - 'code' => 'zu', - 'name' => 'Zulu', - 'nativeName' => 'isiZulu', - ], + "code" => "zu", + "name" => "Zulu", + "nativeName" => "isiZulu" + ] ]; diff --git a/app/config/locale/templates.php b/app/config/locale/templates.php index 9c365813a7..f2672c04a0 100644 --- a/app/config/locale/templates.php +++ b/app/config/locale/templates.php @@ -10,6 +10,6 @@ return [ 'sms' => [ 'verification', 'login', - 'invitation', - ], + 'invitation' + ] ]; diff --git a/app/config/messagingProviders.php b/app/config/messagingProviders.php index 1d3ba8ed60..a33665196b 100644 --- a/app/config/messagingProviders.php +++ b/app/config/messagingProviders.php @@ -1,300 +1,300 @@ [ - 'mailchimp' => [ - 'name' => 'Mailchimp', - 'developers' => 'https://mailchimp.com/developer/marketing/api/', - 'icon' => 'icon-mailchimp', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'mailgun' => [ - 'name' => 'Mailgun', - 'developers' => 'https://documentation.mailgun.com/', - 'icon' => 'icon-mailgun', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'mailjet' => [ - 'name' => 'Mailjet', - 'developers' => 'https://dev.mailjet.com/', - 'icon' => 'icon-mailjet', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'postmark' => [ - 'name' => 'Postmark', - 'developers' => 'https://postmarkapp.com/developer', - 'icon' => 'icon-postmark', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sendgrid' => [ - 'name' => 'Sendgrid', - 'developers' => 'https://docs.sendgrid.com/api-reference/how-to-use-the-sendgrid-v3-api/', - 'icon' => 'icon-sendgrid', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sendinblue' => [ - 'name' => 'SendinBlue', - 'developers' => 'https://developers.sendinblue.com/', - 'icon' => 'icon-sendinblue', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'mailslurp' => [ - 'name' => 'MailSlurp', - 'developers' => 'https://www.mailslurp.com/docs/', - 'icon' => 'icon-mailslurp', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'elasticemail' => [ - 'name' => 'ElasticEmail', - 'developers' => 'https://api.elasticemail.com/public/help', - 'icon' => 'icon-elasticemail', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'ses' => [ - 'name' => 'SES', - 'developers' => 'https://docs.aws.amazon.com/ses/latest/APIReference/', - 'icon' => 'icon-ses', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], + 'email' => [ + 'mailchimp' => [ + 'name' => 'Mailchimp', + 'developers' => 'https://mailchimp.com/developer/marketing/api/', + 'icon' => 'icon-mailchimp', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, ], - 'sms' => [ - 'africastalking' => [ - 'name' => 'Africa\'s Talking', - 'developers' => 'https://developers.africastalking.com/', - 'icon' => 'icon-africastalking', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'clickatell' => [ - 'name' => 'Clickatell', - 'developers' => 'https://www.clickatell.com/developers/api-docs/', - 'icon' => 'icon-clickatell', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'infobip' => [ - 'name' => 'Infobip', - 'developers' => 'https://www.infobip.com/docs/', - 'icon' => 'icon-infobip', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'msg91' => [ - 'name' => 'Msg91', - 'developers' => 'https://docs.msg91.com/reference/overview', - 'icon' => 'icon-msg91', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'plivo' => [ - 'name' => 'Plivo', - 'developers' => 'https://developers.plivo.com/', - 'icon' => 'icon-plivo', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sinch' => [ - 'name' => 'Sinch', - 'developers' => 'https://developers.sinch.com/', - 'icon' => 'icon-sinch', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sms77' => [ - 'name' => 'Sms77', - 'developers' => 'https://sms77.io/docs/gateway/', - 'icon' => 'icon-sms77', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'telesign' => [ - 'name' => 'Telesign', - 'developers' => 'https://developer.telesign.com/enterprise/docs', - 'icon' => 'icon-telesign', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'textmagic' => [ - 'name' => 'TextMagic', - 'developers' => 'https://www.textmagic.com/docs/api/', - 'icon' => 'icon-twilio', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'twilio' => [ - 'name' => 'Twilio', - 'developers' => 'https://www.twilio.com/docs/sms', - 'icon' => 'icon-twilio', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'twilio-notify' => [ - 'name' => 'Twilio Notify', - 'developers' => 'https://www.twilio.com/docs/notify', - 'icon' => 'icon-twilio', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'vonage' => [ - 'name' => 'Vonage', - 'developers' => 'https://developer.nexmo.com/', - 'icon' => 'icon-vonage', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], + 'mailgun' => [ + 'name' => 'Mailgun', + 'developers' => 'https://documentation.mailgun.com/', + 'icon' => 'icon-mailgun', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, ], - 'push' => [ - 'apns' => [ - 'name' => 'APNS', - 'developers' => 'https://developer.apple.com/documentation/usernotifications', - 'icon' => 'icon-apns', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'fcm' => [ - 'name' => 'FCM', - 'developers' => 'https://firebase.google.com/docs/cloud-messaging', - 'icon' => 'icon-fcm', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'one_signal' => [ - 'name' => 'OneSignal', - 'developers' => 'https://documentation.onesignal.com/docs', - 'icon' => 'icon-onesignal', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'pushbullet' => [ - 'name' => 'PushBullet', - 'developers' => 'https://docs.pushbullet.com/', - 'icon' => 'icon-pushbullet', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'pusher' => [ - 'name' => 'Pusher', - 'developers' => 'https://pusher.com/docs', - 'icon' => 'icon-pusher', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'pushwoosh' => [ - 'name' => 'Pushwoosh', - 'developers' => 'https://www.pushwoosh.com/docs/', - 'icon' => 'icon-pushwoosh', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'urban_airship' => [ - 'name' => 'Urban Airship', - 'developers' => 'https://docs.airship.com/api/', - 'icon' => 'icon-urbanairship', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'web_push' => [ - 'name' => 'WebPush', - 'developers' => 'https://developer.mozilla.org/en-US/docs/Web/API/Push_API', - 'icon' => 'icon-webpush', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], + 'mailjet' => [ + 'name' => 'Mailjet', + 'developers' => 'https://dev.mailjet.com/', + 'icon' => 'icon-mailjet', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, ], + 'postmark' => [ + 'name' => 'Postmark', + 'developers' => 'https://postmarkapp.com/developer', + 'icon' => 'icon-postmark', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sendgrid' => [ + 'name' => 'Sendgrid', + 'developers' => 'https://docs.sendgrid.com/api-reference/how-to-use-the-sendgrid-v3-api/', + 'icon' => 'icon-sendgrid', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sendinblue' => [ + 'name' => 'SendinBlue', + 'developers' => 'https://developers.sendinblue.com/', + 'icon' => 'icon-sendinblue', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'mailslurp' => [ + 'name' => 'MailSlurp', + 'developers' => 'https://www.mailslurp.com/docs/', + 'icon' => 'icon-mailslurp', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'elasticemail' => [ + 'name' => 'ElasticEmail', + 'developers' => 'https://api.elasticemail.com/public/help', + 'icon' => 'icon-elasticemail', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'ses' => [ + 'name' => 'SES', + 'developers' => 'https://docs.aws.amazon.com/ses/latest/APIReference/', + 'icon' => 'icon-ses', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + ], + 'sms' => [ + 'africastalking' => [ + 'name' => 'Africa\'s Talking', + 'developers' => 'https://developers.africastalking.com/', + 'icon' => 'icon-africastalking', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'clickatell' => [ + 'name' => 'Clickatell', + 'developers' => 'https://www.clickatell.com/developers/api-docs/', + 'icon' => 'icon-clickatell', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'infobip' => [ + 'name' => 'Infobip', + 'developers' => 'https://www.infobip.com/docs/', + 'icon' => 'icon-infobip', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'msg91' => [ + 'name' => 'Msg91', + 'developers' => 'https://docs.msg91.com/reference/overview', + 'icon' => 'icon-msg91', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'plivo' => [ + 'name' => 'Plivo', + 'developers' => 'https://developers.plivo.com/', + 'icon' => 'icon-plivo', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sinch' => [ + 'name' => 'Sinch', + 'developers' => 'https://developers.sinch.com/', + 'icon' => 'icon-sinch', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'sms77' => [ + 'name' => 'Sms77', + 'developers' => 'https://sms77.io/docs/gateway/', + 'icon' => 'icon-sms77', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'telesign' => [ + 'name' => 'Telesign', + 'developers' => 'https://developer.telesign.com/enterprise/docs', + 'icon' => 'icon-telesign', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'textmagic' => [ + 'name' => 'TextMagic', + 'developers' => 'https://www.textmagic.com/docs/api/', + 'icon' => 'icon-twilio', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'twilio' => [ + 'name' => 'Twilio', + 'developers' => 'https://www.twilio.com/docs/sms', + 'icon' => 'icon-twilio', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'twilio-notify' => [ + 'name' => 'Twilio Notify', + 'developers' => 'https://www.twilio.com/docs/notify', + 'icon' => 'icon-twilio', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'vonage' => [ + 'name' => 'Vonage', + 'developers' => 'https://developer.nexmo.com/', + 'icon' => 'icon-vonage', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + ], + 'push' => [ + 'apns' => [ + 'name' => 'APNS', + 'developers' => 'https://developer.apple.com/documentation/usernotifications', + 'icon' => 'icon-apns', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'fcm' => [ + 'name' => 'FCM', + 'developers' => 'https://firebase.google.com/docs/cloud-messaging', + 'icon' => 'icon-fcm', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'one_signal' => [ + 'name' => 'OneSignal', + 'developers' => 'https://documentation.onesignal.com/docs', + 'icon' => 'icon-onesignal', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'pushbullet' => [ + 'name' => 'PushBullet', + 'developers' => 'https://docs.pushbullet.com/', + 'icon' => 'icon-pushbullet', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'pusher' => [ + 'name' => 'Pusher', + 'developers' => 'https://pusher.com/docs', + 'icon' => 'icon-pusher', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'pushwoosh' => [ + 'name' => 'Pushwoosh', + 'developers' => 'https://www.pushwoosh.com/docs/', + 'icon' => 'icon-pushwoosh', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'urban_airship' => [ + 'name' => 'Urban Airship', + 'developers' => 'https://docs.airship.com/api/', + 'icon' => 'icon-urbanairship', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + 'web_push' => [ + 'name' => 'WebPush', + 'developers' => 'https://developer.mozilla.org/en-US/docs/Web/API/Push_API', + 'icon' => 'icon-webpush', + 'enabled' => false, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], + ] ]; diff --git a/app/config/platforms.php b/app/config/platforms.php index 76dcbca50d..56103fad4a 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -24,7 +24,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'javascript', - 'source' => \realpath(__DIR__.'/../sdks/client-web'), + 'source' => \realpath(__DIR__ . '/../sdks/client-web'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-web.git', 'gitRepoName' => 'sdk-for-web', 'gitUserName' => 'appwrite', @@ -58,7 +58,7 @@ return [ 'source' => 'https://github.com/appwrite/todo-with-svelte', 'url' => 'https://appwrite-todo-with-svelte.vercel.app/', ], - ], + ] ], [ 'key' => 'flutter', @@ -72,7 +72,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'dart', - 'source' => \realpath(__DIR__.'/../sdks/client-flutter'), + 'source' => \realpath(__DIR__ . '/../sdks/client-flutter'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-flutter.git', 'gitRepoName' => 'sdk-for-flutter', 'gitUserName' => 'appwrite', @@ -90,7 +90,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'swift', - 'source' => \realpath(__DIR__.'/../sdks/client-apple'), + 'source' => \realpath(__DIR__ . '/../sdks/client-apple'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-apple.git', 'gitRepoName' => 'sdk-for-apple', 'gitUserName' => 'appwrite', @@ -125,7 +125,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'kotlin', - 'source' => \realpath(__DIR__.'/../sdks/client-android'), + 'source' => \realpath(__DIR__ . '/../sdks/client-android'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-android.git', 'gitRepoName' => 'sdk-for-android', 'gitUserName' => 'appwrite', @@ -147,7 +147,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'graphql', - 'source' => \realpath(__DIR__.'/../sdks/client-graphql'), + 'source' => \realpath(__DIR__ . '/../sdks/client-graphql'), 'gitUrl' => '', 'gitRepoName' => '', 'gitUserName' => '', @@ -166,7 +166,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'http', - 'source' => \realpath(__DIR__.'/../sdks/client-rest'), + 'source' => \realpath(__DIR__ . '/../sdks/client-rest'), 'gitUrl' => '', 'gitRepoName' => '', 'gitUserName' => '', @@ -194,7 +194,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_CONSOLE, 'prism' => 'javascript', - 'source' => \realpath(__DIR__.'/../sdks/console-web'), + 'source' => \realpath(__DIR__ . '/../sdks/console-web'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-console.git', 'gitBranch' => 'dev', 'gitRepoName' => 'sdk-for-console', @@ -212,7 +212,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_CONSOLE, 'prism' => 'bash', - 'source' => \realpath(__DIR__.'/../sdks/console-cli'), + 'source' => \realpath(__DIR__ . '/../sdks/console-cli'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-cli.git', 'gitRepoName' => 'sdk-for-cli', 'gitUserName' => 'appwrite', @@ -240,7 +240,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'javascript', - 'source' => \realpath(__DIR__.'/../sdks/server-nodejs'), + 'source' => \realpath(__DIR__ . '/../sdks/server-nodejs'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-node.git', 'gitRepoName' => 'sdk-for-node', 'gitUserName' => 'appwrite', @@ -258,7 +258,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'typescript', - 'source' => \realpath(__DIR__.'/../sdks/server-deno'), + 'source' => \realpath(__DIR__ . '/../sdks/server-deno'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-deno.git', 'gitRepoName' => 'sdk-for-deno', 'gitUserName' => 'appwrite', @@ -276,7 +276,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'php', - 'source' => \realpath(__DIR__.'/../sdks/server-php'), + 'source' => \realpath(__DIR__ . '/../sdks/server-php'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-php.git', 'gitRepoName' => 'sdk-for-php', 'gitUserName' => 'appwrite', @@ -294,7 +294,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'python', - 'source' => \realpath(__DIR__.'/../sdks/server-python'), + 'source' => \realpath(__DIR__ . '/../sdks/server-python'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-python.git', 'gitRepoName' => 'sdk-for-python', 'gitUserName' => 'appwrite', @@ -312,7 +312,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'ruby', - 'source' => \realpath(__DIR__.'/../sdks/server-ruby'), + 'source' => \realpath(__DIR__ . '/../sdks/server-ruby'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-ruby.git', 'gitRepoName' => 'sdk-for-ruby', 'gitUserName' => 'appwrite', @@ -330,7 +330,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'go', - 'source' => \realpath(__DIR__.'/../sdks/server-go'), + 'source' => \realpath(__DIR__ . '/../sdks/server-go'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-go.git', 'gitRepoName' => 'sdk-for-go', 'gitUserName' => 'appwrite', @@ -348,7 +348,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'java', - 'source' => \realpath(__DIR__.'/../sdks/server-java'), + 'source' => \realpath(__DIR__ . '/../sdks/server-java'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-java.git', 'gitRepoName' => 'sdk-for-java', 'gitUserName' => 'appwrite', @@ -366,7 +366,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'csharp', - 'source' => \realpath(__DIR__.'/../sdks/server-dotnet'), + 'source' => \realpath(__DIR__ . '/../sdks/server-dotnet'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-dotnet.git', 'gitRepoName' => 'sdk-for-dotnet', 'gitUserName' => 'appwrite', @@ -384,7 +384,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'dart', - 'source' => \realpath(__DIR__.'/../sdks/server-dart'), + 'source' => \realpath(__DIR__ . '/../sdks/server-dart'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-dart.git', 'gitRepoName' => 'sdk-for-dart', 'gitUserName' => 'appwrite', @@ -402,7 +402,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'kotlin', - 'source' => \realpath(__DIR__.'/../sdks/server-kotlin'), + 'source' => \realpath(__DIR__ . '/../sdks/server-kotlin'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-kotlin.git', 'gitRepoName' => 'sdk-for-kotlin', 'gitUserName' => 'appwrite', @@ -424,7 +424,7 @@ return [ 'hidden' => false, 'family' => APP_PLATFORM_SERVER, 'prism' => 'swift', - 'source' => \realpath(__DIR__.'/../sdks/server-swift'), + 'source' => \realpath(__DIR__ . '/../sdks/server-swift'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-swift.git', 'gitRepoName' => 'sdk-for-swift', 'gitUserName' => 'appwrite', @@ -442,7 +442,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_SERVER, 'prism' => 'graphql', - 'source' => \realpath(__DIR__.'/../sdks/server-graphql'), + 'source' => \realpath(__DIR__ . '/../sdks/server-graphql'), 'gitUrl' => '', 'gitRepoName' => '', 'gitUserName' => '', @@ -461,7 +461,7 @@ return [ 'hidden' => true, 'family' => APP_PLATFORM_SERVER, 'prism' => 'http', - 'source' => \realpath(__DIR__.'/../sdks/server-rest'), + 'source' => \realpath(__DIR__ . '/../sdks/server-rest'), 'gitUrl' => '', 'gitRepoName' => '', 'gitUserName' => '', diff --git a/app/config/regions.php b/app/config/regions.php index cc920bee82..0dc5fab1ed 100644 --- a/app/config/regions.php +++ b/app/config/regions.php @@ -5,5 +5,5 @@ return [ 'name' => 'Default', 'default' => true, 'disabled' => false, - ], + ] ]; diff --git a/app/config/roles.php b/app/config/roles.php index cf1827e25e..4bc85f7a28 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -25,7 +25,7 @@ $member = [ 'providers.write', 'providers.read', 'messages.write', - 'messages.read', + 'messages.read' ]; $admins = [ @@ -64,7 +64,7 @@ $admins = [ 'providers.write', 'providers.read', 'messages.write', - 'messages.read', + 'messages.read' ]; return [ diff --git a/app/config/runtimes.php b/app/config/runtimes.php index d249946d05..c24aaa109e 100644 --- a/app/config/runtimes.php +++ b/app/config/runtimes.php @@ -4,8 +4,8 @@ * List of Appwrite Cloud Functions supported runtimes */ -use Appwrite\Runtimes\Runtimes; use Utopia\App; +use Appwrite\Runtimes\Runtimes; $runtimes = new Runtimes('v2'); diff --git a/app/config/scopes.php b/app/config/scopes.php index 6dbc19d4aa..cf00654b1e 100644 --- a/app/config/scopes.php +++ b/app/config/scopes.php @@ -37,7 +37,7 @@ return [ // List of publicly visible scopes 'indexes.write' => [ 'description' => 'Access to create, update, and delete your project\'s database collection\'s indexes', ], - 'documents.read' => [ + 'documents.read' => [ 'description' => 'Access to read your project\'s database documents', ], 'documents.write' => [ @@ -111,5 +111,5 @@ return [ // List of publicly visible scopes ], 'targets.write' => [ 'description' => 'Access to create, update, and delete your project\'s targets', - ], + ] ]; diff --git a/app/config/services.php b/app/config/services.php index ee879eff94..f80431f784 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -66,8 +66,8 @@ return [ 'optional' => true, 'icon' => '/images/services/databases.png', 'globalAttributes' => [ - 'databaseId', - ], + 'databaseId' + ] ], 'locale' => [ 'key' => 'locale', @@ -237,5 +237,5 @@ return [ 'tests' => false, 'optional' => true, 'icon' => '/images/services/messaging.png', - ], + ] ]; diff --git a/app/config/usage.php b/app/config/usage.php index a0d3f9f725..2179bcce54 100644 --- a/app/config/usage.php +++ b/app/config/usage.php @@ -1,24 +1,24 @@ [ - 'period' => '1h', - 'limit' => 24, - 'factor' => 3600, - ], - '7d' => [ - 'period' => '1d', - 'limit' => 7, - 'factor' => 86400, - ], - '30d' => [ - 'period' => '1d', - 'limit' => 30, - 'factor' => 86400, - ], - '90d' => [ - 'period' => '1d', - 'limit' => 90, - 'factor' => 86400, - ], + '24h' => [ + 'period' => '1h', + 'limit' => 24, + 'factor' => 3600, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + 'factor' => 86400, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + 'factor' => 86400, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + 'factor' => 86400, + ], ]; diff --git a/app/config/variables.php b/app/config/variables.php index 136ecec5de..c04ba339e5 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -14,7 +14,7 @@ return [ 'default' => 'production', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_LOCALE', @@ -23,7 +23,7 @@ return [ 'default' => 'en', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_OPTIONS_ABUSE', @@ -32,7 +32,7 @@ return [ 'default' => 'enabled', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_OPTIONS_FORCE_HTTPS', @@ -41,7 +41,7 @@ return [ 'default' => 'disabled', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_OPENSSL_KEY_V1', @@ -50,7 +50,7 @@ return [ 'default' => 'your-secret-key', 'required' => true, 'question' => 'Choose a secret API key, make sure to make a backup of your key in a secure location', - 'filter' => 'token', + 'filter' => 'token' ], [ 'name' => '_APP_DOMAIN', @@ -59,7 +59,7 @@ return [ 'default' => 'localhost', 'required' => true, 'question' => 'Enter your Appwrite hostname', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_DOMAIN_TARGET', @@ -67,8 +67,8 @@ return [ 'introduction' => '', 'default' => 'localhost', 'required' => true, - 'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.'.PHP_EOL.'You can use the same value as used for the Appwrite hostname.', - 'filter' => 'domainTarget', + 'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.' . PHP_EOL . 'You can use the same value as used for the Appwrite hostname.', + 'filter' => 'domainTarget' ], [ 'name' => '_APP_CONSOLE_WHITELIST_ROOT', @@ -77,7 +77,7 @@ return [ 'default' => 'enabled', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_CONSOLE_WHITELIST_EMAILS', @@ -86,7 +86,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], // [ // 'name' => '_APP_CONSOLE_WHITELIST_DOMAINS', @@ -103,7 +103,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_CONSOLE_ROOT_SESSION', @@ -112,7 +112,7 @@ return [ 'default' => 'disabled', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_SYSTEM_EMAIL_NAME', @@ -121,7 +121,7 @@ return [ 'default' => 'Appwrite', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_SYSTEM_EMAIL_ADDRESS', @@ -130,7 +130,7 @@ return [ 'default' => 'team@appwrite.io', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_SYSTEM_RESPONSE_FORMAT', @@ -139,7 +139,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_SYSTEM_SECURITY_EMAIL_ADDRESS', @@ -148,7 +148,7 @@ return [ 'default' => 'certs@appwrite.io', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_USAGE_STATS', @@ -157,7 +157,7 @@ return [ 'default' => 'enabled', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_LOGGING_PROVIDER', @@ -166,7 +166,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_LOGGING_CONFIG', @@ -175,7 +175,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_USAGE_AGGREGATION_INTERVAL', @@ -184,7 +184,7 @@ return [ 'default' => '30', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_USAGE_TIMESERIES_INTERVAL', @@ -193,7 +193,7 @@ return [ 'default' => '30', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_USAGE_DATABASE_INTERVAL', @@ -202,7 +202,7 @@ return [ 'default' => '900', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_WORKER_PER_CORE', @@ -211,7 +211,7 @@ return [ 'default' => 6, 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_CONSOLE_INVITES', @@ -220,7 +220,7 @@ return [ 'default' => 'enabled', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], ], ], @@ -235,7 +235,7 @@ return [ 'default' => 'redis', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_REDIS_PORT', @@ -244,7 +244,7 @@ return [ 'default' => '6379', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_REDIS_USER', @@ -253,7 +253,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_REDIS_PASS', @@ -262,7 +262,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], ], ], @@ -277,7 +277,7 @@ return [ 'default' => 'mariadb', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_DB_PORT', @@ -286,7 +286,7 @@ return [ 'default' => '3306', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_DB_SCHEMA', @@ -295,7 +295,7 @@ return [ 'default' => 'appwrite', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_DB_USER', @@ -304,7 +304,7 @@ return [ 'default' => 'user', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_DB_PASS', @@ -313,7 +313,7 @@ return [ 'default' => 'password', 'required' => false, 'question' => '', - 'filter' => 'password', + 'filter' => 'password' ], [ 'name' => '_APP_DB_ROOT_PASS', @@ -322,7 +322,7 @@ return [ 'default' => 'rootsecretpassword', 'required' => false, 'question' => '', - 'filter' => 'password', + 'filter' => 'password' ], [ 'name' => '_APP_CONNECTIONS_MAX', @@ -331,26 +331,26 @@ return [ 'default' => 251, 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], - // [ - // 'name' => '_APP_CONNECTIONS_DB_PROJECT', - // 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.', - // 'introduction' => 'TBD', - // 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', - // 'required' => true, - // 'question' => '', - // 'filter' => '' - // ], - // [ - // 'name' => '_APP_CONNECTIONS_DB_CONSOLE', - // 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.', - // 'introduction' => 'TBD', - // 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', - // 'required' => true, - // 'question' => '', - // 'filter' => '' - // ] +// [ +// 'name' => '_APP_CONNECTIONS_DB_PROJECT', +// 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.', +// 'introduction' => 'TBD', +// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', +// 'required' => true, +// 'question' => '', +// 'filter' => '' +// ], +// [ +// 'name' => '_APP_CONNECTIONS_DB_CONSOLE', +// 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.', +// 'introduction' => 'TBD', +// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', +// 'required' => true, +// 'question' => '', +// 'filter' => '' +// ] ], ], [ @@ -364,7 +364,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_SMTP_PORT', @@ -373,7 +373,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_SMTP_SECURE', @@ -382,7 +382,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_SMTP_USERNAME', @@ -391,7 +391,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_SMTP_PASSWORD', @@ -400,7 +400,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], ], ], @@ -415,7 +415,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_SMS_FROM', @@ -424,7 +424,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], ], ], @@ -439,7 +439,7 @@ return [ 'default' => '30000000', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_STORAGE_PREVIEW_LIMIT', @@ -448,7 +448,7 @@ return [ 'default' => '20000000', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_STORAGE_ANTIVIRUS', @@ -457,7 +457,7 @@ return [ 'default' => 'disabled', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_STORAGE_ANTIVIRUS_HOST', @@ -466,7 +466,7 @@ return [ 'default' => 'clamav', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_STORAGE_ANTIVIRUS_PORT', @@ -475,7 +475,7 @@ return [ 'default' => '3310', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_CONNECTIONS_STORAGE', @@ -666,7 +666,7 @@ return [ 'default' => '30000000', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_TIMEOUT', @@ -675,7 +675,7 @@ return [ 'default' => '900', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_BUILD_TIMEOUT', @@ -684,7 +684,7 @@ return [ 'default' => '900', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_CONTAINERS', @@ -693,7 +693,7 @@ return [ 'default' => '10', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_CPUS', @@ -702,7 +702,7 @@ return [ 'default' => '0', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_MEMORY', @@ -711,7 +711,7 @@ return [ 'default' => '0', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_MEMORY_SWAP', @@ -720,16 +720,16 @@ return [ 'default' => '0', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_RUNTIMES', - 'description' => "This option allows you to enable or disable runtime environments for cloud functions. Disable unused runtimes to save disk space.\n\nTo enable cloud function runtimes, pass a list of enabled environments separated by a comma.\n\nCurrently, supported environments are: ".\implode(', ', \array_keys(Config::getParam('runtimes'))), + 'description' => "This option allows you to enable or disable runtime environments for cloud functions. Disable unused runtimes to save disk space.\n\nTo enable cloud function runtimes, pass a list of enabled environments separated by a comma.\n\nCurrently, supported environments are: " . \implode(', ', \array_keys(Config::getParam('runtimes'))), 'introduction' => '0.8.0', 'default' => 'node-16.0,php-8.0,python-3.9,ruby-3.0', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_EXECUTOR_SECRET', @@ -738,7 +738,7 @@ return [ 'default' => 'your-secret-key', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_EXECUTOR_HOST', @@ -747,7 +747,7 @@ return [ 'default' => 'http://appwrite-executor/v1', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_EXECUTOR_RUNTIME_NETWORK', @@ -756,7 +756,7 @@ return [ 'default' => 'appwrite_runtimes', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_ENVS', @@ -765,7 +765,7 @@ return [ 'default' => 'node-16.0,php-7.4,python-3.9,ruby-3.0', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_INACTIVE_THRESHOLD', @@ -774,7 +774,7 @@ return [ 'default' => '60', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => 'DOCKERHUB_PULL_USERNAME', @@ -783,7 +783,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => 'DOCKERHUB_PULL_PASSWORD', @@ -792,7 +792,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => 'DOCKERHUB_PULL_EMAIL', @@ -801,7 +801,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => 'OPEN_RUNTIMES_NETWORK', @@ -810,7 +810,7 @@ return [ 'default' => 'appwrite_runtimes', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_RUNTIMES_NETWORK', @@ -819,7 +819,7 @@ return [ 'default' => 'runtimes', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_DOCKER_HUB_USERNAME', @@ -828,7 +828,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_DOCKER_HUB_PASSWORD', @@ -837,7 +837,7 @@ return [ 'default' => '', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_FUNCTIONS_MAINTENANCE_INTERVAL', @@ -846,7 +846,7 @@ return [ 'default' => '60', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], ], ], @@ -861,7 +861,7 @@ return [ 'default' => '86400', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_MAINTENANCE_RETENTION_CACHE', @@ -870,7 +870,7 @@ return [ 'default' => '2592000', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_MAINTENANCE_RETENTION_EXECUTION', @@ -879,7 +879,7 @@ return [ 'default' => '1209600', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_MAINTENANCE_RETENTION_AUDIT', @@ -888,7 +888,7 @@ return [ 'default' => '1209600', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_MAINTENANCE_RETENTION_ABUSE', @@ -897,7 +897,7 @@ return [ 'default' => '86400', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_MAINTENANCE_RETENTION_USAGE_HOURLY', @@ -906,7 +906,7 @@ return [ 'default' => '8640000', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_MAINTENANCE_RETENTION_SCHEDULES', @@ -915,8 +915,8 @@ return [ 'default' => '86400', 'required' => false, 'question' => '', - 'filter' => '', - ], + 'filter' => '' + ] ], ], [ @@ -930,7 +930,7 @@ return [ 'default' => '10', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_GRAPHQL_MAX_COMPLEXITY', @@ -939,7 +939,7 @@ return [ 'default' => '250', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], [ 'name' => '_APP_GRAPHQL_MAX_DEPTH', @@ -948,7 +948,7 @@ return [ 'default' => '3', 'required' => false, 'question' => '', - 'filter' => '', + 'filter' => '' ], ], ], diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 8f9fc34635..46acd2efdb 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -4,9 +4,6 @@ use Ahc\Jwt\JWT; use Appwrite\Auth\Auth; use Appwrite\Auth\OAuth2\Exception as OAuth2Exception; use Appwrite\Auth\Validator\Password; -use Appwrite\Auth\Validator\PasswordDictionary; -use Appwrite\Auth\Validator\PasswordHistory; -use Appwrite\Auth\Validator\PersonalData; use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; use Appwrite\Event\Event; @@ -14,11 +11,16 @@ use Appwrite\Event\Mail; use Appwrite\Event\Phone as EventPhone; use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; +use Utopia\Validator\Host; +use Utopia\Validator\URL; use Appwrite\OpenSSL\OpenSSL; use Appwrite\Template\Template; use Appwrite\URL\URL as URLParser; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Database\Validator\Queries\Identities; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use MaxMind\Db\Reader; @@ -26,25 +28,23 @@ use Utopia\App; use Utopia\Audit\Audit as EventAudit; use Utopia\Config\Config; use Utopia\Database\Database; -use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\DateTime; use Utopia\Database\Exception\Duplicate; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; -use Utopia\Validator\Host; use Utopia\Validator\Text; -use Utopia\Validator\URL; use Utopia\Validator\WhiteList; +use Appwrite\Auth\Validator\PasswordHistory; +use Appwrite\Auth\Validator\PasswordDictionary; +use Appwrite\Auth\Validator\PersonalData; $oauthDefaultSuccess = '/auth/oauth2/success'; $oauthDefaultFailure = '/auth/oauth2/failure'; @@ -77,19 +77,20 @@ App::post('/v1/account/invite') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $email, string $password, string $name, string $code, Request $request, Response $response, Document $project, Database $dbForProject, Event $events) { + if ($project->getId() !== 'console') { throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN); } $email = \strtolower($email); - $whitelistCodes = (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null)) : []; + $whitelistCodes = (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null)) : []; if (empty($whitelistCodes)) { throw new Exception(Exception::GENERAL_CODES_DISABLED); } - if (! empty($whitelistCodes) && ! \in_array($code, $whitelistCodes)) { + if (!empty($whitelistCodes) && !\in_array($code, $whitelistCodes)) { throw new Exception(Exception::USER_INVALID_CODE); } @@ -105,7 +106,7 @@ App::post('/v1/account/invite') try { $userId = $userId == 'unique()' ? ID::unique() : $userId; - $user = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([ + $user = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([ '$id' => $userId, '$permissions' => [ Permission::read(Role::any()), @@ -126,7 +127,7 @@ App::post('/v1/account/invite') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]), + 'search' => implode(' ', [$userId, $email, $name]) ]))); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); @@ -176,11 +177,11 @@ App::post('/v1/account') $whitelistEmails = $project->getAttribute('authWhitelistEmails'); $whitelistIPs = $project->getAttribute('authWhitelistIPs'); - if (! empty($whitelistEmails) && ! \in_array($email, $whitelistEmails) && ! \in_array(strtoupper($email), $whitelistEmails)) { + if (!empty($whitelistEmails) && !\in_array($email, $whitelistEmails) && !\in_array(strtoupper($email), $whitelistEmails)) { throw new Exception(Exception::USER_EMAIL_NOT_WHITELISTED); } - if (! empty($whitelistIPs) && ! \in_array($request->getIP(), $whitelistIPs)) { + if (!empty($whitelistIPs) && !\in_array($request->getIP(), $whitelistIPs)) { throw new Exception(Exception::USER_IP_NOT_WHITELISTED); } } @@ -199,13 +200,13 @@ App::post('/v1/account') $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) { $personalDataValidator = new PersonalData($userId, $email, $name, null); - if (! $personalDataValidator->isValid($password)) { + if (!$personalDataValidator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA); } } @@ -239,7 +240,7 @@ App::post('/v1/account') 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), // Add this here to make sure it's returned in the response ]); - Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); } @@ -285,6 +286,7 @@ App::post('/v1/account/sessions/email') ->inject('geodb') ->inject('events') ->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) { + $email = \strtolower($email); $protocol = $request->getProtocol(); @@ -292,7 +294,7 @@ App::post('/v1/account/sessions/email') Query::equal('email', [$email]), ]); - if (! $profile || empty($profile->getAttribute('passwordUpdate')) || ! Auth::passwordVerify($password, $profile->getAttribute('password'), $profile->getAttribute('hash'), $profile->getAttribute('hashOptions'))) { + if (!$profile || empty($profile->getAttribute('passwordUpdate')) || !Auth::passwordVerify($password, $profile->getAttribute('password'), $profile->getAttribute('hash'), $profile->getAttribute('hashOptions'))) { throw new Exception(Exception::USER_INVALID_CREDENTIALS); } @@ -344,26 +346,31 @@ App::post('/v1/account/sessions/email') Permission::delete(Role::user($user->getId())), ])); - if (! Config::getParam('domainVerification')) { + + if (!Config::getParam('domainVerification')) { $response - ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); + ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])) + ; } $response - ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED); + ->setStatusCode(Response::STATUS_CODE_CREATED) + ; - $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', $expire); + ->setAttribute('expire', $expire) + ; $events ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()); + ->setParam('sessionId', $session->getId()) + ; $response->dynamic($session, Response::MODEL_SESSION); }); @@ -371,7 +378,7 @@ App::post('/v1/account/sessions/email') App::get('/v1/account/sessions/oauth2/:provider') ->desc('Create OAuth2 Session') ->groups(['api', 'account']) - ->label('error', __DIR__.'/../../views/general/error.phtml') + ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('scope', 'public') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') @@ -382,47 +389,48 @@ App::get('/v1/account/sessions/oauth2/:provider') ->label('sdk.methodType', 'webAuth') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 Provider. Currently, supported providers are: '.\implode(', ', \array_keys(\array_filter(Config::getParam('authProviders'), fn ($node) => (! $node['mock'])))).'.') - ->param('success', '', fn ($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. 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']) - ->param('failure', '', fn ($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. 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']) - ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' scopes are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long.', true) + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('authProviders'), fn($node) => (!$node['mock'])))) . '.') + ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. 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']) + ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. 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']) + ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) ->inject('request') ->inject('response') ->inject('project') ->action(function (string $provider, string $success, string $failure, array $scopes, Request $request, Response $response, Document $project) use ($oauthDefaultSuccess, $oauthDefaultFailure) { + $protocol = $request->getProtocol(); - $callback = $protocol.'://'.$request->getHostname().'/v1/account/sessions/oauth2/callback/'.$provider.'/'.$project->getId(); - $providerEnabled = $project->getAttribute('authProviders', [])[$provider.'Enabled'] ?? false; + $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); + $providerEnabled = $project->getAttribute('authProviders', [])[$provider . 'Enabled'] ?? false; - if (! $providerEnabled) { - throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your '.APP_NAME.' console to continue.'); + if (!$providerEnabled) { + throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your ' . APP_NAME . ' console to continue.'); } - $appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}'; + $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; - if (! empty($appSecret) && isset($appSecret['version'])) { - $key = App::getEnv('_APP_OPENSSL_KEY_V'.$appSecret['version']); + if (!empty($appSecret) && isset($appSecret['version'])) { + $key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']); $appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key, 0, \hex2bin($appSecret['iv']), \hex2bin($appSecret['tag'])); } if (empty($appId) || empty($appSecret)) { - throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please configure the provider app ID and app secret key from your '.APP_NAME.' console to continue.'); + throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.'); } - $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); + $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); - if (! \class_exists($className)) { + if (!\class_exists($className)) { throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } if (empty($success)) { - $success = $protocol.'://'.$request->getHostname().$oauthDefaultSuccess; + $success = $protocol . '://' . $request->getHostname() . $oauthDefaultSuccess; } if (empty($failure)) { - $failure = $protocol.'://'.$request->getHostname().$oauthDefaultFailure; + $failure = $protocol . '://' . $request->getHostname() . $oauthDefaultFailure; } $oauth2 = new $className($appId, $appSecret, $callback, ['success' => $success, 'failure' => $failure], $scopes); @@ -436,7 +444,7 @@ App::get('/v1/account/sessions/oauth2/:provider') App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->desc('OAuth2 Callback') ->groups(['account']) - ->label('error', __DIR__.'/../../views/general/error.phtml') + ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('scope', 'public') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') @@ -448,26 +456,27 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->inject('request') ->inject('response') ->action(function (string $projectId, string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response) { + $domain = $request->getHostname(); $protocol = $request->getProtocol(); $response ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') ->addHeader('Pragma', 'no-cache') - ->redirect($protocol.'://'.$domain.'/v1/account/sessions/oauth2/'.$provider.'/redirect?' - .\http_build_query([ + ->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?' + . \http_build_query([ 'project' => $projectId, 'code' => $code, 'state' => $state, 'error' => $error, - 'error_description' => $error_description, + 'error_description' => $error_description ])); }); App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->desc('OAuth2 Callback') ->groups(['account']) - ->label('error', __DIR__.'/../../views/general/error.phtml') + ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('scope', 'public') ->label('origin', '*') ->label('docs', false) @@ -480,26 +489,27 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->inject('request') ->inject('response') ->action(function (string $projectId, string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response) { + $domain = $request->getHostname(); $protocol = $request->getProtocol(); $response ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') ->addHeader('Pragma', 'no-cache') - ->redirect($protocol.'://'.$domain.'/v1/account/sessions/oauth2/'.$provider.'/redirect?' - .\http_build_query([ + ->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?' + . \http_build_query([ 'project' => $projectId, 'code' => $code, 'state' => $state, 'error' => $error, - 'error_description' => $error_description, + 'error_description' => $error_description ])); }); App::get('/v1/account/sessions/oauth2/:provider/redirect') ->desc('OAuth2 Redirect') ->groups(['api', 'account', 'session']) - ->label('error', __DIR__.'/../../views/general/error.phtml') + ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('audits.event', 'session.create') @@ -521,17 +531,18 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->inject('geodb') ->inject('events') ->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $events) use ($oauthDefaultSuccess) { + $protocol = $request->getProtocol(); - $callback = $protocol.'://'.$request->getHostname().'/v1/account/sessions/oauth2/callback/'.$provider.'/'.$project->getId(); + $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); $defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => '']; $validateURL = new URL(); - $appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}'; - $providerEnabled = $project->getAttribute('authProviders', [])[$provider.'Enabled'] ?? false; + $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $providerEnabled = $project->getAttribute('authProviders', [])[$provider . 'Enabled'] ?? false; - $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); + $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); - if (! \class_exists($className)) { + if (!\class_exists($className)) { throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } @@ -541,7 +552,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') /** @var Appwrite\Auth\OAuth2 $oauth2 */ $oauth2 = new $className($appId, $appSecret, $callback); - if (! empty($state)) { + if (!empty($state)) { try { $state = \array_merge($defaultState, $oauth2->parseState($state)); } catch (\Exception $exception) { @@ -551,25 +562,25 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $state = $defaultState; } - if (! $validateURL->isValid($state['success'])) { + if (!$validateURL->isValid($state['success'])) { throw new Exception(Exception::PROJECT_INVALID_SUCCESS_URL); } - if (! empty($state['failure']) && ! $validateURL->isValid($state['failure'])) { + if (!empty($state['failure']) && !$validateURL->isValid($state['failure'])) { throw new Exception(Exception::PROJECT_INVALID_FAILURE_URL); } $failure = []; - if (! empty($state['failure'])) { + if (!empty($state['failure'])) { $failure = URLParser::parse($state['failure']); } $failureRedirect = (function (string $type, ?string $message = null, ?int $code = null) use ($failure, $response) { $exception = new Exception($type, $message, $code); - if (! empty($failure)) { + if (!empty($failure)) { $query = URLParser::parseQuery($failure['query']); $query['error'] = json_encode([ 'message' => $exception->getMessage(), 'type' => $exception->getType(), - 'code' => ! \is_null($code) ? $code : $exception->getCode(), + 'code' => !\is_null($code) ? $code : $exception->getCode(), ]); $failure['query'] = URLParser::unparseQuery($query); $response->redirect(URLParser::unparse($failure), 301); @@ -578,14 +589,14 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') throw $exception; }); - if (! $providerEnabled) { - $failureRedirect(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your '.APP_NAME.' console to continue.'); + if (!$providerEnabled) { + $failureRedirect(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your ' . APP_NAME . ' console to continue.'); } - if (! empty($error)) { - $message = 'The '.$providerName.' OAuth2 provider returned an error: '.$error; - if (! empty($error_description)) { - $message .= ': '.$error_description; + if (!empty($error)) { + $message = 'The ' . $providerName . ' OAuth2 provider returned an error: ' . $error; + if (!empty($error_description)) { + $message .= ': ' . $error_description; } $failureRedirect(Exception::USER_OAUTH2_PROVIDER_ERROR, $message); } @@ -594,8 +605,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $failureRedirect(Exception::USER_OAUTH2_PROVIDER_ERROR, 'Missing OAuth2 code. Please contact the Appwrite team for additional support.'); } - if (! empty($appSecret) && isset($appSecret['version'])) { - $key = App::getEnv('_APP_OPENSSL_KEY_V'.$appSecret['version']); + if (!empty($appSecret) && isset($appSecret['version'])) { + $key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']); $appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key, 0, \hex2bin($appSecret['iv']), \hex2bin($appSecret['tag'])); } @@ -610,7 +621,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } catch (OAuth2Exception $ex) { $failureRedirect( $ex->getType(), - 'Failed to obtain access token. The '.$providerName.' OAuth2 provider returned an error: '.$ex->getMessage(), + 'Failed to obtain access token. The ' . $providerName . ' OAuth2 provider returned an error: ' . $ex->getMessage(), $ex->getCode(), ); } @@ -624,14 +635,14 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $email = $oauth2->getUserEmail($accessToken); // Check if this identity is connected to a different user - if (! $user->isEmpty()) { + if (!$user->isEmpty()) { $userId = $user->getId(); $identitiesWithMatchingEmail = $dbForProject->find('identities', [ Query::equal('providerEmail', [$email]), Query::notEqual('userId', $userId), ]); - if (! empty($identitiesWithMatchingEmail)) { + if (!empty($identitiesWithMatchingEmail)) { throw new Exception(Exception::USER_ALREADY_EXISTS); } } @@ -642,7 +653,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') if ($current) { // Delete current session of new one. $currentDocument = $dbForProject->getDocument('sessions', $current); - if (! $currentDocument->isEmpty()) { + if (!$currentDocument->isEmpty()) { $dbForProject->deleteDocument('sessions', $currentDocument->getId()); $dbForProject->deleteCachedDocument('users', $user->getId()); } @@ -653,7 +664,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') Query::equal('provider', [$provider]), Query::equal('providerUid', [$oauth2ID]), ]); - if ($session !== false && ! $session->isEmpty()) { + if ($session !== false && !$session->isEmpty()) { $user->setAttributes($dbForProject->getDocument('users', $session->getAttribute('userId'))->getArrayCopy()); } } @@ -671,7 +682,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $userWithEmail = $dbForProject->findOne('users', [ Query::equal('email', [$email]), ]); - if ($userWithEmail !== false && ! $userWithEmail->isEmpty()) { + if ($userWithEmail !== false && !$userWithEmail->isEmpty()) { $user->setAttributes($userWithEmail->getArrayCopy()); } @@ -682,7 +693,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') Query::equal('providerUid', [$oauth2ID]), ]); - if ($identity !== false && ! $identity->isEmpty()) { + if ($identity !== false && !$identity->isEmpty()) { $user = $dbForProject->getDocument('users', $identity->getAttribute('userId')); } } @@ -702,7 +713,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -729,9 +740,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]), + 'search' => implode(' ', [$userId, $email, $name]) ]); - Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); } catch (Duplicate $th) { $failureRedirect(Exception::USER_ALREADY_EXISTS); } @@ -758,7 +769,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') Query::equal('providerEmail', [$email]), Query::notEqual('userId', $user->getId()), ]); - if (! empty($identitiesWithMatchingEmail)) { + if (!empty($identitiesWithMatchingEmail)) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -776,13 +787,13 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'providerEmail' => $email, 'providerAccessToken' => $accessToken, 'providerRefreshToken' => $refreshToken, - 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry), + 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry), ])); } else { $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry)); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry)); $dbForProject->updateDocument('identities', $identity->getId(), $identity); } @@ -801,7 +812,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'providerUid' => $oauth2ID, 'providerAccessToken' => $accessToken, 'providerRefreshToken' => $refreshToken, - 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry), + 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry), 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'userAgent' => $request->getUserAgent('UNKNOWN'), 'ip' => $request->getIP(), @@ -817,7 +828,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } $user - ->setAttribute('status', true); + ->setAttribute('status', true) + ; Authorization::setRole(Role::user($user->getId())->toString()); @@ -836,9 +848,10 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()) - ->setPayload($response->output($session, Response::MODEL_SESSION)); + ->setPayload($response->output($session, Response::MODEL_SESSION)) + ; - if (! Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } @@ -857,9 +870,10 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $response ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') ->addHeader('Pragma', 'no-cache') - ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->redirect($state['success']); + ->redirect($state['success']) + ; }); App::get('/v1/account/identities') @@ -875,11 +889,12 @@ App::get('/v1/account/identities') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_IDENTITY_LIST) ->label('sdk.offline.model', '/account/identities') - ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Identities::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Identities::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('user') ->inject('dbForProject') ->action(function (array $queries, Response $response, Document $user, Database $dbForProject) { + $queries = Query::parseQueries($queries); $queries[] = Query::equal('userInternalId', [$user->getInternalId()]); @@ -929,6 +944,7 @@ App::delete('/v1/account/identities/:identityId') ->inject('response') ->inject('dbForProject') ->action(function (string $identityId, Response $response, Database $dbForProject) { + $identity = $dbForProject->getDocument('identities', $identityId); if ($identity->isEmpty()) { @@ -959,7 +975,7 @@ App::post('/v1/account/sessions/magic-url') ->label('abuse-key', 'url:{url},email:{param-email}') ->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('email', '', new Email(), 'User email.') - ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) + ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) ->inject('request') ->inject('response') ->inject('user') @@ -969,6 +985,7 @@ App::post('/v1/account/sessions/magic-url') ->inject('events') ->inject('mails') ->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $events, Mail $mails) { + if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled'); } @@ -978,7 +995,7 @@ App::post('/v1/account/sessions/magic-url') $isAppUser = Auth::isAppUser($roles); $result = $dbForProject->findOne('users', [Query::equal('email', [$email])]); - if ($result !== false && ! $result->isEmpty()) { + if ($result !== false && !$result->isEmpty()) { $user->setAttributes($result->getArrayCopy()); } else { $limit = $project->getAttribute('auths', [])['limit'] ?? 0; @@ -995,7 +1012,7 @@ App::post('/v1/account/sessions/magic-url') $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -1021,7 +1038,7 @@ App::post('/v1/account/sessions/magic-url') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email]), + 'search' => implode(' ', [$userId, $email]) ]); Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); @@ -1053,7 +1070,7 @@ App::post('/v1/account/sessions/magic-url') $dbForProject->deleteCachedDocument('users', $user->getId()); if (empty($url)) { - $url = $request->getProtocol().'://'.$request->getHostname().'/auth/magic-url'; + $url = $request->getProtocol() . '://' . $request->getHostname() . '/auth/magic-url'; } $url = Template::parseURL($url); @@ -1061,12 +1078,12 @@ App::post('/v1/account/sessions/magic-url') $url = Template::unParseURL($url); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $project->getAttribute('name')); - $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); - $subject = $locale->getText('emails.magicSession.subject'); + $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $subject = $locale->getText("emails.magicSession.subject"); $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; - $customTemplate = $project->getAttribute('templates', [])['email.magicSession-'.$locale->default] ?? []; - if ($smtpEnabled && ! empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['email.magicSession-' . $locale->default] ?? []; + if ($smtpEnabled && !empty($customTemplate)) { $body = $customTemplate['message'] ?? $body; $subject = $customTemplate['subject'] ?? $subject; $from = $customTemplate['senderName'] ?? $from; @@ -1074,13 +1091,13 @@ App::post('/v1/account/sessions/magic-url') $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText('emails.magicSession.hello')) + ->setParam('{{hello}}', $locale->getText("emails.magicSession.hello")) ->setParam('{{name}}', '') - ->setParam('{{body}}', $locale->getText('emails.magicSession.body')) + ->setParam('{{body}}', $locale->getText("emails.magicSession.body")) ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText('emails.magicSession.footer')) - ->setParam('{{thanks}}', $locale->getText('emails.magicSession.thanks')) - ->setParam('{{signature}}', $locale->getText('emails.magicSession.signature')) + ->setParam('{{footer}}', $locale->getText("emails.magicSession.footer")) + ->setParam('{{thanks}}', $locale->getText("emails.magicSession.thanks")) + ->setParam('{{signature}}', $locale->getText("emails.magicSession.signature")) ->setParam('{{project}}', $project->getAttribute('name')) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -1094,7 +1111,8 @@ App::post('/v1/account/sessions/magic-url') ->setBody($body) ->setFrom($from) ->setRecipient($user->getAttribute('email')) - ->trigger(); + ->trigger() + ; $events->setPayload( $response->output( @@ -1108,7 +1126,8 @@ App::post('/v1/account/sessions/magic-url') $response ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($token, Response::MODEL_TOKEN); + ->dynamic($token, Response::MODEL_TOKEN) + ; }); App::put('/v1/account/sessions/magic-url') @@ -1139,8 +1158,10 @@ App::put('/v1/account/sessions/magic-url') ->inject('geodb') ->inject('events') ->action(function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) { + /** @var Utopia\Database\Document $user */ - $userFromRequest = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); + + $userFromRequest = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); if ($userFromRequest->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -1148,7 +1169,7 @@ App::put('/v1/account/sessions/magic-url') $token = Auth::tokenVerify($userFromRequest->getAttribute('tokens', []), Auth::TOKEN_TYPE_MAGIC_URL, $secret); - if (! $token) { + if (!$token) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -1206,25 +1227,28 @@ App::put('/v1/account/sessions/magic-url') $events ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()); + ->setParam('sessionId', $session->getId()) + ; - if (! Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } $protocol = $request->getProtocol(); $response - ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED); + ->setStatusCode(Response::STATUS_CODE_CREATED) + ; - $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', $expire); + ->setAttribute('expire', $expire) + ; $response->dynamic($session, Response::MODEL_SESSION); }); @@ -1257,6 +1281,7 @@ App::post('/v1/account/sessions/phone') ->inject('messaging') ->inject('locale') ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, EventPhone $messaging, Locale $locale) { + if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -1266,7 +1291,7 @@ App::post('/v1/account/sessions/phone') $isAppUser = Auth::isAppUser($roles); $result = $dbForProject->findOne('users', [Query::equal('phone', [$phone])]); - if ($result !== false && ! $result->isEmpty()) { + if ($result !== false && !$result->isEmpty()) { $user->setAttributes($result->getArrayCopy()); } else { $limit = $project->getAttribute('auths', [])['limit'] ?? 0; @@ -1300,7 +1325,7 @@ App::post('/v1/account/sessions/phone') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $phone]), + 'search' => implode(' ', [$userId, $phone]) ]); Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); @@ -1331,10 +1356,10 @@ App::post('/v1/account/sessions/phone') $dbForProject->deleteCachedDocument('users', $user->getId()); - $message = Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl'); + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl'); - $customTemplate = $project->getAttribute('templates', [])['sms.login-'.$locale->default] ?? []; - if (! empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['sms.login-' . $locale->default] ?? []; + if (!empty($customTemplate)) { $message = $customTemplate['message'] ?? $message; } @@ -1358,7 +1383,8 @@ App::post('/v1/account/sessions/phone') $response ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($token, Response::MODEL_TOKEN); + ->dynamic($token, Response::MODEL_TOKEN) + ; }); App::put('/v1/account/sessions/phone') @@ -1386,7 +1412,8 @@ App::put('/v1/account/sessions/phone') ->inject('geodb') ->inject('events') ->action(function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) { - $userFromRequest = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); + + $userFromRequest = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); if ($userFromRequest->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -1394,7 +1421,7 @@ App::put('/v1/account/sessions/phone') $token = Auth::phoneTokenVerify($userFromRequest->getAttribute('tokens', []), $secret); - if (! $token) { + if (!$token) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -1450,25 +1477,28 @@ App::put('/v1/account/sessions/phone') $events ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()); + ->setParam('sessionId', $session->getId()) + ; - if (! Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } $protocol = $request->getProtocol(); $response - ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED); + ->setStatusCode(Response::STATUS_CODE_CREATED) + ; - $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', $expire); + ->setAttribute('expire', $expire) + ; $response->dynamic($session, Response::MODEL_SESSION); }); @@ -1500,13 +1530,14 @@ App::post('/v1/account/sessions/anonymous') ->inject('geodb') ->inject('events') ->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Event $events) { + $protocol = $request->getProtocol(); if ('console' === $project->getId()) { throw new Exception(Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'Failed to create anonymous user'); } - if (! $user->isEmpty()) { + if (!$user->isEmpty()) { throw new Exception(Exception::USER_SESSION_ALREADY_EXISTS, 'Cannot create an anonymous user when logged in'); } @@ -1544,7 +1575,7 @@ App::post('/v1/account/sessions/anonymous') 'memberships' => null, 'search' => $userId, ]); - Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); // Create session token $duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; @@ -1571,33 +1602,36 @@ App::post('/v1/account/sessions/anonymous') Authorization::setRole(Role::user($user->getId())->toString()); - $session = $dbForProject->createDocument('sessions', $session->setAttribute('$permissions', [ - Permission::read(Role::user($user->getId())), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ])); + $session = $dbForProject->createDocument('sessions', $session-> setAttribute('$permissions', [ + Permission::read(Role::user($user->getId())), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ])); $dbForProject->deleteCachedDocument('users', $user->getId()); $events ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()); + ->setParam('sessionId', $session->getId()) + ; - if (! Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } $response - ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED); + ->setStatusCode(Response::STATUS_CODE_CREATED) + ; - $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', $expire); + ->setAttribute('expire', $expire) + ; $response->dynamic($session, Response::MODEL_SESSION); }); @@ -1620,6 +1654,8 @@ App::post('/v1/account/jwt') ->inject('user') ->inject('dbForProject') ->action(function (Response $response, Document $user, Database $dbForProject) { + + $sessions = $user->getAttribute('sessions', []); $current = new Document(); @@ -1638,13 +1674,13 @@ App::post('/v1/account/jwt') $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic(new Document(['jwt' => $jwt->encode([ - // 'uid' => 1, - // 'aud' => 'http://site.com', - // 'scopes' => ['user'], - // 'iss' => 'http://api.mysite.com', - 'userId' => $user->getId(), - 'sessionId' => $current->getId(), - ])]), Response::MODEL_JWT); + // 'uid' => 1, + // 'aud' => 'http://site.com', + // 'scopes' => ['user'], + // 'iss' => 'http://api.mysite.com', + 'userId' => $user->getId(), + 'sessionId' => $current->getId(), + ])]), Response::MODEL_JWT); }); App::get('/v1/account') @@ -1663,6 +1699,7 @@ App::get('/v1/account') ->inject('response') ->inject('user') ->action(function (Response $response, Document $user) { + $response->dynamic($user, Response::MODEL_ACCOUNT); }); @@ -1682,6 +1719,7 @@ App::get('/v1/account/prefs') ->inject('response') ->inject('user') ->action(function (Response $response, Document $user) { + $prefs = $user->getAttribute('prefs', []); $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); @@ -1704,12 +1742,13 @@ App::get('/v1/account/sessions') ->inject('locale') ->inject('project') ->action(function (Response $response, Document $user, Locale $locale, Document $project) { + $sessions = $user->getAttribute('sessions', []); $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $current = Auth::sessionVerify($sessions, Auth::$secret, $authDuration); foreach ($sessions as $key => $session) {/** @var Document $session */ - $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session->setAttribute('countryName', $countryName); $session->setAttribute('current', ($current == $session->getId()) ? true : false); @@ -1742,6 +1781,7 @@ App::get('/v1/account/logs') ->inject('geodb') ->inject('dbForProject') ->action(function (array $queries, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject) { + $queries = Query::parseQueries($queries); $grouped = Query::groupByType($queries); $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; @@ -1754,7 +1794,7 @@ App::get('/v1/account/logs') $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); @@ -1769,8 +1809,8 @@ App::get('/v1/account/logs') $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -1797,6 +1837,7 @@ App::get('/v1/account/targets') ->inject('response') ->inject('user') ->action(function (Response $response, Document $user) { + $targets = $user->getAttribute('targets', []); $response->dynamic(new Document([ @@ -1825,6 +1866,7 @@ App::get('/v1/account/sessions/:sessionId') ->inject('dbForProject') ->inject('project') ->action(function (?string $sessionId, Response $response, Document $user, Locale $locale, Database $dbForProject, Document $project) { + $sessions = $user->getAttribute('sessions', []); $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $sessionId = ($sessionId === 'current') @@ -1833,12 +1875,13 @@ App::get('/v1/account/sessions/:sessionId') foreach ($sessions as $session) {/** @var Document $session */ if ($sessionId == $session->getId()) { - $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', ($session->getAttribute('secret') == Auth::hash(Auth::$secret))) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', DateTime::formatTz(DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration))); + ->setAttribute('expire', DateTime::formatTz(DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration))) + ; return $response->dynamic($session, Response::MODEL_SESSION); } @@ -1864,6 +1907,7 @@ App::get('/v1/account/targets/:targetId') ->inject('response') ->inject('user') ->action(function (string $targetId, Response $response, Document $user) { + $target = $user->find('$id', $targetId, 'targets'); if (empty($target)) { @@ -1896,6 +1940,7 @@ App::patch('/v1/account/name') ->inject('dbForProject') ->inject('events') ->action(function (string $name, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) { + $user->setAttribute('name', $name); $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); @@ -1931,8 +1976,9 @@ App::patch('/v1/account/password') ->inject('dbForProject') ->inject('events') ->action(function (string $password, string $oldPassword, ?\DateTime $requestTimestamp, Response $response, Document $user, Document $project, Database $dbForProject, Event $events) { + // Check old password only if its an existing user. - if (! empty($user->getAttribute('passwordUpdate')) && ! Auth::passwordVerify($oldPassword, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password + if (!empty($user->getAttribute('passwordUpdate')) && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password throw new Exception(Exception::USER_INVALID_CREDENTIALS); } @@ -1941,7 +1987,7 @@ App::patch('/v1/account/password') $history = $user->getAttribute('passwordHistory', []); if ($historyLimit > 0) { $validator = new PasswordHistory($history, $user->getAttribute('hash'), $user->getAttribute('hashOptions')); - if (! $validator->isValid($password)) { + if (!$validator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED); } @@ -1951,7 +1997,7 @@ App::patch('/v1/account/password') if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) { $personalDataValidator = new PersonalData($user->getId(), $user->getAttribute('email'), $user->getAttribute('name'), $user->getAttribute('phone')); - if (! $personalDataValidator->isValid($password)) { + if (!$personalDataValidator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA); } } @@ -1998,8 +2044,8 @@ App::patch('/v1/account/email') $passwordUpdate = $user->getAttribute('passwordUpdate'); if ( - ! empty($passwordUpdate) && - ! Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions')) + !empty($passwordUpdate) && + !Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions')) ) { // Double check user password throw new Exception(Exception::USER_INVALID_CREDENTIALS); } @@ -2011,14 +2057,14 @@ App::patch('/v1/account/email') Query::equal('providerEmail', [$email]), Query::notEqual('userId', $user->getId()), ]); - if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) // After this user needs to confirm mail again -; + ; if (empty($passwordUpdate)) { $user @@ -2067,8 +2113,8 @@ App::patch('/v1/account/phone') $passwordUpdate = $user->getAttribute('passwordUpdate'); if ( - ! empty($passwordUpdate) && - ! Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions')) + !empty($passwordUpdate) && + !Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions')) ) { // Double check user password throw new Exception(Exception::USER_INVALID_CREDENTIALS); } @@ -2076,7 +2122,7 @@ App::patch('/v1/account/phone') $user ->setAttribute('phone', $phone) ->setAttribute('phoneVerification', false) // After this user needs to confirm phone number again -; + ; if (empty($passwordUpdate)) { $user @@ -2120,6 +2166,7 @@ App::patch('/v1/account/prefs') ->inject('dbForProject') ->inject('events') ->action(function (array $prefs, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) { + $user->setAttribute('prefs', $prefs); $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); @@ -2150,6 +2197,7 @@ App::patch('/v1/account/status') ->inject('dbForProject') ->inject('events') ->action(function (?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) { + $user->setAttribute('status', false); $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); @@ -2158,14 +2206,15 @@ App::patch('/v1/account/status') ->setParam('userId', $user->getId()) ->setPayload($response->output($user, Response::MODEL_ACCOUNT)); - if (! Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([])); } $protocol = $request->getProtocol(); $response - ->addCookie(Auth::$cookieName.'_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) - ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); + ->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) + ; $response->dynamic($user, Response::MODEL_ACCOUNT); }); @@ -2194,6 +2243,7 @@ App::delete('/v1/account/sessions/:sessionId') ->inject('events') ->inject('project') ->action(function (?string $sessionId, ?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Document $project) { + $protocol = $request->getProtocol(); $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $sessionId = ($sessionId === 'current') @@ -2215,16 +2265,19 @@ App::delete('/v1/account/sessions/:sessionId') if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too $session ->setAttribute('current', true) - ->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))); + ->setAttribute('countryName', $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))) + ; - if (! Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response - ->addHeader('X-Fallback-Cookies', \json_encode([])); + ->addHeader('X-Fallback-Cookies', \json_encode([])) + ; } $response - ->addCookie(Auth::$cookieName.'_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) - ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); + ->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) + ; } $dbForProject->deleteCachedDocument('users', $user->getId()); @@ -2232,8 +2285,8 @@ App::delete('/v1/account/sessions/:sessionId') $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()) - ->setPayload($response->output($session, Response::MODEL_SESSION)); - + ->setPayload($response->output($session, Response::MODEL_SESSION)) + ; return $response->noContent(); } } @@ -2287,12 +2340,12 @@ App::patch('/v1/account/sessions/:sessionId') $provider = $session->getAttribute('provider'); $refreshToken = $session->getAttribute('providerRefreshToken'); - $appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}'; + $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; - $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); + $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); - if (! \class_exists($className)) { + if (!\class_exists($className)) { throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } @@ -2303,7 +2356,7 @@ App::patch('/v1/account/sessions/:sessionId') $session ->setAttribute('providerAccessToken', $oauth2->getAccessToken('')) ->setAttribute('providerRefreshToken', $oauth2->getRefreshToken('')) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $oauth2->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry(''))); $dbForProject->updateDocument('sessions', $sessionId, $session); @@ -2316,7 +2369,8 @@ App::patch('/v1/account/sessions/:sessionId') $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()) - ->setPayload($response->output($session, Response::MODEL_SESSION)); + ->setPayload($response->output($session, Response::MODEL_SESSION)) + ; return $response->dynamic($session, Response::MODEL_SESSION); } @@ -2346,27 +2400,29 @@ App::delete('/v1/account/sessions') ->inject('locale') ->inject('events') ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events) { + $protocol = $request->getProtocol(); $sessions = $user->getAttribute('sessions', []); foreach ($sessions as $session) {/** @var Document $session */ $dbForProject->deleteDocument('sessions', $session->getId()); - if (! Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([])); } $session ->setAttribute('current', false) - ->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))); + ->setAttribute('countryName', $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))) + ; if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { $session->setAttribute('current', true); $session->setAttribute('expire', DateTime::addSeconds(new \DateTime($session->getCreatedAt()), Auth::TOKEN_EXPIRATION_LOGIN_LONG)); - // If current session delete the cookies too + // If current session delete the cookies too $response - ->addCookie(Auth::$cookieName.'_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); // Use current session for events. @@ -2411,6 +2467,7 @@ App::post('/v1/account/recovery') ->inject('mails') ->inject('events') ->action(function (string $email, string $url, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Mail $mails, Event $events) { + if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); } @@ -2425,7 +2482,7 @@ App::post('/v1/account/recovery') Query::equal('email', [$email]), ]); - if (! $profile) { + if (!$profile) { throw new Exception(Exception::USER_NOT_FOUND); } @@ -2466,12 +2523,12 @@ App::post('/v1/account/recovery') $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); - $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); - $subject = $locale->getText('emails.recovery.subject'); + $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $subject = $locale->getText("emails.recovery.subject"); $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; - $customTemplate = $project->getAttribute('templates', [])['email.recovery-'.$locale->default] ?? []; - if ($smtpEnabled && ! empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['email.recovery-' . $locale->default] ?? []; + if ($smtpEnabled && !empty($customTemplate)) { $body = $customTemplate['message'] ?? $body; $subject = $customTemplate['subject'] ?? $subject; $from = $customTemplate['senderName'] ?? $from; @@ -2479,13 +2536,13 @@ App::post('/v1/account/recovery') $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText('emails.recovery.hello')) + ->setParam('{{hello}}', $locale->getText("emails.recovery.hello")) ->setParam('{{name}}', $profile->getAttribute('name')) - ->setParam('{{body}}', $locale->getText('emails.recovery.body')) + ->setParam('{{body}}', $locale->getText("emails.recovery.body")) ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText('emails.recovery.footer')) - ->setParam('{{thanks}}', $locale->getText('emails.recovery.thanks')) - ->setParam('{{signature}}', $locale->getText('emails.recovery.signature')) + ->setParam('{{footer}}', $locale->getText("emails.recovery.footer")) + ->setParam('{{thanks}}', $locale->getText("emails.recovery.thanks")) + ->setParam('{{signature}}', $locale->getText("emails.recovery.signature")) ->setParam('{{project}}', $projectName) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -2494,6 +2551,7 @@ App::post('/v1/account/recovery') $body = $body->render(); + $mails ->setRecipient($profile->getAttribute('email', '')) ->setName($profile->getAttribute('name')) @@ -2501,6 +2559,7 @@ App::post('/v1/account/recovery') ->setFrom($from) ->setSubject($subject) ->trigger(); + ; $events ->setParam('userId', $profile->getId()) @@ -2509,7 +2568,8 @@ App::post('/v1/account/recovery') ->setPayload($response->output( $recovery->setAttribute('secret', $secret), Response::MODEL_TOKEN - )); + )) + ; // Hide secret for clients $recovery->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : ''); @@ -2559,7 +2619,7 @@ App::put('/v1/account/recovery') $tokens = $profile->getAttribute('tokens', []); $recovery = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_RECOVERY, $secret); - if (! $recovery) { + if (!$recovery) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -2571,7 +2631,7 @@ App::put('/v1/account/recovery') $history = $profile->getAttribute('passwordHistory', []); if ($historyLimit > 0) { $validator = new PasswordHistory($history, $profile->getAttribute('hash'), $profile->getAttribute('hashOptions')); - if (! $validator->isValid($password)) { + if (!$validator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED); } @@ -2600,7 +2660,8 @@ App::put('/v1/account/recovery') $events ->setParam('userId', $profile->getId()) - ->setParam('tokenId', $recoveryDocument->getId()); + ->setParam('tokenId', $recoveryDocument->getId()) + ; $response->dynamic($recoveryDocument, Response::MODEL_TOKEN); }); @@ -2621,7 +2682,7 @@ App::post('/v1/account/verification') ->label('sdk.response.model', Response::MODEL_TOKEN) ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},userId:{userId}') - ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page + ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page ->inject('request') ->inject('response') ->inject('project') @@ -2631,6 +2692,7 @@ App::post('/v1/account/verification') ->inject('events') ->inject('mails') ->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $events, Mail $mails) { + if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); } @@ -2669,12 +2731,12 @@ App::post('/v1/account/verification') $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); - $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); - $subject = $locale->getText('emails.verification.subject'); + $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $subject = $locale->getText("emails.verification.subject"); $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; - $customTemplate = $project->getAttribute('templates', [])['email.verification-'.$locale->default] ?? []; - if ($smtpEnabled && ! empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['email.verification-' . $locale->default] ?? []; + if ($smtpEnabled && !empty($customTemplate)) { $body = $customTemplate['message'] ?? $body; $subject = $customTemplate['subject'] ?? $subject; $from = $customTemplate['senderName'] ?? $from; @@ -2682,13 +2744,13 @@ App::post('/v1/account/verification') $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText('emails.verification.hello')) + ->setParam('{{hello}}', $locale->getText("emails.verification.hello")) ->setParam('{{name}}', $user->getAttribute('name')) - ->setParam('{{body}}', $locale->getText('emails.verification.body')) + ->setParam('{{body}}', $locale->getText("emails.verification.body")) ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText('emails.verification.footer')) - ->setParam('{{thanks}}', $locale->getText('emails.verification.thanks')) - ->setParam('{{signature}}', $locale->getText('emails.verification.signature')) + ->setParam('{{footer}}', $locale->getText("emails.verification.footer")) + ->setParam('{{thanks}}', $locale->getText("emails.verification.thanks")) + ->setParam('{{signature}}', $locale->getText("emails.verification.signature")) ->setParam('{{project}}', $projectName) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -2703,7 +2765,8 @@ App::post('/v1/account/verification') ->setFrom($from) ->setRecipient($user->getAttribute('email')) ->setName($user->getAttribute('name') ?? '') - ->trigger(); + ->trigger() + ; $events ->setParam('userId', $user->getId()) @@ -2711,7 +2774,8 @@ App::post('/v1/account/verification') ->setPayload($response->output( $verification->setAttribute('secret', $verificationSecret), Response::MODEL_TOKEN - )); + )) + ; // Hide secret for clients $verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $verificationSecret : ''); @@ -2744,7 +2808,8 @@ App::put('/v1/account/verification') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $events) { - $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); + + $profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -2753,7 +2818,7 @@ App::put('/v1/account/verification') $tokens = $profile->getAttribute('tokens', []); $verification = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_VERIFICATION, $secret); - if (! $verification) { + if (!$verification) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -2774,7 +2839,8 @@ App::put('/v1/account/verification') $events ->setParam('userId', $userId) - ->setParam('tokenId', $verificationDocument->getId()); + ->setParam('tokenId', $verificationDocument->getId()) + ; $response->dynamic($verificationDocument, Response::MODEL_TOKEN); }); @@ -2804,6 +2870,7 @@ App::post('/v1/account/verification/phone') ->inject('project') ->inject('locale') ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events, EventPhone $messaging, Document $project, Locale $locale) { + if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED); } @@ -2840,10 +2907,10 @@ App::post('/v1/account/verification/phone') $dbForProject->deleteCachedDocument('users', $user->getId()); - $message = Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl'); + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl'); - $customTemplate = $project->getAttribute('templates', [])['sms.verification-'.$locale->default] ?? []; - if (! empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['sms.verification-' . $locale->default] ?? []; + if (!empty($customTemplate)) { $message = $customTemplate['message'] ?? $message; } @@ -2853,7 +2920,8 @@ App::post('/v1/account/verification/phone') $messaging ->setRecipient($user->getAttribute('phone')) ->setMessage($message) - ->trigger(); + ->trigger() + ; $events ->setParam('userId', $user->getId()) @@ -2861,7 +2929,8 @@ App::post('/v1/account/verification/phone') ->setPayload($response->output( $verification->setAttribute('secret', $secret), Response::MODEL_TOKEN - )); + )) + ; // Hide secret for clients $verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : ''); @@ -2894,7 +2963,8 @@ App::put('/v1/account/verification/phone') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $events) { - $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); + + $profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -2902,7 +2972,7 @@ App::put('/v1/account/verification/phone') $verification = Auth::phoneTokenVerify($user->getAttribute('tokens', []), $secret); - if (! $verification) { + if (!$verification) { throw new Exception(Exception::USER_INVALID_TOKEN); } @@ -2922,7 +2992,8 @@ App::put('/v1/account/verification/phone') $events ->setParam('userId', $user->getId()) - ->setParam('tokenId', $verificationDocument->getId()); + ->setParam('tokenId', $verificationDocument->getId()) + ; $response->dynamic($verificationDocument, Response::MODEL_TOKEN); }); @@ -2961,7 +3032,7 @@ App::post('/v1/account/targets') $target = $dbForProject->getDocument('targets', $targetId); - if (! $target->isEmpty()) { + if (!$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } @@ -2969,7 +3040,7 @@ App::post('/v1/account/targets') '$id' => $targetId, // TO DO: what permissions should be given when created a target. '$permissions' => [ - Permission::read(Role::any()), + Permission::read(Role::any()) ], 'providerId' => $providerId, 'providerInternalId' => $provider->getInternalId(), @@ -3005,6 +3076,7 @@ App::patch('/v1/account/targets/:targetId/identifier') ->inject('dbForProject') ->inject('events') ->action(function (string $targetId, string $userId, string $identifier, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -3049,6 +3121,7 @@ App::delete('/v1/account/targets/:targetId') ->inject('dbForProject') ->inject('events') ->action(function (string $targetId, string $userId, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 047d99823e..0be2e0d849 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -1,6 +1,7 @@ output($output, $quality); $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT') + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') ->setContentType('image/png') ->file($data); unset($image); @@ -82,12 +83,12 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro $accessTokenExpiry = $gitHubSession->getAttribute('providerAccessTokenExpiry'); $refreshToken = $gitHubSession->getAttribute('providerRefreshToken'); - $appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}'; + $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; - $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); + $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); - if (! \class_exists($className)) { + if (!\class_exists($className)) { throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } @@ -104,13 +105,13 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro $verificationId = $oauth2->getUserID($accessToken); if (empty($verificationId)) { - throw new \Exception('Locked tokens.'); // Race codition, handeled in catch + throw new \Exception("Locked tokens."); // Race codition, handeled in catch } $gitHubSession ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $oauth2->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry(''))); Authorization::skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession)); @@ -149,7 +150,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro return [ 'name' => $githubUser, - 'id' => $githubId, + 'id' => $githubId ]; } catch (Exception $error) { if ($logger) { @@ -176,7 +177,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); $responseCode = $logger->addLog($log); - Console::info('GitHub error log pushed with status code: '.$responseCode); + Console::info('GitHub error log pushed with status code: ' . $responseCode); } Console::warning("Failed: {$error->getMessage()}"); @@ -201,12 +202,12 @@ App::get('/v1/avatars/credit-cards/:code') ->label('sdk.description', '/docs/references/avatars/get-credit-card.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG) - ->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: '.\implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))).'.') + ->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: ' . \implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))) . '.') ->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true) ->inject('response') - ->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('credit-cards', $code, $width, $height, $quality, $response)); + ->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('credit-cards', $code, $width, $height, $quality, $response)); App::get('/v1/avatars/browsers/:code') ->desc('Get Browser Icon') @@ -266,17 +267,18 @@ App::get('/v1/avatars/image') ->param('height', 400, new Range(0, 2000), 'Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.', true) ->inject('response') ->action(function (string $url, int $width, int $height, Response $response) { + $quality = 80; $output = 'png'; $type = 'png'; - if (! \extension_loaded('imagick')) { + if (!\extension_loaded('imagick')) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); } $fetch = @\file_get_contents($url, false); - if (! $fetch) { + if (!$fetch) { throw new Exception(Exception::AVATAR_IMAGE_NOT_FOUND); } @@ -291,7 +293,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('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') ->setContentType('image/png') ->file($data); unset($image); @@ -313,13 +315,14 @@ App::get('/v1/avatars/favicon') ->param('url', '', new URL(['http', 'https']), 'Website URL which you want to fetch the favicon from.') ->inject('response') ->action(function (string $url, Response $response) { + $width = 56; $height = 56; $quality = 80; $output = 'png'; $type = 'png'; - if (! \extension_loaded('imagick')) { + if (!\extension_loaded('imagick')) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); } @@ -341,7 +344,7 @@ App::get('/v1/avatars/favicon') \curl_close($curl); - if (! $html) { + if (!$html) { throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED); } @@ -392,7 +395,7 @@ App::get('/v1/avatars/favicon') if (empty($outputHref) || empty($outputExt)) { $default = \parse_url($url); - $outputHref = $default['scheme'].'://'.$default['host'].'/favicon.ico'; + $outputHref = $default['scheme'] . '://' . $default['host'] . '/favicon.ico'; $outputExt = 'ico'; } @@ -403,14 +406,14 @@ 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('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') ->setContentType('image/x-icon') ->file($data); } $fetch = @\file_get_contents($outputHref, false); - if (! $fetch) { + if (!$fetch) { throw new Exception(Exception::AVATAR_ICON_NOT_FOUND); } @@ -420,7 +423,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('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') ->setContentType('image/png') ->file($data); unset($image); @@ -443,6 +446,7 @@ App::get('/v1/avatars/qr') ->param('download', false, new Boolean(true), 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true) ->inject('response') ->action(function (string $text, int $size, int $margin, bool $download, Response $response) { + $download = ($download === '1' || $download === 'true' || $download === 1 || $download === true); $options = new QROptions([ 'addQuietzone' => true, @@ -460,7 +464,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('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->setContentType('image/png') ->send($image->output('png', 9)); }); @@ -484,16 +488,17 @@ App::get('/v1/avatars/initials') ->inject('response') ->inject('user') ->action(function (string $name, int $width, int $height, string $background, Response $response, Document $user) { + $themes = [ ['background' => '#FFA1CE'], // Default (Pink) ['background' => '#FDC584'], // Orange ['background' => '#94DBD1'], // Green ['background' => '#A1C4FF'], // Blue ['background' => '#FFA1CE'], // Pink - ['background' => '#CBB1FC'], // Purple + ['background' => '#CBB1FC'] // Purple ]; - $name = (! empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', '')); + $name = (!empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', '')); $words = \explode(' ', \strtoupper($name)); // if there is no space, try to split by `_` underscore $words = (count($words) == 1) ? \explode('_', \strtoupper($name)) : $words; @@ -515,7 +520,7 @@ App::get('/v1/avatars/initials') // Wrap rand value to avoid out of range $rand = ($rand > \count($themes) - 1) ? $rand % \count($themes) : $rand; - $background = (! empty($background)) ? '#'.$background : $themes[$rand]['background']; + $background = (!empty($background)) ? '#' . $background : $themes[$rand]['background']; $image = new \Imagick(); $punch = new \Imagick(); @@ -524,8 +529,8 @@ App::get('/v1/avatars/initials') $punch->newImage($width, $height, 'transparent'); - $draw->setFont(__DIR__.'/../../assets/fonts/poppins-v9-latin-500.ttf'); - $image->setFont(__DIR__.'/../../assets/fonts/poppins-v9-latin-500.ttf'); + $draw->setFont(__DIR__ . "/../../assets/fonts/poppins-v9-latin-500.ttf"); + $image->setFont(__DIR__ . "/../../assets/fonts/poppins-v9-latin-500.ttf"); $draw->setFillColor(new ImagickPixel('black')); $draw->setFontSize($fontSize); @@ -537,13 +542,13 @@ App::get('/v1/avatars/initials') $punch->negateImage(true, Imagick::CHANNEL_ALPHA); $image->newImage($width, $height, $background); - $image->setImageFormat('png'); + $image->setImageFormat("png"); $image->compositeImage($punch, Imagick::COMPOSITE_COPYOPACITY, 0, 0); //$image->setImageCompressionQuality(9 - round(($quality / 100) * 9)); $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->setContentType('image/png') ->file($image->getImageBlob()); }); @@ -577,7 +582,7 @@ App::get('/v1/cards/cloud') throw new Exception(Exception::USER_NOT_FOUND); } - if (! $mock) { + if (!$mock) { $name = $user->getAttribute('name', 'Anonymous'); $email = $user->getAttribute('email', ''); $createdAt = new \DateTime($user->getCreatedAt()); @@ -597,9 +602,9 @@ App::get('/v1/cards/cloud') $createdAt = new \DateTime($employees[$email]['memberSince'] ?? ''); } - if (! $isEmployee && ! empty($githubName)) { + if (!$isEmployee && !empty($githubName)) { $employeeGitHub = \array_search(\strtolower($githubName), \array_map(fn ($employee) => \strtolower($employee['gitHub']) ?? '', $employees)); - if (! empty($employeeGitHub)) { + if (!empty($employeeGitHub)) { $isEmployee = true; $employeeNumber = $isEmployee ? $employees[$employeeGitHub]['spot'] : ''; $createdAt = new \DateTime($employees[$employeeGitHub]['memberSince'] ?? ''); @@ -640,20 +645,20 @@ App::get('/v1/cards/cloud') $isGolden = $isEmployee || $isHero || $isContributor; $isPlatinum = $isGolden ? false : $isPlatinum; - $memberSince = \strtoupper('Member since '.$createdAt->format('M').' '.$createdAt->format('d').', '.$createdAt->format('o')); + $memberSince = \strtoupper('Member since ' . $createdAt->format('M') . ' ' . $createdAt->format('d') . ', ' . $createdAt->format('o')); $imagePath = $isGolden ? 'front-golden.png' : ($isPlatinum ? 'front-platinum.png' : 'front.png'); - $baseImage = new \Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$imagePath); + $baseImage = new \Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $imagePath); if ($isEmployee) { - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/employee.png'); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/employee.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 793, 35); $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf'); + $text->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf'); $text->setFillColor(new \ImagickPixel('#FFFADF')); $text->setFontSize(\strlen($employeeNumber) <= 2 ? 54 : 48); $text->setFontWeight(700); @@ -661,7 +666,7 @@ App::get('/v1/cards/cloud') $hashtag = new \ImagickDraw(); $hashtag->setTextAlignment(Imagick::ALIGN_CENTER); - $hashtag->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf'); + $hashtag->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf'); $hashtag->setFillColor(new \ImagickPixel('#FFFADF')); $hashtag->setFontSize(28); $hashtag->setFontWeight(700); @@ -684,25 +689,25 @@ App::get('/v1/cards/cloud') } if ($isContributor) { - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/contributor.png'); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/contributor.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 793, 34); } if ($isHero) { - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/hero.png'); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/hero.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 793, 34); } - setlocale(LC_ALL, 'en_US.utf8'); + setlocale(LC_ALL, "en_US.utf8"); // $name = \iconv("utf-8", "ascii//TRANSLIT", $name); // $memberSince = \iconv("utf-8", "ascii//TRANSLIT", $memberSince); // $githubName = \iconv("utf-8", "ascii//TRANSLIT", $githubName); $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__.'/../../../public/fonts/Poppins-Bold.ttf'); + $text->setFont(__DIR__ . '/../../../public/fonts/Poppins-Bold.ttf'); $text->setFillColor(new \ImagickPixel('#FFFFFF')); if (\strlen($name) > 32) { @@ -721,17 +726,17 @@ App::get('/v1/cards/cloud') $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__.'/../../../public/fonts/Inter-SemiBold.ttf'); + $text->setFont(__DIR__ . '/../../../public/fonts/Inter-SemiBold.ttf'); $text->setFillColor(new \ImagickPixel($isGolden || $isPlatinum ? '#FFFFFF' : '#FFB9CC')); $text->setFontSize(27); $text->setFontWeight(600); $text->setTextKerning(1.08); $baseImage->annotateImage($text, 512, 541, 0, \strtoupper($memberSince)); - if (! empty($githubName)) { + if (!empty($githubName)) { $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__.'/../../../public/fonts/Inter-Regular.ttf'); + $text->setFont(__DIR__ . '/../../../public/fonts/Inter-Regular.ttf'); $text->setFillColor(new \ImagickPixel('#FFFFFF')); $text->setFontSize($scalingDown ? 28 : 32); $text->setFontWeight(400); @@ -739,18 +744,18 @@ App::get('/v1/cards/cloud') $baseImage->annotateImage($text, 512 + 20 + 4, 373 + ($scalingDown ? 2 : 0), 0, $githubName); - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github.png'); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $precisionFix = 5; $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 512 - ($metrics['textWidth'] / 2) - 20 - 4, 373 - ($metrics['textHeight'] - $precisionFix)); } - if (! empty($width) || ! empty($height)) { + if (!empty($width) || !empty($height)) { $baseImage->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1); } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->setContentType('image/png') ->file($baseImage->getImageBlob()); }); @@ -784,7 +789,7 @@ App::get('/v1/cards/cloud-back') throw new Exception(Exception::USER_NOT_FOUND); } - if (! $mock) { + if (!$mock) { $userId = $user->getId(); $email = $user->getAttribute('email', ''); @@ -804,31 +809,31 @@ App::get('/v1/cards/cloud-back') $isPlatinum = $mock === 'platinum'; } - $userId = 'UID '.$userId; + $userId = 'UID ' . $userId; $isPlatinum = $isGolden ? false : $isPlatinum; $imagePath = $isGolden ? 'back-golden.png' : ($isPlatinum ? 'back-platinum.png' : 'back.png'); - $baseImage = new \Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$imagePath); + $baseImage = new \Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $imagePath); - setlocale(LC_ALL, 'en_US.utf8'); + setlocale(LC_ALL, "en_US.utf8"); // $userId = \iconv("utf-8", "ascii//TRANSLIT", $userId); $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_CENTER); - $text->setFont(__DIR__.'/../../../public/fonts/SourceCodePro-Regular.ttf'); + $text->setFont(__DIR__ . '/../../../public/fonts/SourceCodePro-Regular.ttf'); $text->setFillColor(new \ImagickPixel($isGolden ? '#664A1E' : ($isPlatinum ? '#555555' : '#E8E9F0'))); $text->setFontSize(28); $text->setFontWeight(400); $baseImage->annotateImage($text, 512, 596, 0, $userId); - if (! empty($width) || ! empty($height)) { + if (!empty($width) || !empty($height)) { $baseImage->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1); } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->setContentType('image/png') ->file($baseImage->getImageBlob()); }); @@ -862,7 +867,7 @@ App::get('/v1/cards/cloud-og') throw new Exception(Exception::USER_NOT_FOUND); } - if (! $mock) { + if (!$mock) { $internalId = $user->getInternalId(); $bgVariation = $internalId % 3 === 0 ? '1' : ($internalId % 3 === 1 ? '2' : '3'); $cardVariation = $internalId % 3 === 0 ? '1' : ($internalId % 3 === 1 ? '2' : '3'); @@ -886,9 +891,9 @@ App::get('/v1/cards/cloud-og') $createdAt = new \DateTime($employees[$email]['memberSince'] ?? ''); } - if (! $isEmployee && ! empty($githubName)) { + if (!$isEmployee && !empty($githubName)) { $employeeGitHub = \array_search(\strtolower($githubName), \array_map(fn ($employee) => \strtolower($employee['gitHub']) ?? '', $employees)); - if (! empty($employeeGitHub)) { + if (!empty($employeeGitHub)) { $isEmployee = true; $employeeNumber = $isEmployee ? $employees[$employeeGitHub]['spot'] : ''; $createdAt = new \DateTime($employees[$employeeGitHub]['memberSince'] ?? ''); @@ -935,17 +940,17 @@ App::get('/v1/cards/cloud-og') $isGolden = $isEmployee || $isHero || $isContributor; $isPlatinum = $isGolden ? false : $isPlatinum; - $memberSince = \strtoupper('Member since '.$createdAt->format('M').' '.$createdAt->format('d').', '.$createdAt->format('o')); + $memberSince = \strtoupper('Member since ' . $createdAt->format('M') . ' ' . $createdAt->format('d') . ', ' . $createdAt->format('o')); - $baseImage = new \Imagick(__DIR__."/../../../public/images/cards/cloud/og-background{$bgVariation}.png"); + $baseImage = new \Imagick(__DIR__ . "/../../../public/images/cards/cloud/og-background{$bgVariation}.png"); $cardType = $isGolden ? '-golden' : ($isPlatinum ? '-platinum' : ''); - $image = new Imagick(__DIR__."/../../../public/images/cards/cloud/og-card{$cardType}{$cardVariation}.png"); + $image = new Imagick(__DIR__ . "/../../../public/images/cards/cloud/og-card{$cardType}{$cardVariation}.png"); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 1008 / 2 - $image->getImageWidth() / 2, 1008 / 2 - $image->getImageHeight() / 2); - $imageLogo = new Imagick(__DIR__.'/../../../public/images/cards/cloud/og-background-logo.png'); - $imageShadow = new Imagick(__DIR__."/../../../public/images/cards/cloud/og-shadow{$cardType}.png"); + $imageLogo = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/og-background-logo.png'); + $imageShadow = new Imagick(__DIR__ . "/../../../public/images/cards/cloud/og-shadow{$cardType}.png"); if ($cardVariation === '1') { $baseImage->compositeImage($imageLogo, Imagick::COMPOSITE_OVER, 32, 1008 - $imageLogo->getImageHeight() - 32); $baseImage->compositeImage($imageShadow, Imagick::COMPOSITE_OVER, -450, 700); @@ -959,19 +964,19 @@ App::get('/v1/cards/cloud-og') if ($isEmployee) { $file = $cardVariation === '3' ? 'employee-skew.png' : 'employee.png'; - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$file); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $file); $image->setGravity(Imagick::GRAVITY_CENTER); $hashtag = new \ImagickDraw(); $hashtag->setTextAlignment(Imagick::ALIGN_LEFT); - $hashtag->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf'); + $hashtag->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf'); $hashtag->setFillColor(new \ImagickPixel('#FFFADF')); $hashtag->setFontSize(20); $hashtag->setFontWeight(700); $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_LEFT); - $text->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf'); + $text->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf'); $text->setFillColor(new \ImagickPixel('#FFFADF')); $text->setFontSize(\strlen($employeeNumber) <= 1 ? 36 : 28); $text->setFontWeight(700); @@ -1045,7 +1050,7 @@ App::get('/v1/cards/cloud-og') if ($isContributor) { $file = $cardVariation === '3' ? 'contributor-skew.png' : 'contributor.png'; - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$file); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $file); $image->setGravity(Imagick::GRAVITY_CENTER); if ($cardVariation === '1') { @@ -1063,7 +1068,7 @@ App::get('/v1/cards/cloud-og') if ($isHero) { $file = $cardVariation === '3' ? 'hero-skew.png' : 'hero.png'; - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$file); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $file); $image->setGravity(Imagick::GRAVITY_CENTER); if ($cardVariation === '1') { @@ -1079,14 +1084,14 @@ App::get('/v1/cards/cloud-og') } } - setlocale(LC_ALL, 'en_US.utf8'); + setlocale(LC_ALL, "en_US.utf8"); // $name = \iconv("utf-8", "ascii//TRANSLIT", $name); // $memberSince = \iconv("utf-8", "ascii//TRANSLIT", $memberSince); // $githubName = \iconv("utf-8", "ascii//TRANSLIT", $githubName); $textName = new \ImagickDraw(); $textName->setTextAlignment(Imagick::ALIGN_CENTER); - $textName->setFont(__DIR__.'/../../../public/fonts/Poppins-Bold.ttf'); + $textName->setFont(__DIR__ . '/../../../public/fonts/Poppins-Bold.ttf'); $textName->setFillColor(new \ImagickPixel('#FFFFFF')); if (\strlen($name) > 32) { @@ -1123,7 +1128,7 @@ App::get('/v1/cards/cloud-og') $textMember = new \ImagickDraw(); $textMember->setTextAlignment(Imagick::ALIGN_CENTER); - $textMember->setFont(__DIR__.'/../../../public/fonts/Inter-Medium.ttf'); + $textMember->setFont(__DIR__ . '/../../../public/fonts/Inter-Medium.ttf'); $textMember->setFillColor(new \ImagickPixel($isGolden || $isPlatinum ? '#FFFFFF' : '#FFB9CC')); $textMember->setFontWeight(500); $textMember->setTextKerning(1.12); @@ -1153,10 +1158,10 @@ App::get('/v1/cards/cloud-og') $baseImage->drawImage($textMember); } - if (! empty($githubName)) { + if (!empty($githubName)) { $text = new \ImagickDraw(); $text->setTextAlignment(Imagick::ALIGN_LEFT); - $text->setFont(__DIR__.'/../../../public/fonts/Inter-Regular.ttf'); + $text->setFont(__DIR__ . '/../../../public/fonts/Inter-Regular.ttf'); $text->setFillColor(new \ImagickPixel('#FFFFFF')); $text->setFontSize($scalingDown ? 16 : 20); $text->setFontWeight(400); @@ -1167,7 +1172,7 @@ App::get('/v1/cards/cloud-og') $group = new Imagick(); $groupWidth = $metrics['textWidth'] + 32 + 4; $group->newImage($groupWidth, $metrics['textHeight'] + 10, '#00000000'); - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github.png'); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $image->resizeImage(32, 32, Imagick::FILTER_LANCZOS, 1); $precisionFix = -1; @@ -1185,7 +1190,7 @@ App::get('/v1/cards/cloud-og') $group = new Imagick(); $groupWidth = $metrics['textWidth'] + 32 + 4; $group->newImage($groupWidth, $metrics['textHeight'] + 10, '#00000000'); - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github.png'); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $image->resizeImage(32, 32, Imagick::FILTER_LANCZOS, 1); $precisionFix = -1; @@ -1205,7 +1210,7 @@ App::get('/v1/cards/cloud-og') $text->annotation(320 + 15 + 2, 640, $githubName); $metrics = $baseImage->queryFontMetrics($text, $githubName); - $image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github-skew.png'); + $image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github-skew.png'); $image->setGravity(Imagick::GRAVITY_CENTER); $baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 512 - ($metrics['textWidth'] / 2), 518 + \strlen($githubName) * 1.3); @@ -1213,12 +1218,12 @@ App::get('/v1/cards/cloud-og') } } - if (! empty($width) || ! empty($height)) { + if (!empty($width) || !empty($height)) { $baseImage->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1); } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->setContentType('image/png') ->file($baseImage->getImageBlob()); }); diff --git a/app/controllers/api/console.php b/app/controllers/api/console.php index 846964cad6..f2ea83af58 100644 --- a/app/controllers/api/console.php +++ b/app/controllers/api/console.php @@ -15,6 +15,7 @@ App::init() } }); + App::get('/v1/console/variables') ->desc('Get Variables') ->groups(['api', 'projects']) @@ -28,6 +29,7 @@ App::get('/v1/console/variables') ->label('sdk.response.model', Response::MODEL_CONSOLE_VARIABLES) ->inject('response') ->action(function (Response $response) { + $variables = new Document([ '_APP_DOMAIN_TARGET' => App::getEnv('_APP_DOMAIN_TARGET'), '_APP_STORAGE_LIMIT' => +App::getEnv('_APP_STORAGE_LIMIT'), @@ -38,6 +40,7 @@ App::get('/v1/console/variables') $response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES); }); + App::post('/v1/console/assistant') ->desc('Ask Query') ->groups(['api', 'assistant']) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 8f1868f17e..aa7999b844 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -17,7 +17,9 @@ use MaxMind\Db\Reader; use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; +use Utopia\Database\Adapter\MariaDB; use Utopia\Database\Database; +use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Authorization as AuthorizationException; use Utopia\Database\Exception\Duplicate as DuplicateException; @@ -44,8 +46,8 @@ use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\FloatValidator; -use Utopia\Validator\Integer; use Utopia\Validator\IP; +use Utopia\Validator\Integer; use Utopia\Validator\JSON; use Utopia\Validator\Nullable; use Utopia\Validator\Range; @@ -58,7 +60,6 @@ use Utopia\Validator\WhiteList; * * * @return Document Newly created attribute document - * * @throws Exception */ function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $database, Event $events): Document @@ -81,14 +82,14 @@ function createAttribute(string $databaseId, string $collectionId, Document $att throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - if (! empty($format)) { - if (! Structure::hasFormat($format, $type)) { + if (!empty($format)) { + if (!Structure::hasFormat($format, $type)) { throw new Exception(Exception::ATTRIBUTE_FORMAT_UNSUPPORTED, "Format {$format} not available for {$type} attributes."); } } @@ -104,7 +105,7 @@ function createAttribute(string $databaseId, string $collectionId, Document $att if ($type === Database::VAR_RELATIONSHIP) { $options['side'] = Database::RELATION_SIDE_PARENT; - $relatedCollection = $dbForProject->getDocument('database_'.$db->getInternalId(), $options['relatedCollection'] ?? ''); + $relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $options['relatedCollection'] ?? ''); if ($relatedCollection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND, 'The related collection was not found.'); } @@ -112,7 +113,7 @@ function createAttribute(string $databaseId, string $collectionId, Document $att try { $attribute = new Document([ - '$id' => ID::custom($db->getInternalId().'_'.$collection->getInternalId().'_'.$key), + '$id' => ID::custom($db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key), 'key' => $key, 'databaseInternalId' => $db->getInternalId(), 'databaseId' => $db->getId(), @@ -138,13 +139,13 @@ function createAttribute(string $databaseId, string $collectionId, Document $att } catch (LimitException) { throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute limit exceeded'); } catch (\Exception $e) { - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); - $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$collection->getInternalId()); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); + $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId()); throw $e; } - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); - $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$collection->getInternalId()); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); + $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId()); if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) { $twoWayKey = $options['twoWayKey']; @@ -154,7 +155,7 @@ function createAttribute(string $databaseId, string $collectionId, Document $att try { $twoWayAttribute = new Document([ - '$id' => ID::custom($db->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$twoWayKey), + '$id' => ID::custom($db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $twoWayKey), 'key' => $twoWayKey, 'databaseInternalId' => $db->getInternalId(), 'databaseId' => $db->getId(), @@ -182,13 +183,13 @@ function createAttribute(string $databaseId, string $collectionId, Document $att $dbForProject->deleteDocument('attributes', $attribute->getId()); throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute limit exceeded'); } catch (\Exception $e) { - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $relatedCollection->getId()); - $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$relatedCollection->getInternalId()); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId()); + $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); throw $e; } - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $relatedCollection->getId()); - $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$relatedCollection->getInternalId()); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId()); + $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); } $database @@ -230,13 +231,13 @@ function updateAttribute( throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $attribute = $dbForProject->getDocument('attributes', $db->getInternalId().'_'.$collection->getInternalId().'_'.$key); + $attribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key); if ($attribute->isEmpty()) { throw new Exception(Exception::ATTRIBUTE_NOT_FOUND); @@ -262,7 +263,7 @@ function updateAttribute( throw new Exception(Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, 'Cannot set default value for array attributes'); } - $collectionId = 'database_'.$db->getInternalId().'_collection_'.$collection->getInternalId(); + $collectionId = 'database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId(); $attribute ->setAttribute('default', $default) @@ -286,18 +287,18 @@ function updateAttribute( } else { $validator = new Range($min, $max, Database::VAR_FLOAT); - if (! is_null($default)) { + if (!is_null($default)) { $default = \floatval($default); } } - if (! is_null($default) && ! $validator->isValid($default)) { + if (!is_null($default) && !$validator->isValid($default)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription()); } $options = [ 'min' => $min, - 'max' => $max, + 'max' => $max ]; $attribute->setAttribute('formatOptions', $options); @@ -313,12 +314,12 @@ function updateAttribute( } } - if (! is_null($default) && ! in_array($default, $elements)) { + if (!is_null($default) && !in_array($default, $elements)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Default value not found in elements'); } $options = [ - 'elements' => $elements, + 'elements' => $elements ]; $attribute->setAttribute('formatOptions', $options); @@ -337,13 +338,13 @@ function updateAttribute( ); if ($primaryDocumentOptions['twoWay']) { - $relatedCollection = $dbForProject->getDocument('database_'.$db->getInternalId(), $primaryDocumentOptions['relatedCollection']); + $relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $primaryDocumentOptions['relatedCollection']); - $relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$primaryDocumentOptions['twoWayKey']); + $relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey']); $relatedOptions = \array_merge($relatedAttribute->getAttribute('options'), $options); $relatedAttribute->setAttribute('options', $relatedOptions); - $dbForProject->updateDocument('attributes', $db->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$primaryDocumentOptions['twoWayKey'], $relatedAttribute); - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $relatedCollection->getId()); + $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey'], $relatedAttribute); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId()); } } else { $dbForProject->updateAttribute( @@ -355,8 +356,8 @@ function updateAttribute( ); } - $dbForProject->updateDocument('attributes', $db->getInternalId().'_'.$collection->getInternalId().'_'.$key, $attribute); - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collection->getId()); + $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key, $attribute); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collection->getId()); $events ->setContext('collection', $collection) @@ -389,6 +390,7 @@ App::post('/v1/databases') ->inject('dbForProject') ->inject('events') ->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) { + $databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId; try { @@ -418,7 +420,7 @@ App::post('/v1/databases') 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '', + 'format' => $attribute['format'] ?? '' ]); } @@ -431,7 +433,7 @@ App::post('/v1/databases') 'orders' => $index['orders'], ]); } - $dbForProject->createCollection('database_'.$database->getInternalId(), $attributes, $indexes); + $dbForProject->createCollection('database_' . $database->getInternalId(), $attributes, $indexes); } catch (DuplicateException) { throw new Exception(Exception::DATABASE_ALREADY_EXISTS); } @@ -454,14 +456,15 @@ App::get('/v1/databases') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DATABASE_LIST) - ->param('queries', [], new Databases(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Databases::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Databases(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Databases::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { + $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -502,6 +505,7 @@ App::get('/v1/databases/:databaseId') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, Response $response, Database $dbForProject) { + $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { @@ -529,6 +533,7 @@ App::get('/v1/databases/:databaseId/logs') ->inject('locale') ->inject('geodb') ->action(function (string $databaseId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { @@ -541,13 +546,13 @@ App::get('/v1/databases/:databaseId/logs') $offset = $grouped['offset'] ?? 0; $audit = new Audit($dbForProject); - $resource = 'database/'.$databaseId; + $resource = 'database/' . $databaseId; $logs = $audit->getLogsByResource($resource, $limit, $offset); $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -575,14 +580,14 @@ App::get('/v1/databases/:databaseId/logs') 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'], + 'deviceModel' => $device['deviceModel'] ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -595,6 +600,7 @@ App::get('/v1/databases/:databaseId/logs') ]), Response::MODEL_LOG_LIST); }); + App::put('/v1/databases/:databaseId') ->desc('Update Database') ->groups(['api', 'database', 'schema']) @@ -616,6 +622,7 @@ App::put('/v1/databases/:databaseId') ->inject('dbForProject') ->inject('events') ->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) { + $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { @@ -630,7 +637,7 @@ App::put('/v1/databases/:databaseId') } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. '.$exception->getMessage()); + throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. ' . $exception->getMessage()); } $events->setParam('databaseId', $database->getId()); @@ -657,18 +664,19 @@ App::delete('/v1/databases/:databaseId') ->inject('events') ->inject('deletes') ->action(function (string $databaseId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { + $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - if (! $dbForProject->deleteDocument('databases', $databaseId)) { + if (!$dbForProject->deleteDocument('databases', $databaseId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove collection from DB'); } $dbForProject->deleteCachedDocument('databases', $database->getId()); - $dbForProject->deleteCachedCollection('databases_'.$database->getInternalId()); + $dbForProject->deleteCachedCollection('databases_' . $database->getInternalId()); $deletes ->setType(DELETE_TYPE_DOCUMENT) @@ -707,9 +715,10 @@ App::post('/v1/databases/:databaseId/collections') ->inject('mode') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } @@ -719,7 +728,7 @@ App::post('/v1/databases/:databaseId/collections') $permissions = Permission::aggregate($permissions); try { - $dbForProject->createDocument('database_'.$database->getInternalId(), new Document([ + $dbForProject->createDocument('database_' . $database->getInternalId(), new Document([ '$id' => $collectionId, 'databaseInternalId' => $database->getInternalId(), 'databaseId' => $databaseId, @@ -729,9 +738,9 @@ App::post('/v1/databases/:databaseId/collections') 'name' => $name, 'search' => implode(' ', [$collectionId, $name]), ])); - $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); - $dbForProject->createCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), permissions: $permissions ?? [], documentSecurity: $documentSecurity); + $dbForProject->createCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), permissions: $permissions ?? [], documentSecurity: $documentSecurity); } catch (DuplicateException) { throw new Exception(Exception::COLLECTION_ALREADY_EXISTS); } catch (LimitException) { @@ -761,21 +770,22 @@ App::get('/v1/databases/:databaseId/collections') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_COLLECTION_LIST) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('queries', [], new Collections(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Collections::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Collections(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Collections::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -785,7 +795,7 @@ App::get('/v1/databases/:databaseId/collections') if ($cursor) { /** @var Query $cursor */ $collectionId = $cursor->getValue(); - $cursorDocument = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $cursorDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Collection '{$collectionId}' for the 'cursor' value not found."); @@ -797,8 +807,8 @@ App::get('/v1/databases/:databaseId/collections') $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ - 'collections' => $dbForProject->find('database_'.$database->getInternalId(), $queries), - 'total' => $dbForProject->count('database_'.$database->getInternalId(), $filterQueries, APP_LIMIT_COUNT), + 'collections' => $dbForProject->find('database_' . $database->getInternalId(), $queries), + 'total' => $dbForProject->count('database_' . $database->getInternalId(), $filterQueries, APP_LIMIT_COUNT), ]), Response::MODEL_COLLECTION_LIST); }); @@ -820,13 +830,14 @@ App::get('/v1/databases/:databaseId/collections/:collectionId') ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -855,13 +866,14 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') ->inject('locale') ->inject('geodb') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collectionDocument = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); - $collection = $dbForProject->getCollection('database_'.$database->getInternalId().'_collection_'.$collectionDocument->getInternalId()); + $collectionDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $collectionDocument->getInternalId()); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -873,13 +885,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') $offset = $grouped['offset'] ?? 0; $audit = new Audit($dbForProject); - $resource = 'database/'.$databaseId.'/collection/'.$collectionId; + $resource = 'database/' . $databaseId . '/collection/' . $collectionId; $logs = $audit->getLogsByResource($resource, $limit, $offset); $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -907,14 +919,14 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'], + 'deviceModel' => $device['deviceModel'] ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -927,6 +939,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') ]), Response::MODEL_LOG_LIST); }); + App::put('/v1/databases/:databaseId/collections/:collectionId') ->alias('/v1/database/collections/:collectionId', ['databaseId' => 'default']) ->desc('Update Collection') @@ -953,13 +966,14 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->inject('mode') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -973,17 +987,17 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') $enabled ??= $collection->getAttribute('enabled', true); try { - $collection = $dbForProject->updateDocument('database_'.$database->getInternalId(), $collectionId, $collection + $collection = $dbForProject->updateDocument('database_' . $database->getInternalId(), $collectionId, $collection ->setAttribute('name', $name) ->setAttribute('$permissions', $permissions) ->setAttribute('documentSecurity', $documentSecurity) ->setAttribute('enabled', $enabled) ->setAttribute('search', implode(' ', [$collectionId, $name]))); - $dbForProject->updateCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $permissions, $documentSecurity); + $dbForProject->updateCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $permissions, $documentSecurity); } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. '.$exception->getMessage()); + throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. ' . $exception->getMessage()); } $events @@ -1016,23 +1030,24 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->inject('events') ->inject('deletes') ->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode, Event $events, Delete $deletes) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - if (! $dbForProject->deleteDocument('database_'.$database->getInternalId(), $collectionId)) { + if (!$dbForProject->deleteDocument('database_' . $database->getInternalId(), $collectionId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove collection from DB'); } - $dbForProject->deleteCachedCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId()); + $dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId()); $deletes ->setType(DELETE_TYPE_DOCUMENT) @@ -1075,9 +1090,10 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + // Ensure attribute default is within required size $validator = new Text($size, 0); - if (! is_null($default) && ! $validator->isValid($default)) { + if (!is_null($default) && !$validator->isValid($default)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription()); } @@ -1128,6 +1144,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_STRING, @@ -1161,7 +1178,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') - ->param('elements', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE, min: 0), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' elements are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long.') + ->param('elements', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE, min: 0), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' elements are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Text(0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) @@ -1170,6 +1187,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + // use length of longest string as attribute size $size = 0; foreach ($elements as $element) { @@ -1180,7 +1198,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') $size = ($length > $size) ? $length : $size; } - if (! is_null($default) && ! in_array($default, $elements)) { + if (!is_null($default) && !in_array($default, $elements)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Default value not found in elements'); } @@ -1226,6 +1244,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_STRING, @@ -1267,6 +1286,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_STRING, @@ -1310,6 +1330,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + // Ensure attribute default is within range $min = (is_null($min)) ? PHP_INT_MIN : \intval($min); $max = (is_null($max)) ? PHP_INT_MAX : \intval($max); @@ -1320,7 +1341,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege $validator = new Range($min, $max, Database::VAR_INTEGER); - if (! is_null($default) && ! $validator->isValid($default)) { + if (!is_null($default) && !$validator->isValid($default)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription()); } @@ -1342,7 +1363,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege $formatOptions = $attribute->getAttribute('formatOptions', []); - if (! empty($formatOptions)) { + if (!empty($formatOptions)) { $attribute->setAttribute('min', \intval($formatOptions['min'])); $attribute->setAttribute('max', \intval($formatOptions['max'])); } @@ -1380,6 +1401,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + // Ensure attribute default is within range $min = (is_null($min)) ? -PHP_FLOAT_MAX : \floatval($min); $max = (is_null($max)) ? PHP_FLOAT_MAX : \floatval($max); @@ -1389,13 +1411,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' } // Ensure default value is a float - if (! is_null($default)) { + if (!is_null($default)) { $default = \floatval($default); } $validator = new Range($min, $max, Database::VAR_FLOAT); - if (! is_null($default) && ! $validator->isValid($default)) { + if (!is_null($default) && !$validator->isValid($default)) { throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription()); } @@ -1415,7 +1437,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' $formatOptions = $attribute->getAttribute('formatOptions', []); - if (! empty($formatOptions)) { + if (!empty($formatOptions)) { $attribute->setAttribute('min', \floatval($formatOptions['min'])); $attribute->setAttribute('max', \floatval($formatOptions['max'])); } @@ -1451,6 +1473,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_BOOLEAN, @@ -1491,6 +1514,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + $filters[] = 'datetime'; $attribute = createAttribute($databaseId, $collectionId, new Document([ @@ -1569,7 +1593,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati 'twoWay' => $twoWay, 'twoWayKey' => $twoWayKey, 'onDelete' => $onDelete, - ], + ] ]), $response, $dbForProject, @@ -1602,17 +1626,18 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_LIST) ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') - ->param('queries', [], new Attributes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Attributes::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Attributes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Attributes::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -1628,7 +1653,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') if ($cursor) { $attributeId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->find('attributes', [ + $cursorDocument = Authorization::skip(fn() => $dbForProject->find('attributes', [ Query::equal('collectionId', [$collectionId]), Query::equal('databaseId', [$databaseId]), Query::equal('key', [$attributeId]), @@ -1669,26 +1694,27 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') Response::MODEL_ATTRIBUTE_IP, Response::MODEL_ATTRIBUTE_DATETIME, Response::MODEL_ATTRIBUTE_RELATIONSHIP, - Response::MODEL_ATTRIBUTE_STRING, ])// needs to be last, since its condition would dominate any other string attribute + Response::MODEL_ATTRIBUTE_STRING])// needs to be last, since its condition would dominate any other string attribute ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $attribute = $dbForProject->getDocument('attributes', $database->getInternalId().'_'.$collection->getInternalId().'_'.$key); + $attribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $collection->getInternalId() . '_' . $key); if ($attribute->isEmpty()) { throw new Exception(Exception::ATTRIBUTE_NOT_FOUND); @@ -1744,6 +1770,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin ->inject('dbForProject') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) { + $attribute = updateAttribute( databaseId: $databaseId, collectionId: $collectionId, @@ -1815,7 +1842,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/enum/ ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') - ->param('elements', null, new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' elements are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long.') + ->param('elements', null, new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' elements are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Text(0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.') ->inject('response') @@ -1957,7 +1984,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/integ $formatOptions = $attribute->getAttribute('formatOptions', []); - if (! empty($formatOptions)) { + if (!empty($formatOptions)) { $attribute->setAttribute('min', \intval($formatOptions['min'])); $attribute->setAttribute('max', \intval($formatOptions['max'])); } @@ -2006,7 +2033,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/float $formatOptions = $attribute->getAttribute('formatOptions', []); - if (! empty($formatOptions)) { + if (!empty($formatOptions)) { $attribute->setAttribute('min', \floatval($formatOptions['min'])); $attribute->setAttribute('max', \floatval($formatOptions['max'])); } @@ -2130,7 +2157,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/ type: Database::VAR_RELATIONSHIP, required: false, options: [ - 'onDelete' => $onDelete, + 'onDelete' => $onDelete ] ); @@ -2167,18 +2194,19 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + + $db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $attribute = $dbForProject->getDocument('attributes', $db->getInternalId().'_'.$collection->getInternalId().'_'.$key); + $attribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key); if ($attribute->isEmpty()) { throw new Exception(Exception::ATTRIBUTE_NOT_FOUND); @@ -2189,19 +2217,19 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key $attribute = $dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'deleting')); } - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); - $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$collection->getInternalId()); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); + $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId()); if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) { $options = $attribute->getAttribute('options'); if ($options['twoWay']) { - $relatedCollection = $dbForProject->getDocument('database_'.$db->getInternalId(), $options['relatedCollection']); + $relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $options['relatedCollection']); if ($relatedCollection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$options['twoWayKey']); + $relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']); if ($relatedAttribute->isEmpty()) { throw new Exception(Exception::ATTRIBUTE_NOT_FOUND); @@ -2211,8 +2239,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key $dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'deleting')); } - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $options['relatedCollection']); - $dbForProject->deleteCachedCollection('database_'.$db->getInternalId().'_collection_'.$relatedCollection->getInternalId()); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $options['relatedCollection']); + $dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); } } @@ -2272,20 +2300,21 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', null, new Key(), 'Index Key.') ->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL, Database::INDEX_ARRAY]), 'Index type.') - ->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' attributes are allowed, each 32 characters long.') - ->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' orders are allowed.', true) + ->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.') + ->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true) ->inject('response') ->inject('dbForProject') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + + $db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -2293,7 +2322,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') $count = $dbForProject->count('indexes', [ Query::equal('collectionInternalId', [$collection->getInternalId()]), - Query::equal('databaseInternalId', [$db->getInternalId()]), + Query::equal('databaseInternalId', [$db->getInternalId()]) ], 61); $limit = $dbForProject->getLimitForIndexes(); @@ -2303,7 +2332,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') } // Convert Document[] to array of attribute metadata - $oldAttributes = \array_map(fn ($a) => $a->getArrayCopy(), $collection->getAttribute('attributes')); + $oldAttributes = \array_map(fn($a) => $a->getArrayCopy(), $collection->getAttribute('attributes')); $oldAttributes[] = [ 'key' => '$id', @@ -2312,7 +2341,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'required' => true, 'array' => false, 'default' => null, - 'size' => 36, + 'size' => 36 ]; $oldAttributes[] = [ @@ -2323,7 +2352,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'required' => false, 'array' => false, 'default' => null, - 'size' => 0, + 'size' => 0 ]; $oldAttributes[] = [ @@ -2334,7 +2363,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'required' => false, 'array' => false, 'default' => null, - 'size' => 0, + 'size' => 0 ]; // lengths hidden by default @@ -2345,7 +2374,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') $attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key')); if ($attributeIndex === false) { - throw new Exception(Exception::ATTRIBUTE_UNKNOWN, 'Unknown attribute: '.$attribute); + throw new Exception(Exception::ATTRIBUTE_UNKNOWN, 'Unknown attribute: ' . $attribute); } $attributeStatus = $oldAttributes[$attributeIndex]['status']; @@ -2353,12 +2382,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') $attributeSize = $oldAttributes[$attributeIndex]['size']; if ($attributeType === Database::VAR_RELATIONSHIP) { - throw new Exception(Exception::ATTRIBUTE_TYPE_INVALID, 'Cannot create an index for a relationship attribute: '.$oldAttributes[$attributeIndex]['key']); + throw new Exception(Exception::ATTRIBUTE_TYPE_INVALID, 'Cannot create an index for a relationship attribute: ' . $oldAttributes[$attributeIndex]['key']); } // ensure attribute is available if ($attributeStatus !== 'available') { - throw new Exception(Exception::ATTRIBUTE_NOT_AVAILABLE, 'Attribute not available: '.$oldAttributes[$attributeIndex]['key']); + throw new Exception(Exception::ATTRIBUTE_NOT_AVAILABLE, 'Attribute not available: ' . $oldAttributes[$attributeIndex]['key']); } // set attribute size as index length only for strings @@ -2366,7 +2395,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') } $index = new Document([ - '$id' => ID::custom($db->getInternalId().'_'.$collection->getInternalId().'_'.$key), + '$id' => ID::custom($db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key), 'key' => $key, 'status' => 'processing', // processing, available, failed, deleting, stuck 'databaseInternalId' => $db->getInternalId(), @@ -2380,7 +2409,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ]); $validator = new IndexValidator($dbForProject->getAdapter()->getMaxIndexLength()); - if (! $validator->isValid($collection->setAttribute('indexes', $index, Document::SET_TYPE_APPEND))) { + if (!$validator->isValid($collection->setAttribute('indexes', $index, Document::SET_TYPE_APPEND))) { throw new Exception(Exception::INDEX_INVALID, $validator->getDescription()); } @@ -2390,7 +2419,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') throw new Exception(Exception::INDEX_ALREADY_EXISTS); } - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); $database ->setType(DATABASE_TYPE_CREATE_INDEX) @@ -2424,17 +2453,18 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') ->label('sdk.response.model', Response::MODEL_INDEX_LIST) ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') - ->param('queries', [], new Indexes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Indexes::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Indexes(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Indexes::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -2443,17 +2473,17 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') $queries = Query::parseQueries($queries); \array_push($queries, Query::equal('collectionId', [$collectionId]), Query::equal('databaseId', [$databaseId])); - // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); - $cursor = reset($cursor); + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); if ($cursor) { $indexId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->find('indexes', [ + $cursorDocument = Authorization::skip(fn() => $dbForProject->find('indexes', [ Query::equal('collectionId', [$collectionId]), Query::equal('databaseId', [$databaseId]), Query::equal('key', [$indexId]), - Query::limit(1), + Query::limit(1) ])); if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { @@ -2488,12 +2518,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -2507,6 +2538,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') $response->dynamic($index, Response::MODEL_INDEX); }); + App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->alias('/v1/database/collections/:collectionId/indexes/:key', ['databaseId' => 'default']) ->desc('Delete Index') @@ -2529,18 +2561,19 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->inject('database') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { - $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + + $db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$db->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $index = $dbForProject->getDocument('indexes', $db->getInternalId().'_'.$collection->getInternalId().'_'.$key); + $index = $dbForProject->getDocument('indexes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key); if (empty($index->getId())) { throw new Exception(Exception::INDEX_NOT_FOUND); @@ -2551,7 +2584,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') $index = $dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'deleting')); } - $dbForProject->deleteCachedDocument('database_'.$db->getInternalId(), $collectionId); + $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId); $database ->setType(DATABASE_TYPE_DELETE_INDEX) @@ -2601,6 +2634,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->inject('events') ->inject('mode') ->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $events, string $mode) { + $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array if (empty($data)) { @@ -2611,16 +2645,16 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, '$id is not allowed for creating new documents, try update instead'); } - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { - if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } } @@ -2637,7 +2671,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') // Add permissions for current the user if none were provided. if (\is_null($permissions)) { $permissions = []; - if (! empty($user->getId())) { + if (!empty($user->getId())) { foreach ($allowedPermissions as $permission) { $permissions[] = (new Permission($permission, 'user', $user->getId()))->toString(); } @@ -2646,7 +2680,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') // Users can only manage their own roles, API keys and Admin users can manage any $roles = Authorization::getRoles(); - if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles)) { + if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -2658,8 +2692,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (! Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')'); + if (!Authorization::isRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } } @@ -2675,20 +2709,20 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $validator = new Authorization($permission); $valid = $validator->isValid($collection->getPermissionsByType($permission)); - if (($permission === Database::PERMISSION_UPDATE && ! $documentSecurity) || ! $valid) { + if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } if ($permission === Database::PERMISSION_UPDATE) { $valid = $valid || $validator->isValid($document->getUpdate()); - if ($documentSecurity && ! $valid) { + if ($documentSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } } $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -2708,21 +2742,21 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) + fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($relations as &$relation) { if ( \is_array($relation) && \array_values($relation) !== $relation - && ! isset($relation['$id']) + && !isset($relation['$id']) ) { $relation['$id'] = ID::unique(); $relation = new Document($relation); } if ($relation instanceof Document) { $current = Authorization::skip( - fn () => $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId(), $relation->getId()) + fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId()) ); if ($current->isEmpty()) { @@ -2752,46 +2786,46 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $checkPermissions($collection, $document, Database::PERMISSION_CREATE); - try { - $document = $dbForProject->createDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $document); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); - } catch (DuplicateException $exception) { - throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); - } + try { + $document = $dbForProject->createDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $document); + } catch (StructureException $exception) { + throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); + } catch (DuplicateException $exception) { + throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); + } - // Add $collectionId and $databaseId for all documents - $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { - $document->setAttribute('$databaseId', $database->getId()); - $document->setAttribute('$collectionId', $collection->getId()); + // Add $collectionId and $databaseId for all documents + $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { + $document->setAttribute('$databaseId', $database->getId()); + $document->setAttribute('$collectionId', $collection->getId()); - $relationships = \array_filter( - $collection->getAttribute('attributes', []), - fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + $relationships = \array_filter( + $collection->getAttribute('attributes', []), + fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + ); + + foreach ($relationships as $relationship) { + $related = $document->getAttribute($relationship->getAttribute('key')); + + if (empty($related)) { + continue; + } + if (!\is_array($related)) { + $related = [$related]; + } + + $relatedCollectionId = $relationship->getAttribute('relatedCollection'); + $relatedCollection = Authorization::skip( + fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); - foreach ($relationships as $relationship) { - $related = $document->getAttribute($relationship->getAttribute('key')); - - if (empty($related)) { - continue; - } - if (! \is_array($related)) { - $related = [$related]; - } - - $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = Authorization::skip( - fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) - ); - - foreach ($related as $relation) { - if ($relation instanceof Document) { - $processDocument($relatedCollection, $relation); - } + foreach ($related as $relation) { + if ($relation instanceof Document) { + $processDocument($relatedCollection, $relation); } } - }; + } + }; $processDocument($collection, $document); @@ -2822,36 +2856,37 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('sdk.offline.model', '/databases/{databaseId}/collections/{collectionId}/documents') ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') - ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long.', true) + ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - if (! $collection->getAttribute('documentSecurity', false)) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if (!$collection->getAttribute('documentSecurity', false)) { $validator = new Authorization(Database::PERMISSION_READ); - if (! $validator->isValid($collection->getRead())) { + if (!$validator->isValid($collection->getRead())) { $collection = new Document(); } } } - if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { + if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } // Validate queries $queriesValidator = new Documents($collection->getAttribute('attributes'), $collection->getAttribute('indexes')); $validQueries = $queriesValidator->isValid($queries); - if (! $validQueries) { + if (!$validQueries) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $queriesValidator->getDescription()); } @@ -2863,7 +2898,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') if ($cursor) { $documentId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId)); + $cursorDocument = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Document '{$documentId}' for the 'cursor' value not found."); @@ -2874,8 +2909,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $filterQueries = Query::groupByType($queries)['filters']; - $documents = $dbForProject->find('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $queries); - $total = $dbForProject->count('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT); + $documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries); + $total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT); // Add $collectionId and $databaseId for all documents $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database): bool { @@ -2889,7 +2924,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -2898,18 +2933,18 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') if (empty($related)) { continue; } - if (! \is_array($related)) { + if (!\is_array($related)) { $relations = [$related]; } else { $relations = $related; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId)); + $relatedCollection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)); foreach ($relations as $index => $doc) { if ($doc instanceof Document) { - if (! $processDocument($relatedCollection, $doc)) { + if (!$processDocument($relatedCollection, $doc)) { unset($relations[$index]); } } @@ -2926,9 +2961,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') }; // The linter is forcing this indentation - foreach ($documents as $document) { - $processDocument($collection, $document); - } + foreach ($documents as $document) { + $processDocument($collection, $document); + } $response->dynamic(new Document([ 'total' => $total, @@ -2958,16 +2993,17 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { - if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } } @@ -2975,13 +3011,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen // Validate queries $queriesValidator = new DocumentQueriesValidator($collection->getAttribute('attributes')); $validQueries = $queriesValidator->isValid($queries); - if (! $validQueries) { + if (!$validQueries) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $queriesValidator->getDescription()); } $queries = Query::parseQueries($queries); - $document = $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId, $queries); + $document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -2998,7 +3034,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3007,13 +3043,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen if (empty($related)) { continue; } - if (! \is_array($related)) { + if (!\is_array($related)) { $related = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) + fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3050,19 +3086,20 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->inject('locale') ->inject('geodb') ->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); + $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $document = $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId); + $document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3074,13 +3111,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen $offset = $grouped['offset'] ?? 0; $audit = new Audit($dbForProject); - $resource = 'database/'.$databaseId.'/collection/'.$collectionId.'/document/'.$document->getId(); + $resource = 'database/' . $databaseId . '/collection/' . $collectionId . '/document/' . $document->getId(); $logs = $audit->getLogsByResource($resource, $limit, $offset); $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -3108,14 +3145,14 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'], + 'deviceModel' => $device['deviceModel'] ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -3158,29 +3195,30 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->inject('events') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events, string $mode) { + $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array if (empty($data) && \is_null($permissions)) { throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD); } - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { - if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } } // Read permission should not be required for update /** @var Document $document */ - $document = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId)); + $document = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3195,7 +3233,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum // Users can only manage their own roles, API keys and Admin users can manage any $roles = Authorization::getRoles(); - if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles) && ! \is_null($permissions)) { + if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -3207,8 +3245,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (! Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')'); + if (!Authorization::isRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } } @@ -3228,7 +3266,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $setCollection = (function (Document $collection, Document $document) use (&$setCollection, $dbForProject, $database) { $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3248,7 +3286,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) + fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($relations as &$relation) { @@ -3256,14 +3294,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum if ( \is_array($relation) && \array_values($relation) !== $relation - && ! isset($relation['$id']) + && !isset($relation['$id']) ) { $relation['$id'] = ID::unique(); $relation = new Document($relation); } if ($relation instanceof Document) { - $oldDocument = Authorization::skip(fn () => $dbForProject->getDocument( - 'database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId(), + $oldDocument = Authorization::skip(fn() => $dbForProject->getDocument( + 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId() )); $relation->removeAttribute('$collectionId'); @@ -3271,7 +3309,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum // Attribute $collection is required for Utopia. $relation->setAttribute( '$collection', - 'database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId() + 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId() ); if ($oldDocument->isEmpty()) { @@ -3296,8 +3334,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum try { $document = $dbForProject->withRequestTimestamp( $requestTimestamp, - fn () => $dbForProject->updateDocument( - 'database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), + fn() => $dbForProject->updateDocument( + 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $document->getId(), $newDocument ) @@ -3317,7 +3355,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3326,13 +3364,13 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum if (empty($related)) { continue; } - if (! \is_array($related)) { + if (!\is_array($related)) { $related = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) + fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3384,22 +3422,23 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->inject('deletes') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events, Delete $deletes, string $mode) { - $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (! $database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + + if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || ! $collection->getAttribute('enabled')) { - if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } } // Read permission should not be required for delete - $document = Authorization::skip(fn () => $dbForProject->getDocument('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $documentId)); + $document = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3410,18 +3449,18 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu $validator = new Authorization(Database::PERMISSION_DELETE); $valid = $validator->isValid($collection->getDelete()); - if (! $documentSecurity && ! $valid) { + if (!$documentSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } $valid = $valid || $validator->isValid($document->getDelete()); - if ($documentSecurity && ! $valid) { + if ($documentSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3430,13 +3469,13 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu if (empty($related)) { continue; } - if (! \is_array($related)) { + if (!\is_array($related)) { $related = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) + fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3452,10 +3491,10 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu $checkPermissions($collection, $document); - Authorization::skip(fn () => $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) { + Authorization::skip(fn() => $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) { try { $dbForProject->deleteDocument( - 'database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), + 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId ); } catch (RestrictedException) { @@ -3464,7 +3503,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu })); $dbForProject->deleteCachedDocument( - 'database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), + 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId ); @@ -3475,7 +3514,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3484,13 +3523,13 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu if (empty($related)) { continue; } - if (! \is_array($related)) { + if (!\is_array($related)) { $related = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn () => $dbForProject->getDocument('database_'.$database->getInternalId(), $relatedCollectionId) + fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3532,6 +3571,7 @@ App::get('/v1/databases/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { + $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -3565,23 +3605,23 @@ App::get('/v1/databases/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; - } + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; } + } $response->dynamic(new Document([ 'range' => $range, - 'databasesTotal' => $usage[$metrics[0]], + 'databasesTotal' => $usage[$metrics[0]], 'collectionsTotal' => $usage[$metrics[1]], - 'documentsTotal' => $usage[$metrics[2]], + 'documentsTotal' => $usage[$metrics[2]], ]), Response::MODEL_USAGE_DATABASES); }); @@ -3600,7 +3640,8 @@ App::get('/v1/databases/:databaseId/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $range, Response $response, Database $dbForProject) { - $database = $dbForProject->getDocument('databases', $databaseId); + + $database = $dbForProject->getDocument('databases', $databaseId); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -3638,23 +3679,23 @@ App::get('/v1/databases/:databaseId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; - } + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; } + } $response->dynamic(new Document([ 'range' => $range, - 'collectionsTotal' => $usage[$metrics[0]], - 'documentsTotal' => $usage[$metrics[1]], + 'collectionsTotal' => $usage[$metrics[0]], + 'documentsTotal' => $usage[$metrics[1]], ]), Response::MODEL_USAGE_DATABASE); }); @@ -3675,9 +3716,10 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $databaseId, string $range, string $collectionId, Response $response, Database $dbForProject) { - $database = $dbForProject->getDocument('databases', $databaseId); - $collectionDocument = $dbForProject->getDocument('database_'.$database->getInternalId(), $collectionId); - $collection = $dbForProject->getCollection('database_'.$database->getInternalId().'_collection_'.$collectionDocument->getInternalId()); + + $database = $dbForProject->getDocument('databases', $databaseId); + $collectionDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $collectionDocument->getInternalId()); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -3714,21 +3756,21 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; - } + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; } + } $response->dynamic(new Document([ 'range' => $range, - 'documentsTotal' => $usage[$metrics[0]], + 'documentsTotal' => $usage[$metrics[0]], ]), Response::MODEL_USAGE_COLLECTION); }); diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index b7baf560bb..81500f1d27 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -9,40 +9,40 @@ use Appwrite\Event\Func; use Appwrite\Event\Usage; use Appwrite\Event\Validator\Event as ValidatorEvent; use Appwrite\Extend\Exception; -use Appwrite\Task\Validator\Cron; use Appwrite\Utopia\Database\Validator\CustomId; -use Appwrite\Utopia\Database\Validator\Queries\Deployments; -use Appwrite\Utopia\Database\Validator\Queries\Executions; -use Appwrite\Utopia\Database\Validator\Queries\Functions; -use Appwrite\Utopia\Response; -use Executor\Executor; -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\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Roles; use Utopia\Database\Validator\UID; use Utopia\Storage\Device; use Utopia\Storage\Validator\File; use Utopia\Storage\Validator\FileExt; use Utopia\Storage\Validator\FileSize; use Utopia\Storage\Validator\Upload; +use Appwrite\Utopia\Response; use Utopia\Swoole\Request; +use Appwrite\Task\Validator\Cron; +use Appwrite\Utopia\Database\Validator\Queries\Deployments; +use Appwrite\Utopia\Database\Validator\Queries\Executions; +use Appwrite\Utopia\Database\Validator\Queries\Functions; +use Utopia\App; +use Utopia\Database\Database; +use Utopia\Database\Document; +use Utopia\Database\DateTime; +use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Validator\ArrayList; -use Utopia\Validator\Boolean; -use Utopia\Validator\Range; use Utopia\Validator\Text; +use Utopia\Validator\Range; use Utopia\Validator\WhiteList; +use Utopia\Config\Config; +use Executor\Executor; +use Utopia\CLI\Console; +use Utopia\Database\Validator\Roles; +use Utopia\Validator\Boolean; +use Utopia\Database\Exception\Duplicate as DuplicateException; -include_once __DIR__.'/../shared/api.php'; +include_once __DIR__ . '/../shared/api.php'; App::post('/v1/functions') ->groups(['api', 'functions']) @@ -60,9 +60,9 @@ App::post('/v1/functions') ->label('sdk.response.model', Response::MODEL_FUNCTION) ->param('functionId', '', new CustomId(), 'Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Function name. Max length: 128 chars.') - ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 64 characters long.', true) + ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) ->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.') - ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.', true) + ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true) ->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.', true) ->param('enabled', true, new Boolean(), 'Is function enabled?', true) @@ -73,6 +73,7 @@ App::post('/v1/functions') ->inject('events') ->inject('dbForConsole') ->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance, Database $dbForConsole) { + $functionId = ($functionId == 'unique()') ? ID::unique() : $functionId; $function = $dbForProject->createDocument('functions', new Document([ '$id' => $functionId, @@ -86,18 +87,18 @@ App::post('/v1/functions') 'schedule' => $schedule, 'scheduleInternalId' => '', 'timeout' => $timeout, - 'search' => implode(' ', [$functionId, $name, $runtime]), + 'search' => implode(' ', [$functionId, $name, $runtime]) ])); $schedule = Authorization::skip( - fn () => $dbForConsole->createDocument('schedules', new Document([ + fn() => $dbForConsole->createDocument('schedules', new Document([ 'region' => App::getEnv('_APP_REGION', 'default'), // Todo replace with projects region 'resourceType' => 'function', 'resourceId' => $function->getId(), 'resourceInternalId' => $function->getInternalId(), 'resourceUpdatedAt' => DateTime::now(), 'projectId' => $project->getId(), - 'schedule' => $function->getAttribute('schedule'), + 'schedule' => $function->getAttribute('schedule'), 'active' => false, ])) ); @@ -124,14 +125,15 @@ App::get('/v1/functions') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_FUNCTION_LIST) - ->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Functions::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Functions::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { + $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -171,17 +173,17 @@ App::get('/v1/functions/runtimes') ->label('sdk.response.model', Response::MODEL_RUNTIME_LIST) ->inject('response') ->action(function (Response $response) { + $runtimes = Config::getParam('runtimes'); $runtimes = array_map(function ($key) use ($runtimes) { $runtimes[$key]['$id'] = $key; - return $runtimes[$key]; }, array_keys($runtimes)); $response->dynamic(new Document([ 'total' => count($runtimes), - 'runtimes' => $runtimes, + 'runtimes' => $runtimes ]), Response::MODEL_RUNTIME_LIST); }); @@ -224,6 +226,7 @@ App::get('/v1/functions/:functionId/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $functionId, string $range, Response $response, Database $dbForProject) { + $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -267,18 +270,18 @@ App::get('/v1/functions/:functionId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; - } + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; } + } $response->dynamic(new Document([ 'range' => $range, @@ -306,6 +309,7 @@ App::get('/v1/functions/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { + $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -344,18 +348,18 @@ App::get('/v1/functions/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; - } + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; } + } $response->dynamic(new Document([ 'range' => $range, 'functionsTotal' => $usage[$metrics[0]], @@ -385,8 +389,8 @@ App::put('/v1/functions/:functionId') ->label('sdk.response.model', Response::MODEL_FUNCTION) ->param('functionId', '', new UID(), 'Function ID.') ->param('name', '', new Text(128), 'Function name. Max length: 128 chars.') - ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 64 characters long.', true) - ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.', true) + ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) + ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true) ->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true) ->param('enabled', true, new Boolean(), 'Is function enabled?', true) @@ -397,6 +401,7 @@ App::put('/v1/functions/:functionId') ->inject('events') ->inject('dbForConsole') ->action(function (string $functionId, string $name, array $execute, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance, Database $dbForConsole) { + $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -419,7 +424,7 @@ App::put('/v1/functions/:functionId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); + ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $eventsInstance->setParam('functionId', $function->getId()); @@ -449,6 +454,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') ->inject('events') ->inject('dbForConsole') ->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Document $project, Event $events, Database $dbForConsole) { + $function = $dbForProject->getDocument('functions', $functionId); $deployment = $dbForProject->getDocument('deployments', $deploymentId); $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')); @@ -478,7 +484,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); + ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $events @@ -509,13 +515,14 @@ App::delete('/v1/functions/:functionId') ->inject('project') ->inject('dbForConsole') ->action(function (string $functionId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Document $project, Database $dbForConsole) { + $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } - if (! $dbForProject->deleteDocument('functions', $function->getId())) { + if (!$dbForProject->deleteDocument('functions', $function->getId())) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove function from DB'); } @@ -563,6 +570,7 @@ App::post('/v1/functions/:functionId/deployments') ->inject('deviceLocal') ->inject('dbForConsole') ->action(function (string $functionId, string $entrypoint, mixed $code, bool $activate, Request $request, Response $response, Database $dbForProject, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal, Database $dbForConsole) { + $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -589,7 +597,7 @@ App::post('/v1/functions/:functionId/deployments') $fileTmpName = (\is_array($file['tmp_name']) && isset($file['tmp_name'][0])) ? $file['tmp_name'][0] : $file['tmp_name']; $fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size']; - if (! $fileExt->isValid($file['name'])) { // Check if file type is allowed + if (!$fileExt->isValid($file['name'])) { // Check if file type is allowed throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED); } @@ -598,7 +606,7 @@ App::post('/v1/functions/:functionId/deployments') $chunk = 1; $chunks = 1; - if (! empty($contentRange)) { + if (!empty($contentRange)) { $start = $request->getContentRangeStart(); $end = $request->getContentRangeEnd(); $fileSize = $request->getContentRangeSize(); @@ -619,21 +627,21 @@ App::post('/v1/functions/:functionId/deployments') } } - if (! $fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit + if (!$fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE); } - if (! $upload->isValid($fileTmpName)) { + if (!$upload->isValid($fileTmpName)) { throw new Exception(Exception::STORAGE_INVALID_FILE); } // Save to storage $fileSize ??= $deviceLocal->getFileSize($fileTmpName); - $path = $deviceFunctions->getPath($deploymentId.'.'.\pathinfo($fileName, PATHINFO_EXTENSION)); + $path = $deviceFunctions->getPath($deploymentId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION)); $deployment = $dbForProject->getDocument('deployments', $deploymentId); $metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)]; - if (! $deployment->isEmpty()) { + if (!$deployment->isEmpty()) { $chunks = $deployment->getAttribute('chunksTotal', 1); $metadata = $deployment->getAttribute('metadata', []); if ($chunk === -1) { @@ -655,7 +663,7 @@ App::post('/v1/functions/:functionId/deployments') $activeDeployments = $dbForProject->find('deployments', [ Query::equal('activate', [true]), Query::equal('resourceId', [$functionId]), - Query::equal('resourceType', ['functions']), + Query::equal('resourceType', ['functions']) ]); foreach ($activeDeployments as $activeDeployment) { @@ -747,11 +755,12 @@ App::get('/v1/functions/:functionId/deployments') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DEPLOYMENT_LIST) ->param('functionId', '', new UID(), 'Function ID.') - ->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Deployments::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject) { + $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -760,7 +769,7 @@ App::get('/v1/functions/:functionId/deployments') $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -818,6 +827,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId') ->inject('response') ->inject('dbForProject') ->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject) { + $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -863,6 +873,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') ->inject('events') ->inject('deviceFunctions') ->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Device $deviceFunctions) { + $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { throw new Exception(Exception::FUNCTION_NOT_FOUND); @@ -878,7 +889,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') } if ($deviceFunctions->delete($deployment->getAttribute('path', ''))) { - if (! $dbForProject->deleteDocument('deployments', $deployment->getId())) { + if (!$dbForProject->deleteDocument('deployments', $deployment->getId())) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove deployment from DB'); } } @@ -922,6 +933,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') ->inject('project') ->inject('events') ->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) { + $function = $dbForProject->getDocument('functions', $functionId); $deployment = $dbForProject->getDocument('deployments', $deploymentId); @@ -986,10 +998,11 @@ App::post('/v1/functions/:functionId/executions') ->inject('queueForFunctions') ->inject('queueForUsage') ->action(function (string $functionId, string $data, bool $async, Response $response, Document $project, Database $dbForProject, Document $user, Event $events, string $mode, Func $queueForFunctions, Usage $queueForUsage) { + $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty() || ! $function->getAttribute('enabled')) { - if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($function->isEmpty() || !$function->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } } @@ -999,7 +1012,7 @@ App::post('/v1/functions/:functionId/executions') $runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null; if (\is_null($runtime)) { - throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "'.$function->getAttribute('runtime', '').'" is not supported'); + throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); } $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', ''))); @@ -1024,7 +1037,7 @@ App::post('/v1/functions/:functionId/executions') $validator = new Authorization('execute'); - if (! $validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function + if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription()); } @@ -1033,7 +1046,7 @@ App::post('/v1/functions/:functionId/executions') /** @var Document $execution */ $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', new Document([ '$id' => $executionId, - '$permissions' => ! $user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [], + '$permissions' => !$user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [], 'functionInternalId' => $function->getInternalId(), 'functionId' => $function->getId(), 'deploymentInternalId' => $deployment->getInternalId(), @@ -1048,7 +1061,7 @@ App::post('/v1/functions/:functionId/executions') ]))); $jwt = ''; // initialize - if (! $user->isEmpty()) { // If userId exists, generate a JWT for function + if (!$user->isEmpty()) { // If userId exists, generate a JWT for function $sessions = $user->getAttribute('sessions', []); $current = new Document(); @@ -1059,7 +1072,7 @@ App::post('/v1/functions/:functionId/executions') } } - if (! $current->isEmpty()) { + if (!$current->isEmpty()) { $jwtObj = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. $jwt = $jwtObj->encode([ 'userId' => $user->getId(), @@ -1091,7 +1104,6 @@ App::post('/v1/functions/:functionId/executions') $vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { $carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? ''; - return $carry; }, []); @@ -1133,13 +1145,13 @@ App::post('/v1/functions/:functionId/executions') * Sync execution compute usage from */ $queueForUsage - ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int) ($executionResponse['duration'] * 1000))// per project - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int) ($executionResponse['duration'] * 1000))// per function -; + ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($executionResponse['duration'] * 1000))// per project + ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($executionResponse['duration'] * 1000))// per function + ; } catch (\Throwable $th) { $interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt())); $execution - ->setAttribute('duration', (float) $interval->format('%s.%f')) + ->setAttribute('duration', (float)$interval->format('%s.%f')) ->setAttribute('status', 'failed') ->setAttribute('statusCode', $th->getCode()) ->setAttribute('stderr', $th->getMessage()); @@ -1152,7 +1164,7 @@ App::post('/v1/functions/:functionId/executions') $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); - if (! $isPrivilegedUser && ! $isAppUser) { + if (!$isPrivilegedUser && !$isAppUser) { $execution->setAttribute('stdout', ''); $execution->setAttribute('stderr', ''); } @@ -1174,23 +1186,24 @@ App::get('/v1/functions/:functionId/executions') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_EXECUTION_LIST) ->param('functionId', '', new UID(), 'Function ID.') - ->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Executions::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') ->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { + $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty() || ! $function->getAttribute('enabled')) { - if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($function->isEmpty() || !$function->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } } $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -1220,11 +1233,10 @@ App::get('/v1/functions/:functionId/executions') $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); - if (! $isPrivilegedUser && ! $isAppUser) { + if (!$isPrivilegedUser && !$isAppUser) { $results = array_map(function ($execution) { $execution->setAttribute('stdout', ''); $execution->setAttribute('stderr', ''); - return $execution; }, $results); } @@ -1252,10 +1264,11 @@ App::get('/v1/functions/:functionId/executions/:executionId') ->inject('dbForProject') ->inject('mode') ->action(function (string $functionId, string $executionId, Response $response, Database $dbForProject, string $mode) { + $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty() || ! $function->getAttribute('enabled')) { - if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if ($function->isEmpty() || !$function->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } } @@ -1273,7 +1286,7 @@ App::get('/v1/functions/:functionId/executions/:executionId') $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); - if (! $isPrivilegedUser && ! $isAppUser) { + if (!$isPrivilegedUser && !$isAppUser) { $execution->setAttribute('stdout', ''); $execution->setAttribute('stderr', ''); } @@ -1297,7 +1310,7 @@ App::post('/v1/functions/:functionId/variables') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_VARIABLE) ->param('functionId', '', new UID(), 'Function unique ID.', false) - ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: '.Database::LENGTH_KEY.' chars.', false) + ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false) ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false) ->inject('response') ->inject('dbForProject') @@ -1335,7 +1348,7 @@ App::post('/v1/functions/:functionId/variables') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); + ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $dbForProject->deleteCachedDocument('functions', $function->getId()); @@ -1344,7 +1357,7 @@ App::post('/v1/functions/:functionId/variables') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); + ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $response @@ -1434,6 +1447,7 @@ App::put('/v1/functions/:functionId/variables/:variableId') ->inject('dbForProject') ->inject('dbForConsole') ->action(function (string $functionId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject, Database $dbForConsole) { + $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -1452,7 +1466,8 @@ App::put('/v1/functions/:functionId/variables/:variableId') $variable ->setAttribute('key', $key) ->setAttribute('value', $value ?? $variable->getAttribute('value')) - ->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key])); + ->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key])) + ; try { $dbForProject->updateDocument('variables', $variable->getId(), $variable); @@ -1464,7 +1479,7 @@ App::put('/v1/functions/:functionId/variables/:variableId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); + ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $dbForProject->deleteCachedDocument('functions', $function->getId()); @@ -1473,7 +1488,7 @@ App::put('/v1/functions/:functionId/variables/:variableId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); + ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $response->dynamic($variable, Response::MODEL_VARIABLE); @@ -1518,7 +1533,7 @@ App::delete('/v1/functions/:functionId/variables/:variableId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); + ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $dbForProject->deleteCachedDocument('functions', $function->getId()); @@ -1527,7 +1542,7 @@ App::delete('/v1/functions/:functionId/variables/:variableId') $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); + ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); $response->noContent(); diff --git a/app/controllers/api/graphql.php b/app/controllers/api/graphql.php index b4eb5ef620..8ee3b5ac47 100644 --- a/app/controllers/api/graphql.php +++ b/app/controllers/api/graphql.php @@ -42,11 +42,11 @@ App::get('/v1/graphql') 'query' => $query, ]; - if (! empty($operationName)) { + if (!empty($operationName)) { $query['operationName'] = $operationName; } - if (! empty($variables)) { + if (!empty($variables)) { $query['variables'] = \json_decode($variables, true); } @@ -150,11 +150,10 @@ App::post('/v1/graphql') /** * Execute a GraphQL request * - * @param GQLSchema $schema - * @param Adapter $promiseAdapter - * @param array $query + * @param GQLSchema $schema + * @param Adapter $promiseAdapter + * @param array $query * @return array - * * @throws Exception */ function execute( @@ -166,7 +165,7 @@ function execute( $maxComplexity = App::getEnv('_APP_GRAPHQL_MAX_COMPLEXITY', 250); $maxDepth = App::getEnv('_APP_GRAPHQL_MAX_DEPTH', 3); - if (! empty($query) && ! isset($query[0])) { + if (!empty($query) && !isset($query[0])) { $query = [$query]; } if (empty($query)) { @@ -225,7 +224,7 @@ function execute( /** * Parse an "application/graphql" type request * - * @param Request $request + * @param Request $request * @return array */ function parseGraphql(Request $request): array @@ -236,8 +235,8 @@ function parseGraphql(Request $request): array /** * Parse an "multipart/form-data" type request * - * @param array $query - * @param Request $request + * @param array $query + * @param Request $request * @return array */ function parseMultipart(array $query, Request $request): array @@ -249,7 +248,7 @@ function parseMultipart(array $query, Request $request): array foreach ($locations as $location) { $items = &$operations; foreach (\explode('.', $location) as $key) { - if (! isset($items[$key]) || ! \is_array($items[$key])) { + if (!isset($items[$key]) || !\is_array($items[$key])) { $items[$key] = []; } $items = &$items[$key]; @@ -277,7 +276,7 @@ function parseMultipart(array $query, Request $request): array function processResult($result, $debugFlags): array { // Only one query, return the result - if (! isset($result[1])) { + if (!isset($result[1])) { return $result[0]->toArray($debugFlags); } diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index 4cac066cc6..d6a2612f32 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -28,10 +28,11 @@ App::get('/v1/health') ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') ->action(function (Response $response) { + $output = [ 'name' => 'http', 'status' => 'pass', - 'ping' => 0, + 'ping' => 0 ]; $response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS); @@ -46,7 +47,7 @@ App::get('/v1/health/version') ->label('sdk.response.model', Response::MODEL_HEALTH_VERSION) ->inject('response') ->action(function (Response $response) { - $response->dynamic(new Document(['version' => APP_VERSION_STABLE]), Response::MODEL_HEALTH_VERSION); + $response->dynamic(new Document([ 'version' => APP_VERSION_STABLE ]), Response::MODEL_HEALTH_VERSION); }); App::get('/v1/health/db') @@ -63,6 +64,7 @@ App::get('/v1/health/db') ->inject('response') ->inject('pools') ->action(function (Response $response, Group $pools) { + $output = []; $configs = [ @@ -79,22 +81,22 @@ App::get('/v1/health/db') if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } else { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } @@ -120,6 +122,7 @@ App::get('/v1/health/cache') ->inject('response') ->inject('pools') ->action(function (Response $response, Group $pools) { + $output = []; $configs = [ @@ -135,22 +138,22 @@ App::get('/v1/health/cache') if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } else { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } @@ -176,6 +179,7 @@ App::get('/v1/health/queue') ->inject('response') ->inject('pools') ->action(function (Response $response, Group $pools) { + $output = []; $configs = [ @@ -191,22 +195,22 @@ App::get('/v1/health/queue') if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } else { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } @@ -232,6 +236,7 @@ App::get('/v1/health/pubsub') ->inject('response') ->inject('pools') ->action(function (Response $response, Group $pools) { + $output = []; $configs = [ @@ -247,22 +252,22 @@ App::get('/v1/health/pubsub') if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } else { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } @@ -287,6 +292,7 @@ App::get('/v1/health/time') ->label('sdk.response.model', Response::MODEL_HEALTH_TIME) ->inject('response') ->action(function (Response $response) { + /* * Code from: @see https://www.beliefmedia.com.au/query-ntp-time-server */ @@ -299,7 +305,7 @@ App::get('/v1/health/time') \socket_connect($sock, $host, 123); /* Send request */ - $msg = "\010".\str_repeat("\0", 47); + $msg = "\010" . \str_repeat("\0", 47); \socket_send($sock, $msg, \strlen($msg), 0); @@ -324,7 +330,7 @@ App::get('/v1/health/time') $output = [ 'remoteTime' => $timestamp, 'localTime' => \time(), - 'diff' => $diff, + 'diff' => $diff ]; $response->dynamic(new Document($output), Response::MODEL_HEALTH_TIME); @@ -343,7 +349,8 @@ App::get('/v1/health/queue/webhooks') ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') ->action(function (Response $response) { - $response->dynamic(new Document(['size' => Resque::size(Event::WEBHOOK_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE); + + $response->dynamic(new Document([ 'size' => Resque::size(Event::WEBHOOK_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); App::get('/v1/health/queue/logs') @@ -359,7 +366,8 @@ App::get('/v1/health/queue/logs') ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') ->action(function (Response $response) { - $response->dynamic(new Document(['size' => Resque::size(Event::AUDITS_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE); + + $response->dynamic(new Document([ 'size' => Resque::size(Event::AUDITS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); App::get('/v1/health/queue/certificates') @@ -375,7 +383,8 @@ App::get('/v1/health/queue/certificates') ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') ->action(function (Response $response) { - $response->dynamic(new Document(['size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE); + + $response->dynamic(new Document([ 'size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); App::get('/v1/health/queue/functions') @@ -393,7 +402,7 @@ App::get('/v1/health/queue/functions') ->inject('response') ->action(function (Connection $queue, Response $response) { $client = new Client(Event::FUNCTIONS_QUEUE_NAME, $queue); - $response->dynamic(new Document(['size' => $client->sumProcessingJobs()]), Response::MODEL_HEALTH_QUEUE); + $response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); App::get('/v1/health/storage/local') @@ -409,30 +418,31 @@ App::get('/v1/health/storage/local') ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') ->action(function (Response $response) { + $checkStart = \microtime(true); foreach ( [ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES, + 'Uploads' => APP_STORAGE_UPLOADS, + 'Cache' => APP_STORAGE_CACHE, + 'Config' => APP_STORAGE_CONFIG, + 'Certs' => APP_STORAGE_CERTIFICATES ] as $key => $volume ) { $device = new Local($volume); - if (! \is_readable($device->getRoot())) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device '.$key.' dir is not readable'); + if (!\is_readable($device->getRoot())) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device ' . $key . ' dir is not readable'); } - if (! \is_writable($device->getRoot())) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device '.$key.' dir is not writable'); + if (!\is_writable($device->getRoot())) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device ' . $key . ' dir is not writable'); } } $output = [ 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000), + 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]; $response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS); @@ -451,9 +461,10 @@ App::get('/v1/health/anti-virus') ->label('sdk.response.model', Response::MODEL_HEALTH_ANTIVIRUS) ->inject('response') ->action(function (Response $response) { + $output = [ 'status' => '', - 'version' => '', + 'version' => '' ]; if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'disabled') { // Check if scans are enabled @@ -488,6 +499,7 @@ App::get('/v1/health/stats') // Currently only used internally ->inject('register') ->inject('deviceFiles') ->action(function (Response $response, Registry $register, Device $deviceFiles) { + $cache = $register->get('cache'); $cacheStats = $cache->info(); @@ -495,7 +507,7 @@ App::get('/v1/health/stats') // Currently only used internally $response ->json([ 'storage' => [ - 'used' => Storage::human($deviceFiles->getDirectorySize($deviceFiles->getRoot().'/')), + 'used' => Storage::human($deviceFiles->getDirectorySize($deviceFiles->getRoot() . '/')), 'partitionTotal' => Storage::human($deviceFiles->getPartitionTotalSpace()), 'partitionFree' => Storage::human($deviceFiles->getPartitionFreeSpace()), ], diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index 5fd423349a..29b4932543 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -1,7 +1,7 @@ getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); - $output['continent'] = $locale->getText('continents.'.strtolower($record['continent']['code']), $locale->getText('locale.country.unknown')); + $output['country'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output['continent'] = $locale->getText('continents.' . strtolower($record['continent']['code']), $locale->getText('locale.country.unknown')); $output['continentCode'] = $record['continent']['code']; $output['eu'] = (\in_array($record['country']['iso_code'], $eu)) ? true : false; @@ -62,9 +62,9 @@ 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', 'public, max-age=' . $time) + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache + ; $response->dynamic(new Document($output), Response::MODEL_LOCALE); }); @@ -111,7 +111,7 @@ App::get('/v1/locale/countries') foreach ($list as $value) { $output[] = new Document([ - 'name' => $locale->getText('countries.'.strtolower($value)), + 'name' => $locale->getText('countries.' . strtolower($value)), 'code' => $value, ]); } @@ -143,9 +143,9 @@ App::get('/v1/locale/countries/eu') $output = []; foreach ($eu as $code) { - if ($locale->getText('countries.'.strtolower($code), false) !== false) { + if ($locale->getText('countries.' . strtolower($code), false) !== false) { $output[] = new Document([ - 'name' => $locale->getText('countries.'.strtolower($code)), + 'name' => $locale->getText('countries.' . strtolower($code)), 'code' => $code, ]); } @@ -180,11 +180,11 @@ App::get('/v1/locale/countries/phones') \asort($list); foreach ($list as $code => $name) { - if ($locale->getText('countries.'.strtolower($code), false) !== false) { + if ($locale->getText('countries.' . strtolower($code), false) !== false) { $output[] = new Document([ - 'code' => '+'.$list[$code], + 'code' => '+' . $list[$code], 'countryCode' => $code, - 'countryName' => $locale->getText('countries.'.strtolower($code)), + 'countryName' => $locale->getText('countries.' . strtolower($code)), ]); } } @@ -212,7 +212,7 @@ App::get('/v1/locale/continents') foreach ($list as $value) { $output[] = new Document([ - 'name' => $locale->getText('continents.'.strtolower($value)), + 'name' => $locale->getText('continents.' . strtolower($value)), 'code' => $value, ]); } @@ -246,6 +246,7 @@ App::get('/v1/locale/currencies') $response->dynamic(new Document(['currencies' => $list, 'total' => \count($list)]), Response::MODEL_CURRENCY_LIST); }); + App::get('/v1/locale/languages') ->desc('List Languages') ->groups(['api', 'locale']) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index a2d7cc6419..1ff95fbeea 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -25,35 +25,35 @@ App::get('/v1/messaging/providers') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER_LIST) - ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) ->inject('dbForProject') ->inject('response') ->action(function (array $queries, Database $dbForProject, Response $response) { - $queries = Query::parseQueries($queries); + $queries = Query::parseQueries($queries); - // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); - $cursor = reset($cursor); + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); - if ($cursor) { - $providerId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ - Query::equal('$id', [$providerId]), - Query::limit(1), - ])); + if ($cursor) { + $providerId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ + Query::equal('$id', [$providerId]), + Query::limit(1), + ])); - if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { - throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); - } + if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); + } - $cursor->setValue($cursorDocument[0]); - } + $cursor->setValue($cursorDocument[0]); + } - $filterQueries = Query::groupByType($queries)['filters']; - $response->dynamic(new Document([ - 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), - 'indexes' => $dbForProject->find('providers', $queries), - ]), Response::MODEL_PROVIDER_LIST); + $filterQueries = Query::groupByType($queries)['filters']; + $response->dynamic(new Document([ + 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), + 'indexes' => $dbForProject->find('providers', $queries), + ]), Response::MODEL_PROVIDER_LIST); }); App::get('/v1/messaging/providers/:id') @@ -71,13 +71,13 @@ App::get('/v1/messaging/providers/:id') ->inject('dbForProject') ->inject('response') ->action(function (string $id, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } - $response->dynamic($provider, Response::MODEL_PROVIDER); + $response->dynamic($provider, Response::MODEL_PROVIDER); }); /** @@ -101,18 +101,18 @@ App::post('/v1/messaging/providers/mailgun') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'mailgun', - 'type' => 'email', - 'credentials' => [ - 'apiKey' => $apiKey, - 'domain' => $domain, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'mailgun', + 'type' => 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + 'domain' => $domain, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/mailgun') @@ -134,39 +134,39 @@ App::patch('/v1/messaging/providers/:id/mailgun') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'mailgun') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); - } + if ($providerAttr !== 'mailgun') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($apiKey || $domain) { - // Check if all five variables are present - if ($apiKey && $domain) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'domain' => $domain, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($apiKey || $domain) { + // Check if all five variables are present + if ($apiKey && $domain) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'domain' => $domain + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/sendgrid') @@ -186,17 +186,17 @@ App::post('/v1/messaging/providers/sendgrid') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'sendgrid', - 'type' => 'email', - 'credentials' => [ - 'apiKey' => $apiKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'sendgrid', + 'type' => 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/sendgrid') @@ -217,32 +217,32 @@ App::patch('/v1/messaging/providers/:id/sendgrid') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'sendgrid') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); - } + if ($providerAttr !== 'sendgrid') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($apiKey) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - ]); - } + if ($apiKey) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey + ]); + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); /** @@ -266,18 +266,18 @@ App::post('/v1/messaging/providers/msg91') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'msg91', - 'type' => 'sms', - 'credentials' => [ - 'senderId' => $senderId, - 'authKey' => $authKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'msg91', + 'type' => 'sms', + 'credentials' => [ + 'senderId' => $senderId, + 'authKey' => $authKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/msg91') @@ -299,39 +299,39 @@ App::patch('/v1/messaging/providers/:id/msg91') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'msg91') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); - } + if ($providerAttr !== 'msg91') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($senderId || $authKey) { - // Check if all five variables are present - if ($senderId && $authKey) { - $provider->setAttribute('credentials', [ - 'senderId' => $senderId, - 'authKey' => $authKey, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($senderId || $authKey) { + // Check if all five variables are present + if ($senderId && $authKey) { + $provider->setAttribute('credentials', [ + 'senderId' => $senderId, + 'authKey' => $authKey + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/telesign') @@ -352,18 +352,18 @@ App::post('/v1/messaging/providers/telesign') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $username, string $password, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'telesign', - 'type' => 'sms', - 'credentials' => [ - 'username' => $username, - 'password' => $password, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'telesign', + 'type' => 'sms', + 'credentials' => [ + 'username' => $username, + 'password' => $password, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/telesign') @@ -385,39 +385,39 @@ App::patch('/v1/messaging/providers/:id/telesign') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $username, string $password, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'telesign') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); - } + if ($providerAttr !== 'telesign') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($username || $password) { - // Check if all five variables are present - if ($username && $password) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'password' => $password, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($username || $password) { + // Check if all five variables are present + if ($username && $password) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'password' => $password + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/textmagic') @@ -438,18 +438,18 @@ App::post('/v1/messaging/providers/textmagic') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'text-magic', - 'type' => 'sms', - 'credentials' => [ - 'username' => $username, - 'apiKey' => $apiKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'text-magic', + 'type' => 'sms', + 'credentials' => [ + 'username' => $username, + 'apiKey' => $apiKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/textmagic') @@ -471,39 +471,39 @@ App::patch('/v1/messaging/providers/:id/textmagic') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'text-magic') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); - } + if ($providerAttr !== 'text-magic') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($username || $apiKey) { - // Check if all five variables are present - if ($username && $apiKey) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'apiKey' => $apiKey, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($username || $apiKey) { + // Check if all five variables are present + if ($username && $apiKey) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'apiKey' => $apiKey + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/twilio') @@ -524,18 +524,18 @@ App::post('/v1/messaging/providers/twilio') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'twilio', - 'type' => 'sms', - 'credentials' => [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'twilio', + 'type' => 'sms', + 'credentials' => [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/twilio') @@ -557,39 +557,39 @@ App::patch('/v1/messaging/providers/:id/twilio') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'twilio') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); - } + if ($providerAttr !== 'twilio') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($accountSid || $authToken) { - // Check if all five variables are present - if ($accountSid && $authToken) { - $provider->setAttribute('credentials', [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($accountSid || $authToken) { + // Check if all five variables are present + if ($accountSid && $authToken) { + $provider->setAttribute('credentials', [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/vonage') @@ -610,18 +610,18 @@ App::post('/v1/messaging/providers/vonage') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'vonage', - 'type' => 'sms', - 'credentials' => [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'vonage', + 'type' => 'sms', + 'credentials' => [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/vonage') @@ -643,39 +643,39 @@ App::patch('/v1/messaging/providers/:id/vonage') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'vonage') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); - } + if ($providerAttr !== 'vonage') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($apiKey || $apiSecret) { - // Check if all five variables are present - if ($apiKey && $apiSecret) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($apiKey || $apiSecret) { + // Check if all five variables are present + if ($apiKey && $apiSecret) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); /** @@ -698,17 +698,17 @@ App::post('/v1/messaging/providers/fcm') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $serverKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'fcm', - 'type' => 'push', - 'credentials' => [ - 'serverKey' => $serverKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'fcm', + 'type' => 'push', + 'credentials' => [ + 'serverKey' => $serverKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/fcm') @@ -729,30 +729,30 @@ App::patch('/v1/messaging/providers/:id/fcm') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $serverKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'fcm') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); - } + if ($providerAttr !== 'fcm') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($serverKey) { - $provider->setAttribute('credentials', ['serverKey' => $serverKey]); - } + if ($serverKey) { + $provider->setAttribute('credentials', ['serverKey' => $serverKey]); + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::post('/v1/messaging/providers/apns') @@ -776,21 +776,21 @@ App::post('/v1/messaging/providers/apns') ->inject('dbForProject') ->inject('response') ->action(function (string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'apns', - 'type' => 'push', - 'credentials' => [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'apns', + 'type' => 'push', + 'credentials' => [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::patch('/v1/messaging/providers/:id/apns') @@ -815,42 +815,42 @@ App::patch('/v1/messaging/providers/:id/apns') ->inject('dbForProject') ->inject('response') ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'apns') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); - } + if ($providerAttr !== 'apns') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { - // Check if all five variables are present - if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { - $provider->setAttribute('credentials', [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } - } + if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { + // Check if all five variables are present + if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { + $provider->setAttribute('credentials', [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); }); App::delete('/v1/messaging/providers/:id') @@ -869,16 +869,16 @@ App::delete('/v1/messaging/providers/:id') ->inject('dbForProject') ->inject('response') ->action(function (string $id, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } - $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $dbForProject->deleteDocument('providers', $provider->getId()); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $dbForProject->deleteDocument('providers', $provider->getId()); - $response->noContent(); + $response->noContent(); }); App::post('/v1/messaging/messages/email') @@ -904,30 +904,30 @@ App::post('/v1/messaging/messages/email') ->inject('events') ->inject('response') ->action(function (string $providerId, string $to, string $subject, string $content, string $from, string $html, DateTime $deliveryTime, Database $dbForProject, Event $eventsInstance, Response $response) { - $provider = $dbForProject->getDocument('providers', $providerId); + $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } - $message = $dbForProject->createDocument('messages', new Document([ - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), - 'to' => $to, - 'data' => [ - 'subject' => $subject, - 'content' => $content, - ], - 'deliveryTime' => $deliveryTime, - 'deliveryError' => null, - 'deliveredTo' => null, - 'delivered' => false, - 'search' => null, - ])); + $message = $dbForProject->createDocument('messages', new Document([ + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'to' => $to, + 'data' => [ + 'subject' => $subject, + 'content' => $content, + ], + 'deliveryTime' => $deliveryTime, + 'deliveryError' => null, + 'deliveredTo' => null, + 'delivered' => false, + 'search' => null, + ])); - $eventsInstance->setParam('messageId', $message->getId()); + $eventsInstance->setParam('messageId', $message->getId()); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_MESSAGE); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_MESSAGE); }); diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index 23ebc29362..8d961a0450 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -28,7 +28,7 @@ use Utopia\Validator\Text; use Utopia\Validator\URL; use Utopia\Validator\WhiteList; -include_once __DIR__.'/../shared/api.php'; +include_once __DIR__ . '/../shared/api.php'; App::post('/v1/migrations/appwrite') ->groups(['api', 'migrations']) @@ -110,7 +110,7 @@ App::post('/v1/migrations/firebase/oauth') $firebase = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' ); $identity = $dbForConsole->findOne('identities', [ @@ -141,7 +141,7 @@ App::post('/v1/migrations/firebase/oauth') $identity = $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $firebase->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry(''))); $dbForConsole->updateDocument('identities', $identity->getId(), $identity); } @@ -167,7 +167,7 @@ App::post('/v1/migrations/firebase/oauth') 'resources' => $resources, 'statusCounters' => '{}', 'resourceData' => '{}', - 'errors' => [], + 'errors' => [] ])); $events->setParam('migrationId', $migration->getId()); @@ -368,14 +368,14 @@ App::get('/v1/migrations') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MIGRATION_LIST) - ->param('queries', [], new Migrations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Migrations::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Migrations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Migrations::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -505,7 +505,7 @@ App::get('/v1/migrations/firebase/report/oauth') $firebase = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' ); $identity = $dbForConsole->findOne('identities', [ @@ -536,7 +536,7 @@ App::get('/v1/migrations/firebase/report/oauth') $identity = $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $firebase->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry(''))); $dbForConsole->updateDocument('identities', $identity->getId(), $identity); } @@ -597,7 +597,7 @@ App::get('/v1/migrations/firebase/connect') $oauth2 = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' ); $url = $oauth2->getLoginURL(); @@ -611,7 +611,7 @@ App::get('/v1/migrations/firebase/redirect') ->desc('Capture and receive data on Firebase authorization') ->groups(['api', 'migrations']) ->label('scope', 'public') - ->label('error', __DIR__.'/../../views/general/error.phtml') + ->label('error', __DIR__ . '/../../views/general/error.phtml') ->param('code', '', new Text(2048), 'OAuth2 code.', true) ->inject('user') ->inject('project') @@ -635,7 +635,7 @@ App::get('/v1/migrations/firebase/redirect') $project = $dbForConsole->getDocument('projects', $projectId); if (empty($redirect)) { - $redirect = $request->getProtocol().'://'.$request->getHostname().'/console/project-$projectId/settings/migrations'; + $redirect = $request->getProtocol() . '://' . $request->getHostname() . '/console/project-$projectId/settings/migrations'; } if ($project->isEmpty()) { @@ -648,11 +648,11 @@ App::get('/v1/migrations/firebase/redirect') } // OAuth Authroization - if (! empty($code)) { + if (!empty($code)) { $oauth2 = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' ); $accessToken = $oauth2->getAccessToken($code); @@ -678,17 +678,17 @@ App::get('/v1/migrations/firebase/redirect') Query::equal('providerEmail', [$email]), ]); - if ($identity !== false && ! $identity->isEmpty()) { + if ($identity !== false && !$identity->isEmpty()) { if ($identity->getAttribute('userInternalId', '') !== $user->getInternalId()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } } - if ($identity !== false && ! $identity->isEmpty()) { + if ($identity !== false && !$identity->isEmpty()) { $identity = $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry)); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry)); $dbForConsole->updateDocument('identities', $identity->getId(), $identity); } else { @@ -706,7 +706,7 @@ App::get('/v1/migrations/firebase/redirect') 'providerEmail' => $email, 'providerAccessToken' => $accessToken, 'providerRefreshToken' => $refreshToken, - 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry), + 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry), ])); } } else { @@ -738,7 +738,7 @@ App::get('/v1/migrations/firebase/projects') $firebase = new OAuth2Firebase( App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), - $request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect' + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' ); $identity = $dbForConsole->findOne('identities', [ @@ -781,7 +781,7 @@ App::get('/v1/migrations/firebase/projects') $identity = $identity ->setAttribute('providerAccessToken', $accessToken) ->setAttribute('providerRefreshToken', $refreshToken) - ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $firebase->getAccessTokenExpiry(''))); + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry(''))); $dbForConsole->updateDocument('identities', $identity->getId(), $identity); } @@ -964,7 +964,7 @@ App::delete('/v1/migrations/:migrationId') throw new Exception(Exception::MIGRATION_NOT_FOUND); } - if (! $dbForProject->deleteDocument('migrations', $migration->getId())) { + if (!$dbForProject->deleteDocument('migrations', $migration->getId())) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove migration from DB', 500); } diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index 0146f1c19f..0f05c6f497 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -4,6 +4,7 @@ use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Config\Config; use Utopia\Database\Database; +use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; @@ -23,6 +24,7 @@ App::get('/v1/project/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { + $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -35,7 +37,7 @@ App::get('/v1/project/usage') METRIC_DATABASES, METRIC_USERS, METRIC_BUCKETS, - METRIC_FILES_STORAGE, + METRIC_FILES_STORAGE ]; Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { @@ -58,23 +60,25 @@ App::get('/v1/project/usage') } }); + $format = match ($days['period']) { '1h' => 'Y-m-d\TH:00:00.000P', '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; - } + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; } + } + $response->dynamic(new Document([ 'range' => $range, diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index f28f5197cb..6fff6b324b 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1,22 +1,19 @@ groups(['projects']) @@ -63,7 +64,7 @@ App::post('/v1/projects') ->param('projectId', '', new ProjectId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can\'t start with a special char. Max length is 36 chars.') ->param('name', null, new Text(128), 'Project name. Max length: 128 chars.') ->param('teamId', '', new UID(), 'Team unique ID.') - ->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn ($config) => ! $config['disabled']))), 'Project Region.', true) + ->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn($config) => !$config['disabled']))), 'Project Region.', true) ->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true) ->param('logo', '', new Text(1024), 'Project logo.', true) ->param('url', '', new URL(), 'Project URL.', true) @@ -78,6 +79,8 @@ App::post('/v1/projects') ->inject('cache') ->inject('pools') ->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools) { + + $team = $dbForConsole->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -161,7 +164,7 @@ App::post('/v1/projects') 'domains' => null, 'auths' => $auths, 'search' => implode(' ', [$projectId, $name]), - 'database' => $database, + 'database' => $database ])); } catch (Duplicate $th) { throw new Exception(Exception::PROJECT_ALREADY_EXISTS); @@ -198,7 +201,7 @@ App::post('/v1/projects') 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '', + 'format' => $attribute['format'] ?? '' ]); } @@ -229,14 +232,15 @@ App::get('/v1/projects') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT_LIST) - ->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Projects::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Projects::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForConsole') ->action(function (array $queries, string $search, Response $response, Database $dbForConsole) { + $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -277,6 +281,7 @@ App::get('/v1/projects/:projectId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -310,6 +315,7 @@ App::patch('/v1/projects/:projectId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $name, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -347,6 +353,7 @@ App::patch('/v1/projects/:projectId/team') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $teamId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); $team = $dbForConsole->getDocument('teams', $teamId); @@ -382,11 +389,12 @@ App::patch('/v1/projects/:projectId/service') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])), true), 'Service name.') + ->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])), true), 'Service name.') ->param('status', null, new Boolean(), 'Service status.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $service, bool $status, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -416,13 +424,14 @@ App::patch('/v1/projects/:projectId/service/all') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, bool $status, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { throw new Exception(Exception::PROJECT_NOT_FOUND); } - $allServices = array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])); + $allServices = array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])); $services = []; foreach ($allServices as $service) { @@ -452,6 +461,7 @@ App::patch('/v1/projects/:projectId/oauth2') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $provider, ?string $appId, ?string $secret, ?bool $enabled, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -461,15 +471,15 @@ App::patch('/v1/projects/:projectId/oauth2') $providers = $project->getAttribute('authProviders', []); if ($appId !== null) { - $providers[$provider.'Appid'] = $appId; + $providers[$provider . 'Appid'] = $appId; } if ($secret !== null) { - $providers[$provider.'Secret'] = $secret; + $providers[$provider . 'Secret'] = $secret; } if ($enabled !== null) { - $providers[$provider.'Enabled'] = $enabled; + $providers[$provider . 'Enabled'] = $enabled; } $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('authProviders', $providers)); @@ -492,6 +502,7 @@ App::patch('/v1/projects/:projectId/auth/limit') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -522,6 +533,7 @@ App::patch('/v1/projects/:projectId/auth/duration') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, int $duration, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -548,11 +560,12 @@ App::patch('/v1/projects/:projectId/auth/:method') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: '.implode(',', \array_keys(Config::getParam('auth'))), false) + ->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: ' . implode(',', \array_keys(Config::getParam('auth'))), false) ->param('status', false, new Boolean(true), 'Set the status of this auth method.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $method, bool $status, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); $auth = Config::getParam('auth')[$method] ?? []; $authKey = $auth['key'] ?? ''; @@ -581,10 +594,11 @@ App::patch('/v1/projects/:projectId/auth/password-history') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is'.APP_LIMIT_USER_PASSWORD_HISTORY.'. Default value is 0') + ->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is' . APP_LIMIT_USER_PASSWORD_HISTORY . '. Default value is 0') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -615,6 +629,7 @@ App::patch('/v1/projects/:projectId/auth/password-dictionary') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, bool $enabled, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -645,6 +660,7 @@ App::patch('/v1/projects/:projectId/auth/personal-data') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, bool $enabled, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -671,10 +687,11 @@ App::patch('/v1/projects/:projectId/auth/max-sessions') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-'.APP_LIMIT_USER_SESSIONS_MAX.'. Default is '.APP_LIMIT_USER_SESSIONS_DEFAULT) + ->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-' . APP_LIMIT_USER_SESSIONS_MAX . '. Default is ' . APP_LIMIT_USER_SESSIONS_DEFAULT) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -713,9 +730,10 @@ App::delete('/v1/projects/:projectId') $deletes ->setType(DELETE_TYPE_DOCUMENT) - ->setDocument($project); + ->setDocument($project) + ; - if (! $dbForConsole->deleteDocument('projects', $projectId)) { + if (!$dbForConsole->deleteDocument('projects', $projectId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove project from DB'); } @@ -736,7 +754,7 @@ App::post('/v1/projects/:projectId/webhooks') ->label('sdk.response.model', Response::MODEL_WEBHOOK) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.') - ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.') + ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') ->param('url', null, new URL(['http', 'https']), 'Webhook URL.') ->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.') ->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true) @@ -744,6 +762,7 @@ App::post('/v1/projects/:projectId/webhooks') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -793,6 +812,7 @@ App::get('/v1/projects/:projectId/webhooks') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -825,6 +845,7 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -856,7 +877,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->param('projectId', '', new UID(), 'Project unique ID.') ->param('webhookId', '', new UID(), 'Webhook unique ID.') ->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.') - ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.') + ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') ->param('url', null, new URL(['http', 'https']), 'Webhook URL.') ->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.') ->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true) @@ -864,6 +885,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -887,7 +909,8 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->setAttribute('url', $url) ->setAttribute('security', $security) ->setAttribute('httpUser', $httpUser) - ->setAttribute('httpPass', $httpPass); + ->setAttribute('httpPass', $httpPass) + ; $dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook); $dbForConsole->deleteCachedDocument('projects', $project->getId()); @@ -910,6 +933,7 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -947,6 +971,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -983,11 +1008,12 @@ App::post('/v1/projects/:projectId/keys') ->label('sdk.response.model', Response::MODEL_KEY) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') - ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' scopes are allowed.') + ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.') ->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1034,6 +1060,7 @@ App::get('/v1/projects/:projectId/keys') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1066,6 +1093,7 @@ App::get('/v1/projects/:projectId/keys/:keyId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1097,11 +1125,12 @@ App::put('/v1/projects/:projectId/keys/:keyId') ->param('projectId', '', new UID(), 'Project unique ID.') ->param('keyId', '', new UID(), 'Key unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') - ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.') + ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') ->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $keyId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1120,7 +1149,8 @@ App::put('/v1/projects/:projectId/keys/:keyId') $key ->setAttribute('name', $name) ->setAttribute('scopes', $scopes) - ->setAttribute('expire', $expire); + ->setAttribute('expire', $expire) + ; $dbForConsole->updateDocument('keys', $key->getId(), $key); @@ -1143,6 +1173,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1205,7 +1236,7 @@ App::post('/v1/projects/:projectId/platforms') 'name' => $name, 'key' => $key, 'store' => $store, - 'hostname' => $hostname, + 'hostname' => $hostname ]); $platform = $dbForConsole->createDocument('platforms', $platform); @@ -1231,6 +1262,7 @@ App::get('/v1/projects/:projectId/platforms') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1263,6 +1295,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1319,7 +1352,8 @@ App::put('/v1/projects/:projectId/platforms/:platformId') ->setAttribute('name', $name) ->setAttribute('key', $key) ->setAttribute('store', $store) - ->setAttribute('hostname', $hostname); + ->setAttribute('hostname', $hostname) + ; $dbForConsole->updateDocument('platforms', $platform->getId(), $platform); @@ -1342,6 +1376,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1381,6 +1416,7 @@ App::post('/v1/projects/:projectId/domains') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $domain, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1392,17 +1428,17 @@ App::post('/v1/projects/:projectId/domains') } $document = $dbForConsole->findOne('domains', [ - Query::equal('domain', [$domain]), + Query::equal('domain', [$domain]) ]); - if ($document && ! $document->isEmpty()) { + if ($document && !$document->isEmpty()) { throw new Exception(Exception::DOMAIN_ALREADY_EXISTS); } $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); - if (! $target->isKnown() || $target->isTest()) { - throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target ('.$target->get().'). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.'); + if (!$target->isKnown() || $target->isTest()) { + throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target (' . $target->get() . '). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.'); } $domain = new Domain($domain); @@ -1447,6 +1483,7 @@ App::get('/v1/projects/:projectId/domains') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1479,6 +1516,7 @@ App::get('/v1/projects/:projectId/domains/:domainId') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1512,6 +1550,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1529,8 +1568,8 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); - if (! $target->isKnown() || $target->isTest()) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.'); + if (!$target->isKnown() || $target->isTest()) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.'); } if ($domain->getAttribute('verification') === true) { @@ -1539,10 +1578,11 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $validator = new CNAME($target->get()); // Verify Domain with DNS records - if (! $validator->isValid($domain->getAttribute('domain', ''))) { + if (!$validator->isValid($domain->getAttribute('domain', ''))) { throw new Exception(Exception::DOMAIN_VERIFICATION_FAILED); } + $dbForConsole->updateDocument('domains', $domain->getId(), $domain->setAttribute('verification', true)); $dbForConsole->deleteCachedDocument('projects', $project->getId()); @@ -1570,6 +1610,7 @@ App::delete('/v1/projects/:projectId/domains/:domainId') ->inject('dbForConsole') ->inject('deletes') ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole, Delete $deletes) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1622,6 +1663,7 @@ App::patch('/v1/projects/:projectId/smtp') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, bool $enabled, string $sender, string $host, int $port, string $username, string $password, string $secure, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1639,7 +1681,7 @@ App::patch('/v1/projects/:projectId/smtp') $mail->SMTPAutoTLS = false; $valid = $mail->SmtpConnect(); - if (! $valid) { + if (!$valid) { throw new Exception(Exception::GENERAL_SMTP_DISABLED); } @@ -1670,10 +1712,11 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale') ->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type') - ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1681,11 +1724,11 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale') } $templates = $project->getAttribute('templates', []); - $template = $templates['sms.'.$type.'-'.$locale] ?? null; + $template = $templates['sms.' . $type . '-' . $locale] ?? null; if (is_null($template)) { $template = [ - 'message' => Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl')->render(), + 'message' => Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl')->render(), ]; } @@ -1707,10 +1750,11 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale') ->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type') - ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1718,11 +1762,11 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale') } $templates = $project->getAttribute('templates', []); - $template = $templates['email.'.$type.'-'.$locale] ?? null; + $template = $templates['email.' . $type . '-' . $locale] ?? null; $localeObj = new Locale($locale); if (is_null($template)) { - $message = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); $message = $message ->setParam('{{hello}}', $localeObj->getText("emails.{$type}.hello")) ->setParam('{{name}}', '') @@ -1737,12 +1781,12 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale') ->render(); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($localeObj->getText('emails.sender'), $project->getAttribute('name')); - $from = empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')) : $from; + $from = empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from; $template = [ 'message' => $message, - 'subject' => $localeObj->getText('emails.'.$type.'.subject'), + 'subject' => $localeObj->getText('emails.' . $type . '.subject'), 'senderEmail' => App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', ''), - 'senderName' => $from, + 'senderName' => $from ]; } @@ -1764,11 +1808,12 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale') ->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type') - ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->param('message', '', new Text(0), 'Template message') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, string $message, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1776,8 +1821,8 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale') } $templates = $project->getAttribute('templates', []); - $templates['sms.'.$type.'-'.$locale] = [ - 'message' => $message, + $templates['sms.' . $type . '-' . $locale] = [ + 'message' => $message ]; $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates)); @@ -1801,7 +1846,7 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale') ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type') - ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->param('senderName', '', new Text(255), 'Name of the email sender') ->param('senderEmail', '', new Email(), 'Email of the sender') ->param('subject', '', new Text(255), 'Email Subject') @@ -1810,6 +1855,7 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, string $senderName, string $senderEmail, string $subject, string $message, string $replyTo, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1817,12 +1863,12 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale') } $templates = $project->getAttribute('templates', []); - $templates['email.'.$type.'-'.$locale] = [ + $templates['email.' . $type . '-' . $locale] = [ 'senderName' => $senderName, 'senderEmail' => $senderEmail, 'subject' => $subject, 'replyTo' => $replyTo, - 'message' => $message, + 'message' => $message ]; $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates)); @@ -1834,7 +1880,7 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale') 'senderEmail' => $senderEmail, 'subject' => $subject, 'replyTo' => $replyTo, - 'message' => $message, + 'message' => $message ]), Response::MODEL_EMAIL_TEMPLATE); }); @@ -1850,10 +1896,11 @@ App::delete('/v1/projects/:projectId/templates/sms/:type/:locale') ->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type') - ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1861,20 +1908,20 @@ App::delete('/v1/projects/:projectId/templates/sms/:type/:locale') } $templates = $project->getAttribute('templates', []); - $template = $templates['sms.'.$type.'-'.$locale] ?? null; + $template = $templates['sms.' . $type . '-' . $locale] ?? null; if (is_null($template)) { throw new Exception(Exception::PROJECT_TEMPLATE_DEFAULT_DELETION); } - unset($template['sms.'.$type.'-'.$locale]); + unset($template['sms.' . $type . '-' . $locale]); $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates)); $response->dynamic(new Document([ 'type' => $type, 'locale' => $locale, - 'message' => $template['message'], + 'message' => $template['message'] ]), Response::MODEL_SMS_TEMPLATE); }); @@ -1890,10 +1937,11 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale') ->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type') - ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1901,13 +1949,13 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale') } $templates = $project->getAttribute('templates', []); - $template = $templates['email.'.$type.'-'.$locale] ?? null; + $template = $templates['email.' . $type . '-' . $locale] ?? null; if (is_null($template)) { throw new Exception(Exception::PROJECT_TEMPLATE_DEFAULT_DELETION); } - unset($templates['email.'.$type.'-'.$locale]); + unset($templates['email.' . $type . '-' . $locale]); $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates)); @@ -1918,6 +1966,6 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale') 'senderEmail' => $template['senderEmail'], 'subject' => $template['subject'], 'replyTo' => $template['replyTo'], - 'message' => $template['message'], + 'message' => $template['message'] ]), Response::MODEL_EMAIL_TEMPLATE); }); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 3206e2231f..c34515b5e1 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -4,27 +4,28 @@ use Appwrite\Auth\Auth; use Appwrite\ClamAV\Network; use Appwrite\Event\Delete; use Appwrite\Event\Event; -use Appwrite\Extend\Exception; -use Appwrite\OpenSSL\OpenSSL; use Appwrite\Utopia\Database\Validator\CustomId; -use Appwrite\Utopia\Database\Validator\Queries\Buckets; -use Appwrite\Utopia\Database\Validator\Queries\Files; +use Appwrite\OpenSSL\OpenSSL; use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Exception\Authorization as AuthorizationException; +use Utopia\Database\DateTime; use Utopia\Database\Exception\Duplicate; +use Utopia\Database\Exception\Authorization as AuthorizationException; use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Permissions; use Utopia\Database\Validator\UID; +use Appwrite\Extend\Exception; +use Appwrite\Utopia\Database\Validator\Queries\Buckets; +use Appwrite\Utopia\Database\Validator\Queries\Files; use Utopia\Image\Image; use Utopia\Storage\Compression\Algorithms\GZIP; use Utopia\Storage\Compression\Algorithms\Zstd; @@ -34,13 +35,14 @@ use Utopia\Storage\Validator\File; use Utopia\Storage\Validator\FileExt; use Utopia\Storage\Validator\FileSize; use Utopia\Storage\Validator\Upload; -use Utopia\Swoole\Request; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\HexColor; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; +use Utopia\DSN\DSN; +use Utopia\Swoole\Request; App::post('/v1/storage/buckets') ->desc('Create bucket') @@ -61,15 +63,16 @@ App::post('/v1/storage/buckets') ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true) ->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true) ->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true) - ->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is '.Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0).'. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) - ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' extensions are allowed, each 64 characters long.', true) - ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd), For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' compression is skipped even if it\'s enabled', true) - ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' encryption is skipped even if it\'s enabled', true) - ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above '.Storage::human(APP_LIMIT_ANTIVIRUS, 0).' AntiVirus scanning is skipped even if it\'s enabled', true) + ->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) + ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true) + ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) + ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) + ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') ->inject('events') ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $events) { + $bucketId = $bucketId === 'unique()' ? ID::unique() : $bucketId; // Map aggregate permissions into the multiple permissions they represent. @@ -94,7 +97,7 @@ App::post('/v1/storage/buckets') 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '', + 'format' => $attribute['format'] ?? '' ]); } @@ -125,13 +128,14 @@ App::post('/v1/storage/buckets') $bucket = $dbForProject->getDocument('buckets', $bucketId); - $dbForProject->createCollection('bucket_'.$bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity); + $dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity); } catch (Duplicate) { throw new Exception(Exception::STORAGE_BUCKET_ALREADY_EXISTS); } $events - ->setParam('bucketId', $bucket->getId()); + ->setParam('bucketId', $bucket->getId()) + ; $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -149,14 +153,15 @@ App::get('/v1/storage/buckets') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_BUCKET_LIST) - ->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Buckets::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Buckets::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { + $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -198,6 +203,7 @@ App::get('/v1/storage/buckets/:bucketId') ->inject('response') ->inject('dbForProject') ->action(function (string $bucketId, Response $response, Database $dbForProject) { + $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -226,11 +232,11 @@ App::put('/v1/storage/buckets/:bucketId') ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true) ->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true) ->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true) - ->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is '.Storage::human((int) App::getEnv('_APP_STORAGE_LIMIT', 0), 0).'. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) - ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' extensions are allowed, each 64 characters long.', true) - ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd), For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' compression is skipped even if it\'s enabled', true) - ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' encryption is skipped even if it\'s enabled', true) - ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above '.Storage::human(APP_LIMIT_ANTIVIRUS, 0).' AntiVirus scanning is skipped even if it\'s enabled', true) + ->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) + ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true) + ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) + ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) + ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') ->inject('events') @@ -265,10 +271,11 @@ App::put('/v1/storage/buckets/:bucketId') ->setAttribute('encryption', $encryption) ->setAttribute('compression', $compression) ->setAttribute('antivirus', $antivirus)); - $dbForProject->updateCollection('bucket_'.$bucket->getInternalId(), $permissions, $fileSecurity); + $dbForProject->updateCollection('bucket_' . $bucket->getInternalId(), $permissions, $fileSecurity); $events - ->setParam('bucketId', $bucket->getId()); + ->setParam('bucketId', $bucket->getId()) + ; $response->dynamic($bucket, Response::MODEL_BUCKET); }); @@ -298,7 +305,7 @@ App::delete('/v1/storage/buckets/:bucketId') throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - if (! $dbForProject->deleteDocument('buckets', $bucketId)) { + if (!$dbForProject->deleteDocument('buckets', $bucketId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove bucket from DB'); } @@ -308,7 +315,8 @@ App::delete('/v1/storage/buckets/:bucketId') $events ->setParam('bucketId', $bucket->getId()) - ->setPayload($response->output($bucket, Response::MODEL_BUCKET)); + ->setPayload($response->output($bucket, Response::MODEL_BUCKET)) + ; $response->noContent(); }); @@ -346,14 +354,15 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('deviceFiles') ->inject('deviceLocal') ->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) { + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $validator = new Authorization(Database::PERMISSION_CREATE); - if (! $validator->isValid($bucket->getCreate())) { + if (!$validator->isValid($bucket->getCreate())) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -369,7 +378,7 @@ App::post('/v1/storage/buckets/:bucketId/files') // Add permissions for current the user if none were provided. if (\is_null($permissions)) { $permissions = []; - if (! empty($user->getId())) { + if (!empty($user->getId())) { foreach ($allowedPermissions as $permission) { $permissions[] = (new Permission($permission, 'user', $user->getId()))->toString(); } @@ -378,7 +387,7 @@ App::post('/v1/storage/buckets/:bucketId/files') // Users can only manage their own roles, API keys and Admin users can manage any $roles = Authorization::getRoles(); - if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles)) { + if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -390,8 +399,8 @@ App::post('/v1/storage/buckets/:bucketId/files') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (! Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')'); + if (!Authorization::isRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } } @@ -402,6 +411,7 @@ App::post('/v1/storage/buckets/:bucketId/files') throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Maximum bucket file size is larger than _APP_STORAGE_LIMIT'); } + $file = $request->getFiles('file'); // GraphQL multipart spec adds files with index keys @@ -423,7 +433,7 @@ App::post('/v1/storage/buckets/:bucketId/files') $chunk = 1; $chunks = 1; - if (! empty($contentRange)) { + if (!empty($contentRange)) { $start = $request->getContentRangeStart(); $end = $request->getContentRangeEnd(); $fileSize = $request->getContentRangeSize(); @@ -434,7 +444,7 @@ App::post('/v1/storage/buckets/:bucketId/files') } $idValidator = new UID(); - if (! $idValidator->isValid($request->getHeader('x-appwrite-id'))) { + if (!$idValidator->isValid($request->getHeader('x-appwrite-id'))) { throw new Exception(Exception::STORAGE_INVALID_APPWRITE_ID); } @@ -455,30 +465,30 @@ App::post('/v1/storage/buckets/:bucketId/files') // Check if file type is allowed $allowedFileExtensions = $bucket->getAttribute('allowedFileExtensions', []); $fileExt = new FileExt($allowedFileExtensions); - if (! empty($allowedFileExtensions) && ! $fileExt->isValid($fileName)) { + if (!empty($allowedFileExtensions) && !$fileExt->isValid($fileName)) { throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED, 'File extension not allowed'); } // Check if file size is exceeding allowed limit $fileSizeValidator = new FileSize($maximumFileSize); - if (! $fileSizeValidator->isValid($fileSize)) { + if (!$fileSizeValidator->isValid($fileSize)) { throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE, 'File size not allowed'); } $upload = new Upload(); - if (! $upload->isValid($fileTmpName)) { + if (!$upload->isValid($fileTmpName)) { throw new Exception(Exception::STORAGE_INVALID_FILE); } // Save to storage $fileSize ??= $deviceLocal->getFileSize($fileTmpName); - $path = $deviceFiles->getPath($fileId.'.'.\pathinfo($fileName, PATHINFO_EXTENSION)); - $path = str_ireplace($deviceFiles->getRoot(), $deviceFiles->getRoot().DIRECTORY_SEPARATOR.$bucket->getId(), $path); // Add bucket id to path after root + $path = $deviceFiles->getPath($fileId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION)); + $path = str_ireplace($deviceFiles->getRoot(), $deviceFiles->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $path); // Add bucket id to path after root - $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); + $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); $metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)]; - if (! $file->isEmpty()) { + if (!$file->isEmpty()) { $chunks = $file->getAttribute('chunksTotal', 1); $metadata = $file->getAttribute('metadata', []); if ($chunk === -1) { @@ -498,7 +508,7 @@ App::post('/v1/storage/buckets/:bucketId/files') (int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310) ); - if (! $antivirus->fileScan($path)) { + if (!$antivirus->fileScan($path)) { $deviceFiles->delete($path); throw new Exception(Exception::STORAGE_INVALID_FILE); } @@ -532,8 +542,8 @@ App::post('/v1/storage/buckets/:bucketId/files') $data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag); } - if (! empty($data)) { - if (! $deviceFiles->write($path, $data, $mimeType)) { + if (!empty($data)) { + if (!$deviceFiles->write($path, $data, $mimeType)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to save file'); } } @@ -577,7 +587,7 @@ App::post('/v1/storage/buckets/:bucketId/files') 'metadata' => $metadata, ]); - $file = $dbForProject->createDocument('bucket_'.$bucket->getInternalId(), $doc); + $file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc); } else { $file = $file ->setAttribute('$permissions', $permissions) @@ -592,7 +602,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->setAttribute('metadata', $metadata) ->setAttribute('chunksUploaded', $chunksUploaded); - $file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file); + $file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file); } } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); @@ -623,13 +633,13 @@ App::post('/v1/storage/buckets/:bucketId/files') 'metadata' => $metadata, ]); - $file = $dbForProject->createDocument('bucket_'.$bucket->getInternalId(), $doc); + $file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc); } else { $file = $file ->setAttribute('chunksUploaded', $chunksUploaded) ->setAttribute('metadata', $metadata); - $file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file); + $file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file); } } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); @@ -643,7 +653,8 @@ App::post('/v1/storage/buckets/:bucketId/files') $events ->setParam('bucketId', $bucket->getId()) ->setParam('fileId', $file->getId()) - ->setContext('bucket', $bucket); + ->setContext('bucket', $bucket) + ; $metadata = null; // was causing leaks as it was passed by reference @@ -665,28 +676,29 @@ App::get('/v1/storage/buckets/:bucketId/files') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_FILE_LIST) ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') - ->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Files::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') ->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (! $fileSecurity && ! $valid) { + if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -697,10 +709,10 @@ App::get('/v1/storage/buckets/:bucketId/files') /** @var Query $cursor */ $fileId = $cursor->getValue(); - if ($fileSecurity && ! $valid) { - $cursorDocument = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); + if ($fileSecurity && !$valid) { + $cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); + $cursorDocument = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($cursorDocument->isEmpty()) { @@ -712,12 +724,12 @@ App::get('/v1/storage/buckets/:bucketId/files') $filterQueries = Query::groupByType($queries)['filters']; - if ($fileSecurity && ! $valid) { - $files = $dbForProject->find('bucket_'.$bucket->getInternalId(), $queries); - $total = $dbForProject->count('bucket_'.$bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT); + if ($fileSecurity && !$valid) { + $files = $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries); + $total = $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT); } else { - $files = Authorization::skip(fn () => $dbForProject->find('bucket_'.$bucket->getInternalId(), $queries)); - $total = Authorization::skip(fn () => $dbForProject->count('bucket_'.$bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT)); + $files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries)); + $total = Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT)); } $response->dynamic(new Document([ @@ -744,23 +756,24 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('dbForProject') ->inject('mode') ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, string $mode) { + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (! $fileSecurity && ! $valid) { + if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } - if ($fileSecurity && ! $valid) { - $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); + if ($fileSecurity && !$valid) { + $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -789,7 +802,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->param('fileId', '', new UID(), 'File ID') ->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true) ->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true) - ->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of '.implode(',', Image::getGravityTypes()), true) + ->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of ' . implode(",", Image::getGravityTypes()), true) ->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true) ->param('borderWidth', 0, new Range(0, 100), 'Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.', true) ->param('borderColor', '', new HexColor(), 'Preview image border color. Use a valid HEX color, no # is needed for prefix.', true) @@ -806,20 +819,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->inject('deviceFiles') ->inject('deviceLocal') ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Request $request, Response $response, Document $project, Database $dbForProject, string $mode, Device $deviceFiles, Device $deviceLocal) { - if (! \extension_loaded('imagick')) { + + if (!\extension_loaded('imagick')) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); } $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (! $fileSecurity && ! $valid) { + if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -831,10 +845,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $outputs = Config::getParam('storage-outputs'); $fileLogos = Config::getParam('storage-logos'); - if ($fileSecurity && ! $valid) { - $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); + if ($fileSecurity && !$valid) { + $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -846,8 +860,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $algorithm = $file->getAttribute('algorithm', 'none'); $cipher = $file->getAttribute('openSSLCipher'); $mime = $file->getAttribute('mimeType'); - if (! \in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) { - if (! \in_array($mime, $inputs)) { + if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) { + if (!\in_array($mime, $inputs)) { $path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default']; } else { // it was an image but the file size exceeded the limit @@ -861,7 +875,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $deviceFiles = $deviceLocal; } - if (! $deviceFiles->exists($path)) { + if (!$deviceFiles->exists($path)) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } @@ -871,13 +885,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type; } + $source = $deviceFiles->read($path); - if (! empty($cipher)) { // Decrypt + if (!empty($cipher)) { // Decrypt $source = OpenSSL::decrypt( $source, $file->getAttribute('openSSLCipher'), - App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')), + App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')), 0, \hex2bin($file->getAttribute('openSSLIV')), \hex2bin($file->getAttribute('openSSLTag')) @@ -899,23 +914,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $image->crop((int) $width, (int) $height, $gravity); - if (! empty($opacity) || $opacity === 0) { + if (!empty($opacity) || $opacity === 0) { $image->setOpacity($opacity); } - if (! empty($background)) { - $image->setBackground('#'.$background); + if (!empty($background)) { + $image->setBackground('#' . $background); } - if (! empty($borderWidth)) { - $image->setBorder($borderWidth, '#'.$borderColor); + if (!empty($borderWidth)) { + $image->setBorder($borderWidth, '#' . $borderColor); } - if (! empty($borderRadius)) { + if (!empty($borderRadius)) { $image->setBorderRadius($borderRadius); } - if (! empty($rotation)) { + if (!empty($rotation)) { $image->setRotation(($rotation + 360) % 360); } @@ -924,9 +939,10 @@ 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('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') ->setContentType($contentType) - ->file($data); + ->file($data) + ; unset($image); }); @@ -951,23 +967,24 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->inject('mode') ->inject('deviceFiles') ->action(function (string $bucketId, string $fileId, Request $request, Response $response, Database $dbForProject, string $mode, Device $deviceFiles) { + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (! $fileSecurity && ! $valid) { + if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } - if ($fileSecurity && ! $valid) { - $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); + if ($fileSecurity && !$valid) { + $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -976,20 +993,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $path = $file->getAttribute('path', ''); - if (! $deviceFiles->exists($path)) { - throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in '.$path); + if (!$deviceFiles->exists($path)) { + throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path); } $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('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->addHeader('X-Peak', \memory_get_peak_usage()) - ->addHeader('Content-Disposition', 'attachment; filename="'.$file->getAttribute('name', '').'"'); + ->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"') + ; $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); - if (! empty($rangeHeader)) { + if (!empty($rangeHeader)) { $start = $request->getRangeStart(); $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); @@ -1004,18 +1022,18 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $response ->addHeader('Accept-Ranges', 'bytes') - ->addHeader('Content-Range', 'bytes '.$start.'-'.$end.'/'.$size) + ->addHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $size) ->addHeader('Content-Length', $end - $start + 1) ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } $source = ''; - if (! empty($file->getAttribute('openSSLCipher'))) { // Decrypt + if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceFiles->read($path); $source = OpenSSL::decrypt( $source, $file->getAttribute('openSSLCipher'), - App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')), + App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')), 0, \hex2bin($file->getAttribute('openSSLIV')), \hex2bin($file->getAttribute('openSSLTag')) @@ -1039,14 +1057,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') break; } - if (! empty($source)) { - if (! empty($rangeHeader)) { + if (!empty($source)) { + if (!empty($rangeHeader)) { $response->send(substr($source, $start, ($end - $start + 1))); } $response->send($source); } - if (! empty($rangeHeader)) { + if (!empty($rangeHeader)) { $response->send($deviceFiles->read($path, $start, ($end - $start + 1))); } @@ -1087,23 +1105,24 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->inject('mode') ->inject('deviceFiles') ->action(function (string $bucketId, string $fileId, Response $response, Request $request, Database $dbForProject, string $mode, Device $deviceFiles) { + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (! $fileSecurity && ! $valid) { + if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } - if ($fileSecurity && ! $valid) { - $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); + if ($fileSecurity && !$valid) { + $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -1114,8 +1133,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $path = $file->getAttribute('path', ''); - if (! $deviceFiles->exists($path)) { - throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in '.$path); + if (!$deviceFiles->exists($path)) { + throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path); } $contentType = 'text/plain'; @@ -1128,14 +1147,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->setContentType($contentType) ->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('X-Peak', \memory_get_peak_usage()); + ->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('X-Peak', \memory_get_peak_usage()) + ; $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); - if (! empty($rangeHeader)) { + if (!empty($rangeHeader)) { $start = $request->getRangeStart(); $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); @@ -1156,12 +1176,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') } $source = ''; - if (! empty($file->getAttribute('openSSLCipher'))) { // Decrypt + if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceFiles->read($path); $source = OpenSSL::decrypt( $source, $file->getAttribute('openSSLCipher'), - App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')), + App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')), 0, \hex2bin($file->getAttribute('openSSLIV')), \hex2bin($file->getAttribute('openSSLTag')) @@ -1185,14 +1205,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') break; } - if (! empty($source)) { - if (! empty($rangeHeader)) { + if (!empty($source)) { + if (!empty($rangeHeader)) { $response->send(substr($source, $start, ($end - $start + 1))); } $response->send($source); } - if (! empty($rangeHeader)) { + if (!empty($rangeHeader)) { $response->send($deviceFiles->read($path, $start, ($end - $start + 1))); } @@ -1242,21 +1262,22 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('mode') ->inject('events') ->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $events) { + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttributes('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_UPDATE); $valid = $validator->isValid($bucket->getUpdate()); - if (! $fileSecurity && ! $valid) { + if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } // Read permission should not be required for update - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); @@ -1271,7 +1292,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') // Users can only manage their own roles, API keys and Admin users can manage any $roles = Authorization::getRoles(); - if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles) && ! \is_null($permissions)) { + if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -1283,8 +1304,8 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') $permission->getIdentifier(), $permission->getDimension() ))->toString(); - if (! Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')'); + if (!Authorization::isRole($role)) { + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); } } } @@ -1296,24 +1317,25 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') $file->setAttribute('$permissions', $permissions); - if (! is_null($name)) { + if (!is_null($name)) { $file->setAttribute('name', $name); } - if ($fileSecurity && ! $valid) { + if ($fileSecurity && !$valid) { try { - $file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file); + $file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file); } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } } else { - $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file)); + $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); } $events ->setParam('bucketId', $bucket->getId()) ->setParam('fileId', $file->getId()) - ->setContext('bucket', $bucket); + ->setContext('bucket', $bucket) + ; $response->dynamic($file, Response::MODEL_FILE); }); @@ -1346,26 +1368,26 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, string $mode, Device $deviceFiles, Delete $deletes) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttributes('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_DELETE); $valid = $validator->isValid($bucket->getDelete()); - if (! $fileSecurity && ! $valid) { + if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } // Read permission should not be required for delete - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); } // Make sure we don't delete the file before the document permission check occurs - if ($fileSecurity && ! $valid && ! $validator->isValid($file->getDelete())) { + if ($fileSecurity && !$valid && !$validator->isValid($file->getDelete())) { throw new Exception(Exception::USER_UNAUTHORIZED); } @@ -1382,19 +1404,20 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') if ($deviceDeleted) { $deletes ->setType(DELETE_TYPE_CACHE_BY_RESOURCE) - ->setResource('file/'.$fileId); + ->setResource('file/' . $fileId) + ; - if ($fileSecurity && ! $valid) { + if ($fileSecurity && !$valid) { try { - $deleted = $dbForProject->deleteDocument('bucket_'.$bucket->getInternalId(), $fileId); + $deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId); } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } } else { - $deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_'.$bucket->getInternalId(), $fileId)); + $deleted = Authorization::skip(fn() => $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId)); } - if (! $deleted) { + if (!$deleted) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove file from DB'); } } else { @@ -1405,7 +1428,8 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->setParam('bucketId', $bucket->getId()) ->setParam('fileId', $file->getId()) ->setContext('bucket', $bucket) - ->setPayload($response->output($file, Response::MODEL_FILE)); + ->setPayload($response->output($file, Response::MODEL_FILE)) + ; $response->noContent(); }); @@ -1424,6 +1448,7 @@ App::get('/v1/storage/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { + $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -1493,6 +1518,7 @@ App::get('/v1/storage/:bucketId/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $bucketId, string $range, Response $response, Database $dbForProject) { + $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index e50378f4b6..e03e481d7c 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -9,10 +9,14 @@ use Appwrite\Event\Mail; use Appwrite\Event\Phone as EventPhone; use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; +use Utopia\Validator\Host; use Appwrite\Template\Template; use Appwrite\Utopia\Database\Validator\CustomId; +use Utopia\Database\Validator\Queries; use Appwrite\Utopia\Database\Validator\Queries\Memberships; use Appwrite\Utopia\Database\Validator\Queries\Teams; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use MaxMind\Db\Reader; @@ -20,24 +24,20 @@ use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; use Utopia\Database\Database; -use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Authorization as AuthorizationException; use Utopia\Database\Exception\Duplicate; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\DateTime; +use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; -use Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; -use Utopia\Validator\Host; use Utopia\Validator\Text; App::post('/v1/teams') @@ -56,19 +56,20 @@ App::post('/v1/teams') ->label('sdk.response.model', Response::MODEL_TEAM) ->param('teamId', '', new CustomId(), 'Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', null, new Text(128), 'Team name. Max length: 128 chars.') - ->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.', true) + ->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', true) ->inject('response') ->inject('user') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $events) { + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); $teamId = $teamId == 'unique()' ? ID::unique() : $teamId; try { - $team = Authorization::skip(fn () => $dbForProject->createDocument('teams', new Document([ + $team = Authorization::skip(fn() => $dbForProject->createDocument('teams', new Document([ '$id' => $teamId, '$permissions' => [ Permission::read(Role::team($teamId)), @@ -84,8 +85,8 @@ App::post('/v1/teams') throw new Exception(Exception::TEAM_ALREADY_EXISTS); } - if (! $isPrivilegedUser && ! $isAppUser) { // Don't add user on server mode - if (! \in_array('owner', $roles)) { + if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode + if (!\in_array('owner', $roles)) { $roles[] = 'owner'; } @@ -109,7 +110,7 @@ App::post('/v1/teams') 'joined' => DateTime::now(), 'confirm' => true, 'secret' => '', - 'search' => implode(' ', [$membershipId, $user->getId()]), + 'search' => implode(' ', [$membershipId, $user->getId()]) ]); $membership = $dbForProject->createDocument('memberships', $membership); @@ -118,7 +119,7 @@ App::post('/v1/teams') $events->setParam('teamId', $team->getId()); - if (! empty($user->getId())) { + if (!empty($user->getId())) { $events->setParam('userId', $user->getId()); } @@ -139,14 +140,15 @@ App::get('/v1/teams') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TEAM_LIST) ->label('sdk.offline.model', '/teams') - ->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Teams::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { + $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -193,6 +195,7 @@ App::get('/v1/teams/:teamId') ->inject('response') ->inject('dbForProject') ->action(function (string $teamId, Response $response, Database $dbForProject) { + $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -218,6 +221,7 @@ App::get('/v1/teams/:teamId/prefs') ->inject('response') ->inject('dbForProject') ->action(function (string $teamId, Response $response, Database $dbForProject) { + $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -252,6 +256,7 @@ App::put('/v1/teams/:teamId') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, string $name, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events) { + $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -293,6 +298,7 @@ App::put('/v1/teams/:teamId/prefs') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, array $prefs, Response $response, Database $dbForProject, Event $events) { + $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -325,13 +331,14 @@ App::delete('/v1/teams/:teamId') ->inject('events') ->inject('deletes') ->action(function (string $teamId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { + $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); } - if (! $dbForProject->deleteDocument('teams', $teamId)) { + if (!$dbForProject->deleteDocument('teams', $teamId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove team from DB'); } @@ -341,7 +348,8 @@ App::delete('/v1/teams/:teamId') $events ->setParam('teamId', $team->getId()) - ->setPayload($response->output($team, Response::MODEL_TEAM)); + ->setPayload($response->output($team, Response::MODEL_TEAM)) + ; $response->noContent(); }); @@ -367,8 +375,8 @@ 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](/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.') - ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page + ->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](/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') + ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['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') ->inject('project') @@ -379,13 +387,14 @@ App::post('/v1/teams/:teamId/memberships') ->inject('messaging') ->inject('events') ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, EventPhone $messaging, Event $events) { + if (empty($userId) && empty($email) && empty($phone)) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'At least one of userId, email, or phone is required'); } $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); - if (! $isPrivilegedUser && ! $isAppUser && empty(App::getEnv('_APP_SMTP_HOST'))) { + if (!$isPrivilegedUser && !$isAppUser && empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED); } @@ -396,28 +405,28 @@ App::post('/v1/teams/:teamId/memberships') if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); } - if (! empty($userId)) { + if (!empty($userId)) { $invitee = $dbForProject->getDocument('users', $userId); if ($invitee->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND, 'User with given userId doesn\'t exist.', 404); } - if (! empty($email) && $invitee->getAttribute('email', '') !== $email) { + if (!empty($email) && $invitee->getAttribute('email', '') !== $email) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and email doesn\'t match', 409); } - if (! empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { + if (!empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and phone doesn\'t match', 409); } $email = $invitee->getAttribute('email', ''); $phone = $invitee->getAttribute('phone', ''); $name = empty($name) ? $invitee->getAttribute('name', '') : $name; - } elseif (! empty($email)) { + } elseif (!empty($email)) { $invitee = $dbForProject->findOne('users', [Query::equal('email', [$email])]); // Get user by email address - if (! empty($invitee) && ! empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { + if (!empty($invitee) && !empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given email and phone doesn\'t match', 409); } - } elseif (! empty($phone)) { + } elseif (!empty($phone)) { $invitee = $dbForProject->findOne('users', [Query::equal('phone', [$phone])]); - if (! empty($invitee) && ! empty($email) && $invitee->getAttribute('email', '') !== $email) { + if (!empty($invitee) && !empty($email) && $invitee->getAttribute('email', '') !== $email) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given phone and email doesn\'t match', 409); } } @@ -437,13 +446,13 @@ App::post('/v1/teams/:teamId/memberships') $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } try { $userId = ID::unique(); - $invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([ + $invitee = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([ '$id' => $userId, '$permissions' => [ Permission::read(Role::any()), @@ -471,16 +480,16 @@ App::post('/v1/teams/:teamId/memberships') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]), + 'search' => implode(' ', [$userId, $email, $name]) ]))); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); } } - $isOwner = Authorization::isRole('team:'.$team->getId().'/owner'); + $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); - if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server) + if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to send invitations for this team'); } @@ -505,17 +514,17 @@ App::post('/v1/teams/:teamId/memberships') 'joined' => ($isPrivilegedUser || $isAppUser) ? DateTime::now() : null, 'confirm' => ($isPrivilegedUser || $isAppUser), 'secret' => Auth::hash($secret), - 'search' => implode(' ', [$membershipId, $invitee->getId()]), + 'search' => implode(' ', [$membershipId, $invitee->getId()]) ]); if ($isPrivilegedUser || $isAppUser) { // Allow admin to create membership try { - $membership = Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership)); + $membership = Authorization::skip(fn() => $dbForProject->createDocument('memberships', $membership)); } catch (Duplicate $th) { throw new Exception(Exception::TEAM_INVITE_ALREADY_EXISTS); } $team->setAttribute('total', $team->getAttribute('total', 0) + 1); - $team = Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team)); + $team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team)); $dbForProject->deleteCachedDocument('users', $invitee->getId()); } else { @@ -528,16 +537,16 @@ App::post('/v1/teams/:teamId/memberships') $url = Template::parseURL($url); $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]); $url = Template::unParseURL($url); - if (! empty($email)) { + if (!empty($email)) { $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); - $body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl'); - $subject = \sprintf($locale->getText('emails.invitation.subject'), $team->getAttribute('name'), $projectName); + $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName); $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; - $customTemplate = $project->getAttribute('templates', [])['email.invitation-'.$locale->default] ?? []; - if ($smtpEnabled && ! empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['email.invitation-' . $locale->default] ?? []; + if ($smtpEnabled && !empty($customTemplate)) { $body = $customTemplate['message']; $subject = $customTemplate['subject']; $from = $customTemplate['senderName']; @@ -548,13 +557,13 @@ App::post('/v1/teams/:teamId/memberships') $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText('emails.invitation.hello')) + ->setParam('{{hello}}', $locale->getText("emails.invitation.hello")) ->setParam('{{name}}', $user->getAttribute('name')) - ->setParam('{{body}}', $locale->getText('emails.invitation.body')) + ->setParam('{{body}}', $locale->getText("emails.invitation.body")) ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText('emails.invitation.footer')) - ->setParam('{{thanks}}', $locale->getText('emails.invitation.thanks')) - ->setParam('{{signature}}', $locale->getText('emails.invitation.signature')) + ->setParam('{{footer}}', $locale->getText("emails.invitation.footer")) + ->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks")) + ->setParam('{{signature}}', $locale->getText("emails.invitation.signature")) ->setParam('{{project}}', $projectName) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -569,12 +578,13 @@ App::post('/v1/teams/:teamId/memberships') ->setFrom($from) ->setRecipient($invitee->getAttribute('email')) ->setName($invitee->getAttribute('name')) - ->trigger(); - } elseif (! empty($phone)) { - $message = Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl'); + ->trigger() + ; + } elseif (!empty($phone)) { + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl'); - $customTemplate = $project->getAttribute('templates', [])['sms.invitation-'.$locale->default] ?? []; - if (! empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['sms.invitation-' . $locale->default] ?? []; + if (!empty($customTemplate)) { $message = $customTemplate['message']; } @@ -590,7 +600,8 @@ App::post('/v1/teams/:teamId/memberships') $events ->setParam('teamId', $team->getId()) - ->setParam('membershipId', $membership->getId()); + ->setParam('membershipId', $membership->getId()) + ; $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -616,11 +627,12 @@ App::get('/v1/teams/:teamId/memberships') ->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST) ->label('sdk.offline.model', '/teams/{teamId}/memberships') ->param('teamId', '', new UID(), 'Team ID.') - ->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Memberships::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (string $teamId, array $queries, string $search, Response $response, Database $dbForProject) { + $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -629,7 +641,7 @@ App::get('/v1/teams/:teamId/memberships') $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -664,7 +676,7 @@ App::get('/v1/teams/:teamId/memberships') max: APP_LIMIT_COUNT ); - $memberships = array_filter($memberships, fn (Document $membership) => ! empty($membership->getAttribute('userId'))); + $memberships = array_filter($memberships, fn(Document $membership) => !empty($membership->getAttribute('userId'))); $memberships = array_map(function ($membership) use ($dbForProject, $team) { $user = $dbForProject->getDocument('users', $membership->getAttribute('userId')); @@ -672,7 +684,8 @@ App::get('/v1/teams/:teamId/memberships') $membership ->setAttribute('teamName', $team->getAttribute('name')) ->setAttribute('userName', $user->getAttribute('name')) - ->setAttribute('userEmail', $user->getAttribute('email')); + ->setAttribute('userEmail', $user->getAttribute('email')) + ; return $membership; }, $memberships); @@ -701,6 +714,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') ->inject('response') ->inject('dbForProject') ->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject) { + $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -718,7 +732,8 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') $membership ->setAttribute('teamName', $team->getAttribute('name')) ->setAttribute('userName', $user->getAttribute('name')) - ->setAttribute('userEmail', $user->getAttribute('email')); + ->setAttribute('userEmail', $user->getAttribute('email')) + ; $response->dynamic($membership, Response::MODEL_MEMBERSHIP); }); @@ -739,13 +754,14 @@ 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', [], 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.') ->inject('request') ->inject('response') ->inject('user') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) { + $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); @@ -763,9 +779,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); - $isOwner = Authorization::isRole('team:'.$team->getId().'/owner'); + $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); - if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server) + if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to modify roles'); } @@ -832,7 +848,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') throw new Exception(Exception::TEAM_MEMBERSHIP_MISMATCH); } - $team = Authorization::skip(fn () => $dbForProject->getDocument('teams', $teamId)); + $team = Authorization::skip(fn() => $dbForProject->getDocument('teams', $teamId)); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); @@ -843,7 +859,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if ($userId !== $membership->getAttribute('userId')) { - throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')'); + throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')'); } if ($user->isEmpty()) { @@ -851,7 +867,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if ($membership->getAttribute('userId') !== $user->getId()) { - throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')'); + throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')'); } if ($membership->getAttribute('confirm') === true) { @@ -860,9 +876,10 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $membership // Attach user to team ->setAttribute('joined', DateTime::now()) - ->setAttribute('confirm', true); + ->setAttribute('confirm', true) + ; - Authorization::skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); + Authorization::skip(fn() => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); // Log user in @@ -900,20 +917,23 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $dbForProject->deleteCachedDocument('users', $user->getId()); - $team = Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1))); + $team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1))); $events ->setParam('teamId', $team->getId()) - ->setParam('membershipId', $membership->getId()); + ->setParam('membershipId', $membership->getId()) + ; - if (! Config::getParam('domainVerification')) { + if (!Config::getParam('domainVerification')) { $response - ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); + ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])) + ; } $response - ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) - ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); + ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) + ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) + ; $response->dynamic( $membership @@ -943,6 +963,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') ->inject('dbForProject') ->inject('events') ->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $events) { + $membership = $dbForProject->getDocument('memberships', $membershipId); if ($membership->isEmpty()) { @@ -977,13 +998,14 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') if ($membership->getAttribute('confirm')) { // Count only confirmed members $team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0)); - Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team)); + Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team)); } $events ->setParam('teamId', $team->getId()) ->setParam('membershipId', $membership->getId()) - ->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP)); + ->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP)) + ; $response->noContent(); }); @@ -1006,6 +1028,7 @@ App::get('/v1/teams/:teamId/logs') ->inject('locale') ->inject('geodb') ->action(function (string $teamId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -1018,13 +1041,13 @@ App::get('/v1/teams/:teamId/logs') $offset = $grouped['offset'] ?? 0; $audit = new Audit($dbForProject); - $resource = 'team/'.$team->getId(); + $resource = 'team/' . $team->getId(); $logs = $audit->getLogsByResource($resource, $limit, $offset); $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -1052,14 +1075,14 @@ App::get('/v1/teams/:teamId/logs') 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'], + 'deviceModel' => $device['deviceModel'] ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index f868bdd69e..cf94135351 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -2,43 +2,43 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\Validator\Password; -use Appwrite\Auth\Validator\PasswordDictionary; -use Appwrite\Auth\Validator\PasswordHistory; -use Appwrite\Auth\Validator\PersonalData; use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; use Appwrite\Event\Delete; use Appwrite\Event\Event; -use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; use Appwrite\Utopia\Database\Validator\CustomId; +use Utopia\Database\Validator\Queries; use Appwrite\Utopia\Database\Validator\Queries\Identities; use Appwrite\Utopia\Database\Validator\Queries\Users; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; use Appwrite\Utopia\Response; -use MaxMind\Db\Reader; use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; -use Utopia\Database\Database; -use Utopia\Database\DateTime; -use Utopia\Database\Document; -use Utopia\Database\Exception\Duplicate; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Locale\Locale; +use Appwrite\Extend\Exception; +use Utopia\Database\Document; +use Utopia\Database\DateTime; +use Utopia\Database\Exception\Duplicate; +use Utopia\Database\Validator\UID; +use Utopia\Database\Database; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; -use Utopia\Database\Validator\UID; -use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; -use Utopia\Validator\Boolean; -use Utopia\Validator\Integer; -use Utopia\Validator\Text; use Utopia\Validator\WhiteList; +use Utopia\Validator\Text; +use Utopia\Validator\Boolean; +use MaxMind\Db\Reader; +use Utopia\Validator\Integer; +use Appwrite\Auth\Validator\PasswordHistory; +use Appwrite\Auth\Validator\PasswordDictionary; +use Appwrite\Auth\Validator\PersonalData; /** TODO: Remove function when we move to using utopia/platform */ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Document $project, Database $dbForProject, Event $events): Document @@ -46,14 +46,14 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e $hashOptionsObject = (\is_string($hashOptions)) ? \json_decode($hashOptions, true) : $hashOptions; // Cast to JSON array $passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0; - if (! empty($email)) { + if (!empty($email)) { $email = \strtolower($email); // Makes sure this email is not already used in another identity $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } } @@ -65,12 +65,12 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) { $personalDataValidator = new PersonalData($userId, $email, $name, $phone); - if (! $personalDataValidator->isValid($password)) { + if (!$personalDataValidator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA); } } - $password = (! empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null; + $password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null; $user = $dbForProject->createDocument('users', new Document([ '$id' => $userId, '$permissions' => [ @@ -86,7 +86,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'labels' => [], 'password' => $password, 'passwordHistory' => is_null($password) && $passwordHistory === 0 ? [] : [$password], - 'passwordUpdate' => (! empty($password)) ? DateTime::now() : null, + 'passwordUpdate' => (!empty($password)) ? DateTime::now() : null, 'hash' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO : $hash, 'hashOptions' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO_OPTIONS : $hashOptionsObject + ['type' => $hash], 'registration' => DateTime::now(), @@ -96,7 +96,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $phone, $name]), + 'search' => implode(' ', [$userId, $email, $phone, $name]) ])); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); @@ -131,6 +131,7 @@ App::post('/v1/users') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) { + $user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $project, $dbForProject, $events); $response @@ -254,8 +255,8 @@ App::post('/v1/users/sha') ->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Document $project, Database $dbForProject, Event $events) { $options = '{}'; - if (! empty($passwordVersion)) { - $options = '{"version":"'.$passwordVersion.'"}'; + if (!empty($passwordVersion)) { + $options = '{"version":"' . $passwordVersion . '"}'; } $user = createUser('sha', $options, $userId, $email, $password, null, $name, $project, $dbForProject, $events); @@ -328,7 +329,7 @@ App::post('/v1/users/scrypt') 'costCpu' => $passwordCpu, 'costMemory' => $passwordMemory, 'costParallel' => $passwordParallel, - 'length' => $passwordLength, + 'length' => $passwordLength ]; $user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $project, $dbForProject, $events); @@ -364,7 +365,7 @@ App::post('/v1/users/scrypt-modified') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Document $project, Database $dbForProject, Event $events) { - $user = createUser('scryptMod', '{"signerKey":"'.$passwordSignerKey.'","saltSeparator":"'.$passwordSaltSeparator.'","salt":"'.$passwordSalt.'"}', $userId, $email, $password, null, $name, $project, $dbForProject, $events); + $user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $project, $dbForProject, $events); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -405,7 +406,7 @@ App::post('/v1/users/:userId/targets') $target = $dbForProject->getDocument('targets', $targetId); - if (! $target->isEmpty()) { + if (!$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } @@ -413,7 +414,7 @@ App::post('/v1/users/:userId/targets') '$id' => $targetId, // TO DO: what permissions should be given when created a target. '$permissions' => [ - Permission::read(Role::any()), + Permission::read(Role::any()) ], 'providerId' => $providerId, 'providerInternalId' => $provider->getInternalId(), @@ -441,14 +442,15 @@ App::get('/v1/users') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_USER_LIST) - ->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Users::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { + $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -490,6 +492,7 @@ App::get('/v1/users/:userId') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, Response $response, Database $dbForProject) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -514,6 +517,7 @@ App::get('/v1/users/:userId/prefs') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, Response $response, Database $dbForProject) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -541,6 +545,7 @@ App::get('/v1/users/:userId/targets/:targetId') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, string $targetId, Response $response, Database $dbForProject) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -572,6 +577,7 @@ App::get('/v1/users/:userId/sessions') ->inject('dbForProject') ->inject('locale') ->action(function (string $userId, Response $response, Database $dbForProject, Locale $locale) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -582,7 +588,8 @@ App::get('/v1/users/:userId/sessions') foreach ($sessions as $key => $session) { /** @var Document $session */ - $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); + + $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session->setAttribute('countryName', $countryName); $session->setAttribute('current', false); @@ -610,6 +617,7 @@ App::get('/v1/users/:userId/memberships') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, Response $response, Database $dbForProject) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -651,6 +659,7 @@ App::get('/v1/users/:userId/logs') ->inject('locale') ->inject('geodb') ->action(function (string $userId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -669,7 +678,7 @@ App::get('/v1/users/:userId/logs') $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -693,14 +702,14 @@ App::get('/v1/users/:userId/logs') 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'], + 'deviceModel' => $device['deviceModel'] ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); @@ -728,6 +737,7 @@ App::get('/v1/users/:userId/targets') ->inject('response') ->inject('dbForProject') ->action(function (string $userId, Response $response, Database $dbForProject) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -753,14 +763,15 @@ App::get('/v1/users/identities') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_IDENTITY_LIST) - ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Identities::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Identities::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { + $queries = Query::parseQueries($queries); - if (! empty($search)) { + if (!empty($search)) { $queries[] = Query::search('search', $search); } @@ -808,6 +819,7 @@ App::patch('/v1/users/:userId/status') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, bool $status, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -844,6 +856,7 @@ App::put('/v1/users/:userId/labels') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, array $labels, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -880,6 +893,7 @@ App::patch('/v1/users/:userId/verification') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -914,6 +928,7 @@ App::patch('/v1/users/:userId/verification/phone') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, bool $phoneVerification, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -949,6 +964,7 @@ App::patch('/v1/users/:userId/name') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $name, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -986,6 +1002,7 @@ App::patch('/v1/users/:userId/password') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $password, Response $response, Document $project, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -994,7 +1011,7 @@ App::patch('/v1/users/:userId/password') if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) { $personalDataValidator = new PersonalData($userId, $user->getAttribute('email'), $user->getAttribute('name'), $user->getAttribute('phone')); - if (! $personalDataValidator->isValid($password)) { + if (!$personalDataValidator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA); } } @@ -1005,7 +1022,7 @@ App::patch('/v1/users/:userId/password') $history = $user->getAttribute('passwordHistory', []); if ($historyLimit > 0) { $validator = new PasswordHistory($history, $user->getAttribute('hash'), $user->getAttribute('hashOptions')); - if (! $validator->isValid($password)) { + if (!$validator->isValid($password)) { throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED); } @@ -1048,6 +1065,7 @@ App::patch('/v1/users/:userId/email') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $email, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1061,13 +1079,15 @@ App::patch('/v1/users/:userId/email') Query::equal('providerEmail', [$email]), Query::notEqual('userId', $user->getId()), ]); - if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } $user ->setAttribute('email', $email) - ->setAttribute('emailVerification', false); + ->setAttribute('emailVerification', false) + ; + try { $user = $dbForProject->updateDocument('users', $user->getId(), $user); @@ -1100,6 +1120,7 @@ App::patch('/v1/users/:userId/phone') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $number, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1108,7 +1129,8 @@ App::patch('/v1/users/:userId/phone') $user ->setAttribute('phone', $number) - ->setAttribute('phoneVerification', false); + ->setAttribute('phoneVerification', false) + ; try { $user = $dbForProject->updateDocument('users', $user->getId(), $user); @@ -1142,6 +1164,7 @@ App::patch('/v1/users/:userId/verification') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1173,6 +1196,7 @@ App::patch('/v1/users/:userId/prefs') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, array $prefs, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1206,6 +1230,7 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->inject('dbForProject') ->inject('events') ->action(function (string $targetId, string $userId, string $identifier, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1251,6 +1276,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, string $sessionId, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1292,6 +1318,7 @@ App::delete('/v1/users/:userId/sessions') ->inject('dbForProject') ->inject('events') ->action(function (string $userId, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1334,6 +1361,7 @@ App::delete('/v1/users/:userId') ->inject('events') ->inject('deletes') ->action(function (string $userId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1374,6 +1402,7 @@ App::delete('/v1/users/:userId/targets/:targetId') ->inject('dbForProject') ->inject('events') ->action(function (string $targetId, string $userId, Response $response, Database $dbForProject, Event $events) { + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1420,6 +1449,7 @@ App::delete('/v1/users/identities/:identityId') ->inject('events') ->inject('deletes') ->action(function (string $identityId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { + $identity = $dbForProject->getDocument('identities', $identityId); if ($identity->isEmpty()) { @@ -1446,6 +1476,7 @@ App::get('/v1/users/usage') ->inject('dbForProject') ->inject('register') ->action(function (string $range, Response $response, Database $dbForProject) { + $periods = Config::getParam('usage', []); $stats = $usage = []; $days = $periods[$range]; @@ -1478,22 +1509,22 @@ App::get('/v1/users/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; - } + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; } + } $response->dynamic(new Document([ 'range' => $range, - 'usersTotal' => $usage[$metrics[0]], + 'usersTotal' => $usage[$metrics[0]], 'sessionsTotal' => $usage[$metrics[1]], ]), Response::MODEL_USAGE_USERS); }); diff --git a/app/controllers/general.php b/app/controllers/general.php index bbd3d45f31..e8d6bb225a 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -1,38 +1,38 @@ getHostname(); $domains = Config::getParam('domains', []); - if (! array_key_exists($domain, $domains)) { - $domain = new Domain(! empty($domain) ? $domain : ''); + if (!array_key_exists($domain, $domains)) { + $domain = new Domain(!empty($domain) ? $domain : ''); - if (empty($domain->get()) || ! $domain->isKnown() || $domain->isTest()) { + if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) { $domains[$domain->get()] = false; - Console::warning($domain->get().' is not a publicly accessible domain. Skipping SSL certificate generation.'); + Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.'); } elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) { Console::warning('Skipping SSL certificates generation on ACME challenge.'); } else { @@ -97,7 +97,7 @@ App::init() $envDomain = App::getEnv('_APP_DOMAIN', ''); $mainDomain = null; - if (! empty($envDomain) && $envDomain !== 'localhost') { + if (!empty($envDomain) && $envDomain !== 'localhost') { $mainDomain = $envDomain; } else { $domainDocument = $dbForConsole->findOne('domains', [Query::orderAsc('_id')]); @@ -105,13 +105,13 @@ App::init() } if ($mainDomain !== $domain->get()) { - Console::warning($domain->get().' is not a main domain. Skipping SSL certificate generation.'); + Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.'); } else { $domainDocument = $dbForConsole->findOne('domains', [ - Query::equal('domain', [$domain->get()]), + Query::equal('domain', [$domain->get()]) ]); - if (! $domainDocument) { + if (!$domainDocument) { $domainDocument = new Document([ 'domain' => $domain->get(), 'tld' => $domain->getSuffix(), @@ -122,7 +122,7 @@ App::init() $domainDocument = $dbForConsole->createDocument('domains', $domainDocument); - Console::info('Issuing a TLS certificate for the main domain ('.$domain->get().') in a few seconds...'); + Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...'); (new Certificate()) ->setDomain($domainDocument) @@ -145,7 +145,7 @@ App::init() throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND); } - if (! empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) { + if (!empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) { throw new AppwriteException(AppwriteException::PROJECT_UNKNOWN); } @@ -160,14 +160,14 @@ App::init() $refDomainOrigin = $origin; } - $refDomain = (! empty($protocol) ? $protocol : $request->getProtocol()).'://'.$refDomainOrigin.(! empty($port) ? ':'.$port : ''); + $refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $refDomainOrigin . (!empty($port) ? ':' . $port : ''); - $refDomain = (! $route->getLabel('origin', false)) // This route is publicly accessible + $refDomain = (!$route->getLabel('origin', false)) // This route is publicly accessible ? $refDomain - : (! empty($protocol) ? $protocol : $request->getProtocol()).'://'.$origin.(! empty($port) ? ':'.$port : ''); + : (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : ''); $selfDomain = new Domain($request->getHostname()); - $endDomain = new Domain((string) $origin); + $endDomain = new Domain((string)$origin); Config::setParam( 'domainVerification', @@ -175,7 +175,7 @@ App::init() $endDomain->getRegisterable() !== '' ); - $isLocalHost = $request->getHostname() === 'localhost' || $request->getHostname() === 'localhost:'.$request->getPort(); + $isLocalHost = $request->getHostname() === 'localhost' || $request->getHostname() === 'localhost:' . $request->getPort(); $isIpAddress = filter_var($request->getHostname(), FILTER_VALIDATE_IP) !== false; $isConsoleProject = $project->getAttribute('$id', '') === 'console'; @@ -186,8 +186,8 @@ App::init() $isLocalHost || $isIpAddress ? null : ($isConsoleProject && $isConsoleRootSession - ? '.'.$selfDomain->getRegisterable() - : '.'.$request->getHostname() + ? '.' . $selfDomain->getRegisterable() + : '.' . $request->getHostname() ) ); @@ -231,12 +231,12 @@ App::init() throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP.'); } - return $response->redirect('https://'.$request->getHostname().$request->getURI()); + return $response->redirect('https://' . $request->getHostname() . $request->getURI()); } } if ($request->getProtocol() === 'https') { - $response->addHeader('Strict-Transport-Security', 'max-age='.(60 * 60 * 24 * 126)); // 126 days + $response->addHeader('Strict-Transport-Security', 'max-age=' . (60 * 60 * 24 * 126)); // 126 days } $response @@ -246,7 +246,8 @@ App::init() ->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma') ->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies') ->addHeader('Access-Control-Allow-Origin', $refDomain) - ->addHeader('Access-Control-Allow-Credentials', 'true'); + ->addHeader('Access-Control-Allow-Credentials', 'true') + ; /* * Validate Client Domain - Check to avoid CSRF attack @@ -257,7 +258,7 @@ App::init() $originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', []))); if ( - ! $originValidator->isValid($origin) + !$originValidator->isValid($origin) && \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE]) && $route->getLabel('origin', false) !== '*' && empty($request->getHeader('x-appwrite-key', '')) @@ -297,7 +298,7 @@ App::init() $authKey = $request->getHeader('x-appwrite-key', ''); - if (! empty($authKey)) { // API Key authentication + if (!empty($authKey)) { // API Key authentication // Check if given key match project API keys $key = $project->find('secret', $authKey, 'keys'); @@ -309,7 +310,7 @@ App::init() $user = new Document([ '$id' => '', 'status' => true, - 'email' => 'app.'.$project->getId().'@service.'.$request->getHostname(), + 'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(), 'password' => '', 'name' => $project->getAttribute('name', 'Untitled'), ]); @@ -318,8 +319,8 @@ App::init() $scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', [])); $expire = $key->getAttribute('expire'); - if (! empty($expire) && $expire < DateTime::formatTz(DateTime::now())) { - throw new AppwriteException(AppwriteException::PROJECT_KEY_EXPIRED); + if (!empty($expire) && $expire < DateTime::formatTz(DateTime::now())) { + throw new AppwriteException(AppwriteException:: PROJECT_KEY_EXPIRED); } Authorization::setRole(Auth::USER_ROLE_APPS); @@ -336,7 +337,7 @@ App::init() $sdk = $request->getHeader('x-sdk-name', 'UNKNOWN'); if ($sdkValidator->isValid($sdk)) { $sdks = $key->getAttribute('sdks', []); - if (! in_array($sdk, $sdks)) { + if (!in_array($sdk, $sdks)) { array_push($sdks, $sdk); $key->setAttribute('sdks', $sdks); @@ -356,22 +357,22 @@ App::init() } $service = $route->getLabel('sdk.namespace', ''); - if (! empty($service)) { + if (!empty($service)) { if ( array_key_exists($service, $project->getAttribute('services', [])) - && ! $project->getAttribute('services', [])[$service] - && ! (Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) + && !$project->getAttribute('services', [])[$service] + && !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles())) ) { throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED); } } - if (! \in_array($scope, $scopes)) { + if (!\in_array($scope, $scopes)) { if ($project->isEmpty()) { // Check if permission is denied because project is missing throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND); } - throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')'); + throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')'); } if (false === $user->getAttribute('status')) { // Account is blocked @@ -387,6 +388,7 @@ App::options() ->inject('request') ->inject('response') ->action(function (Request $request, Response $response) { + $origin = $request->getOrigin(); $response @@ -408,6 +410,7 @@ App::error() ->inject('logger') ->inject('loggerBreadcrumbs') ->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, array $loggerBreadcrumbs) { + $version = App::getEnv('_APP_VERSION', 'UNKNOWN'); $route = $utopia->match($request); @@ -422,11 +425,11 @@ App::error() $log = new Utopia\Logger\Log(); - if (isset($user) && ! $user->isEmpty()) { + if (isset($user) && !$user->isEmpty()) { $log->setUser(new User($user->getId())); } - $log->setNamespace('http'); + $log->setNamespace("http"); $log->setServer(\gethostname()); $log->setVersion($version); $log->setType(Log::TYPE_ERROR); @@ -439,7 +442,7 @@ App::error() $log->addTag('code', $error->getCode()); $log->addTag('projectId', $project->getId()); $log->addTag('hostname', $request->getHostname()); - $log->addTag('locale', (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', ''))); + $log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', ''))); $log->addExtra('file', $error->getFile()); $log->addExtra('line', $error->getLine()); @@ -447,7 +450,7 @@ App::error() $log->addExtra('detailedTrace', $error->getTrace()); $log->addExtra('roles', Authorization::getRoles()); - $action = $route->getLabel('sdk.namespace', 'UNKNOWN_NAMESPACE').'.'.$route->getLabel('sdk.method', 'UNKNOWN_METHOD'); + $action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD"); $log->setAction($action); $isProduction = App::getEnv('_APP_ENV', 'development') === 'production'; @@ -458,7 +461,7 @@ App::error() } $responseCode = $logger->addLog($log); - Console::info('Log pushed with status code: '.$responseCode); + Console::info('Log pushed with status code: ' . $responseCode); } } @@ -469,17 +472,17 @@ App::error() $trace = $error->getTrace(); if (php_sapi_name() === 'cli') { - Console::error('[Error] Timestamp: '.date('c', time())); + Console::error('[Error] Timestamp: ' . date('c', time())); if ($route) { - Console::error('[Error] Method: '.$route->getMethod()); - Console::error('[Error] URL: '.$route->getPath()); + Console::error('[Error] Method: ' . $route->getMethod()); + Console::error('[Error] URL: ' . $route->getPath()); } - Console::error('[Error] Type: '.get_class($error)); - Console::error('[Error] Message: '.$message); - Console::error('[Error] File: '.$file); - Console::error('[Error] Line: '.$line); + Console::error('[Error] Type: ' . get_class($error)); + Console::error('[Error] Message: ' . $message); + Console::error('[Error] File: ' . $file); + Console::error('[Error] Line: ' . $line); } /** Handle Utopia Errors */ @@ -500,7 +503,7 @@ App::error() } /** Wrap all exceptions inside Appwrite\Extend\Exception */ - if (! ($error instanceof AppwriteException)) { + if (!($error instanceof AppwriteException)) { $error = new AppwriteException(AppwriteException::GENERAL_UNKNOWN, $message, $code, $error); } @@ -545,7 +548,8 @@ App::error() ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate') ->addHeader('Expires', '0') ->addHeader('Pragma', 'no-cache') - ->setStatusCode($code); + ->setStatusCode($code) + ; $template = ($route) ? $route->getLabel('error', null) : null; @@ -553,14 +557,15 @@ App::error() $layout = new View($template); $layout - ->setParam('title', $project->getAttribute('name').' - Error') + ->setParam('title', $project->getAttribute('name') . ' - Error') ->setParam('development', App::isDevelopment()) ->setParam('projectName', $project->getAttribute('name')) ->setParam('projectURL', $project->getAttribute('url')) ->setParam('message', $error->getMessage()) ->setParam('type', $type) ->setParam('code', $code) - ->setParam('trace', $trace); + ->setParam('trace', $trace) + ; $response->html($layout->render()); } @@ -577,7 +582,7 @@ App::get('/robots.txt') ->label('docs', false) ->inject('response') ->action(function (Response $response) { - $template = new View(__DIR__.'/../views/general/robots.phtml'); + $template = new View(__DIR__ . '/../views/general/robots.phtml'); $response->text($template->render(false)); }); @@ -587,7 +592,7 @@ App::get('/humans.txt') ->label('docs', false) ->inject('response') ->action(function (Response $response) { - $template = new View(__DIR__.'/../views/general/humans.phtml'); + $template = new View(__DIR__ . '/../views/general/humans.phtml'); $response->text($template->render(false)); }); @@ -606,43 +611,43 @@ App::get('/.well-known/acme-challenge/*') ...Text::ALPHABET_LOWER, ...Text::ALPHABET_UPPER, '-', - '_', + '_' ]); - if (! $validator->isValid($token) || \count($uriChunks) !== 4) { + if (!$validator->isValid($token) || \count($uriChunks) !== 4) { throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, 'Invalid challenge token.'); } $base = \realpath(APP_STORAGE_CERTIFICATES); - $absolute = \realpath($base.'/.well-known/acme-challenge/'.$token); + $absolute = \realpath($base . '/.well-known/acme-challenge/' . $token); - if (! $base) { + if (!$base) { throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Storage error'); } - if (! $absolute) { + if (!$absolute) { throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path'); } - if (! \substr($absolute, 0, \strlen($base)) === $base) { + if (!\substr($absolute, 0, \strlen($base)) === $base) { throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, 'Invalid path'); } - if (! \file_exists($absolute)) { + if (!\file_exists($absolute)) { throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path'); } $content = @\file_get_contents($absolute); - if (! $content) { + if (!$content) { throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Failed to get contents'); } $response->text($content); }); -include_once __DIR__.'/shared/api.php'; -include_once __DIR__.'/shared/api/auth.php'; +include_once __DIR__ . '/shared/api.php'; +include_once __DIR__ . '/shared/api/auth.php'; foreach (Config::getParam('services', []) as $service) { include_once $service['controller']; diff --git a/app/controllers/mock.php b/app/controllers/mock.php index 779c361b61..892c41d872 100644 --- a/app/controllers/mock.php +++ b/app/controllers/mock.php @@ -3,18 +3,18 @@ global $utopia, $request, $response; use Appwrite\Extend\Exception; +use Utopia\Database\Document; +use Utopia\Validator\Host; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Utopia\App; -use Utopia\Database\Document; -use Utopia\Database\Helpers\ID; -use Utopia\Storage\Validator\File; use Utopia\Validator\ArrayList; -use Utopia\Validator\Host; use Utopia\Validator\Integer; -use Utopia\Validator\Nullable; use Utopia\Validator\Text; +use Utopia\Storage\Validator\File; use Utopia\Validator\WhiteList; +use Utopia\Database\Helpers\ID; +use Utopia\Validator\Nullable; App::get('/v1/mock/tests/foo') ->desc('Get Foo') @@ -220,9 +220,9 @@ App::get('/v1/mock/tests/general/headers') 'x-sdk-version' => $request->getHeader('x-sdk-version'), ]; $res = array_map(function ($key, $value) { - return $key.': '.$value; + return $key . ': ' . $value; }, array_keys($res), $res); - $res = implode('; ', $res); + $res = implode("; ", $res); $response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK); }); @@ -241,12 +241,14 @@ App::get('/v1/mock/tests/general/download') ->label('sdk.mock', true) ->inject('response') ->action(function (Response $response) { + $response ->setContentType('text/plain') ->addHeader('Content-Disposition', 'attachment; filename="test.txt"') - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->addHeader('X-Peak', \memory_get_peak_usage()) - ->send('GET:/v1/mock/tests/general/download:passed'); + ->send("GET:/v1/mock/tests/general/download:passed") + ; }); App::post('/v1/mock/tests/general/upload') @@ -269,13 +271,14 @@ App::post('/v1/mock/tests/general/upload') ->inject('request') ->inject('response') ->action(function (string $x, int $y, array $z, mixed $file, Request $request, Response $response) { + $file = $request->getFiles('file'); $contentRange = $request->getHeader('content-range'); $chunkSize = 5 * 1024 * 1024; // 5MB - if (! empty($contentRange)) { + if (!empty($contentRange)) { $start = $request->getContentRangeStart(); $end = $request->getContentRangeEnd(); $size = $request->getContentRangeSize(); @@ -290,7 +293,7 @@ App::post('/v1/mock/tests/general/upload') throw new Exception(Exception::GENERAL_MOCK, 'Invalid content-range header'); } - if ($start === 0 && ! empty($id)) { + if ($start === 0 && !empty($id)) { throw new Exception(Exception::GENERAL_MOCK, 'First chunked request cannot have id header'); } @@ -314,7 +317,7 @@ App::post('/v1/mock/tests/general/upload') $response->json([ '$id' => ID::custom('newfileid'), 'chunksTotal' => (int) ceil($size / ($end + 1 - $start)), - 'chunksUploaded' => ceil($start / $chunkSize) + 1, + 'chunksUploaded' => ceil($start / $chunkSize) + 1 ]); } } else { @@ -327,7 +330,7 @@ App::post('/v1/mock/tests/general/upload') } if ($file['size'] !== 38756) { - throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size'); + throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size'); } if (\md5(\file_get_contents($file['tmp_name'])) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') { @@ -350,6 +353,7 @@ App::get('/v1/mock/tests/general/redirect') ->label('sdk.mock', true) ->inject('response') ->action(function (Response $response) { + $response->redirect('/v1/mock/tests/general/redirect/done'); }); @@ -383,6 +387,7 @@ App::get('/v1/mock/tests/general/set-cookie') ->inject('response') ->inject('request') ->action(function (Response $response, Request $request) { + $response->addCookie('cookieName', 'cookieValue', \time() + 31536000, '/', $request->getHostname(), true, true); }); @@ -400,6 +405,7 @@ App::get('/v1/mock/tests/general/get-cookie') ->label('sdk.mock', true) ->inject('request') ->action(function (Request $request) { + if ($request->getCookie('cookieName', '') !== 'cookieValue') { throw new Exception(Exception::GENERAL_MOCK, 'Missing cookie value'); } @@ -418,6 +424,7 @@ App::get('/v1/mock/tests/general/empty') ->label('sdk.mock', true) ->inject('response') ->action(function (Response $response) { + $response->noContent(); }); @@ -458,9 +465,9 @@ App::get('/v1/mock/tests/general/headers') 'x-sdk-version' => $request->getHeader('x-sdk-version'), ]; $res = array_map(function ($key, $value) { - return $key.': '.$value; + return $key . ': ' . $value; }, array_keys($res), $res); - $res = implode('; ', $res); + $res = implode("; ", $res); $response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK); }); @@ -511,9 +518,11 @@ App::get('/v1/mock/tests/general/502-error') ->label('sdk.mock', true) ->inject('response') ->action(function (Response $response) { + $response ->setStatusCode(502) - ->text('This is a text error'); + ->text('This is a text error') + ; }); App::get('/v1/mock/tests/general/oauth2') @@ -528,7 +537,8 @@ App::get('/v1/mock/tests/general/oauth2') ->param('state', '', new Text(1024), 'OAuth2 state.') ->inject('response') ->action(function (string $client_id, string $redirectURI, string $scope, string $state, Response $response) { - $response->redirect($redirectURI.'?'.\http_build_query(['code' => 'abcdef', 'state' => $state])); + + $response->redirect($redirectURI . '?' . \http_build_query(['code' => 'abcdef', 'state' => $state])); }); App::get('/v1/mock/tests/general/oauth2/token') @@ -545,6 +555,7 @@ App::get('/v1/mock/tests/general/oauth2/token') ->param('refresh_token', '', new Text(100), 'OAuth2 refresh token.', true) ->inject('response') ->action(function (string $client_id, string $client_secret, string $grantType, string $redirectURI, string $code, string $refreshToken, Response $response) { + if ($client_id != '1') { throw new Exception(Exception::GENERAL_MOCK, 'Invalid client ID'); } @@ -556,7 +567,7 @@ App::get('/v1/mock/tests/general/oauth2/token') $responseJson = [ 'access_token' => '123456', 'refresh_token' => 'tuvwxyz', - 'expires_in' => 14400, + 'expires_in' => 14400 ]; if ($grantType === 'authorization_code') { @@ -584,6 +595,7 @@ App::get('/v1/mock/tests/general/oauth2/user') ->param('token', '', new Text(100), 'OAuth2 Access Token.') ->inject('response') ->action(function (string $token, Response $response) { + if ($token != '123456') { throw new Exception(Exception::GENERAL_MOCK, 'Invalid token'); } @@ -602,6 +614,7 @@ App::get('/v1/mock/tests/general/oauth2/success') ->label('docs', false) ->inject('response') ->action(function (Response $response) { + $response->json([ 'result' => 'success', ]); @@ -614,6 +627,7 @@ App::get('/v1/mock/tests/general/oauth2/failure') ->label('docs', false) ->inject('response') ->action(function (Response $response) { + $response ->setStatusCode(Response::STATUS_CODE_BAD_REQUEST) ->json([ @@ -627,22 +641,23 @@ App::shutdown() ->inject('response') ->inject('request') ->action(function (App $utopia, Response $response, Request $request) { - $result = []; - $route = $utopia->match($request); - $path = APP_STORAGE_CACHE.'/tests.json'; - $tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : []; - if (! \is_array($tests)) { + $result = []; + $route = $utopia->match($request); + $path = APP_STORAGE_CACHE . '/tests.json'; + $tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : []; + + if (!\is_array($tests)) { throw new Exception(Exception::GENERAL_MOCK, 'Failed to read results', 500); } - $result[$route->getMethod().':'.$route->getPath()] = true; + $result[$route->getMethod() . ':' . $route->getPath()] = true; $tests = \array_merge($tests, $result); - if (! \file_put_contents($path, \json_encode($tests), LOCK_EX)) { + if (!\file_put_contents($path, \json_encode($tests), LOCK_EX)) { throw new Exception(Exception::GENERAL_MOCK, 'Failed to save results', 500); } - $response->dynamic(new Document(['result' => $route->getMethod().':'.$route->getPath().':passed']), Response::MODEL_MOCK); + $response->dynamic(new Document(['result' => $route->getMethod() . ':' . $route->getPath() . ':passed']), Response::MODEL_MOCK); }); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index ad7b3d135d..2bbac41811 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -7,14 +7,14 @@ use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Event\Func; use Appwrite\Event\Mail; -use Appwrite\Event\Usage; use Appwrite\Extend\Exception; +use Appwrite\Event\Usage; use Appwrite\Messaging\Adapter\Realtime; -use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; +use Appwrite\Utopia\Request; +use Utopia\App; use Utopia\Abuse\Abuse; use Utopia\Abuse\Adapters\TimeLimit; -use Utopia\App; use Utopia\Cache\Adapter\Filesystem; use Utopia\Cache\Cache; use Utopia\Database\Database; @@ -36,7 +36,7 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar $replace = $parts[1] ?? ''; $params = match ($namespace) { - 'user' => (array) $user, + 'user' => (array)$user, 'request' => $requestParams, default => $responsePayload, }; @@ -45,11 +45,11 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar $label = \str_replace($find, $params[$replace], $label); } } - return $label; }; $databaseListener = function (string $event, Document $document, Document $project, Usage $queueForUsage, Database $dbForProject) { + $value = 1; if ($event === Database::EVENT_DOCUMENT_DELETE) { $value = -1; @@ -81,13 +81,13 @@ $databaseListener = function (string $event, Document $document, Document $proje ->addReduce($document); } break; - case str_starts_with($document->getCollection(), 'database_') && ! str_contains($document->getCollection(), 'collection'): //collections + case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections $parts = explode('_', $document->getCollection()); $databaseInternalId = $parts[1] ?? 0; $queueForUsage ->addMetric(METRIC_COLLECTIONS, $value) // per project ->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value) // per database -; + ; if ($event === Database::EVENT_DOCUMENT_DELETE) { $queueForUsage @@ -96,7 +96,7 @@ $databaseListener = function (string $event, Document $document, Document $proje break; case str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_'): //documents $parts = explode('_', $document->getCollection()); - $databaseInternalId = $parts[1] ?? 0; + $databaseInternalId = $parts[1] ?? 0; $collectionInternalId = $parts[3] ?? 0; $queueForUsage ->addMetric(METRIC_DOCUMENTS, $value) // per project @@ -132,13 +132,13 @@ $databaseListener = function (string $event, Document $document, Document $proje ->addMetric(METRIC_DEPLOYMENTS, $value) // per project ->addMetric(METRIC_DEPLOYMENTS_STORAGE, $document->getAttribute('size') * $value) // per project ->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS), $value)// per function - ->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value); // per function + ->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value);// per function break; case $document->getCollection() === 'executions': $queueForUsage ->addMetric(METRIC_EXECUTIONS, $value) // per project - ->addMetric(str_replace('{functionInternalId}', $document->getAttribute('functionInternalId'), METRIC_FUNCTION_ID_EXECUTIONS), $value); // per function + ->addMetric(str_replace('{functionInternalId}', $document->getAttribute('functionInternalId'), METRIC_FUNCTION_ID_EXECUTIONS), $value);// per function break; default: break; @@ -161,6 +161,7 @@ App::init() ->inject('mode') ->inject('mails') ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, Usage $queueForUsage, string $mode, Mail $mails) use ($databaseListener) { + $route = $utopia->match($request); if ($project->isEmpty() && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope @@ -173,7 +174,7 @@ App::init() $abuseKeyLabel = $route->getLabel('abuse-key', 'url:{url},ip:{ip}'); $timeLimitArray = []; - $abuseKeyLabel = (! is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel; + $abuseKeyLabel = (!is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel; foreach ($abuseKeyLabel as $abuseKey) { $timeLimit = new TimeLimit($abuseKey, $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForProject); @@ -181,7 +182,7 @@ App::init() ->setParam('{userId}', $user->getId()) ->setParam('{userAgent}', $request->getUserAgent('')) ->setParam('{ip}', $request->getIP()) - ->setParam('{url}', $request->getHostname().$route->getPath()) + ->setParam('{url}', $request->getHostname() . $route->getPath()) ->setParam('{method}', $request->getMethod()); $timeLimitArray[] = $timeLimit; } @@ -194,8 +195,8 @@ App::init() foreach ($timeLimitArray as $timeLimit) { foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys - if (! empty($value)) { - $timeLimit->setParam('{param-'.$key.'}', (\is_array($value)) ? \json_encode($value) : $value); + if (!empty($value)) { + $timeLimit->setParam('{param-' . $key . '}', (\is_array($value)) ? \json_encode($value) : $value); } } @@ -209,15 +210,16 @@ App::init() $response ->addHeader('X-RateLimit-Limit', $limit) ->addHeader('X-RateLimit-Remaining', $remaining) - ->addHeader('X-RateLimit-Reset', $time); + ->addHeader('X-RateLimit-Reset', $time) + ; } $enabled = App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled'; if ( $enabled // Abuse is enabled - && ! $isAppUser // User is not API key - && ! $isPrivilegedUser // User is not an admin + && !$isAppUser // User is not API key + && !$isPrivilegedUser // User is not an admin && $abuse->check() // Route is rate-limited ) { throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED); @@ -241,7 +243,7 @@ App::init() ->setUser($user); $smtp = $project->getAttribute('smtp', []); - if (! empty($smtp) && ($smtp['enabled'] ?? false)) { + if (!empty($smtp) && ($smtp['enabled'] ?? false)) { $mails ->setSmtpHost($smtp['host'] ?? '') ->setSmtpPort($smtp['port'] ?? 25) @@ -263,14 +265,14 @@ App::init() $useCache = $route->getLabel('cache', false); if ($useCache) { - $key = md5($request->getURI().implode('*', $request->getParams())).'*'.APP_CACHE_BUSTER; + $key = md5($request->getURI() . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER; $cache = new Cache( - new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$project->getId()) + new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId()) ); $timestamp = 60 * 60 * 24 * 30; $data = $cache->load($key, $timestamp); - if (! empty($data)) { + if (!empty($data)) { $data = json_decode($data, true); $parts = explode('/', $data['resourceType']); $type = $parts[0] ?? null; @@ -280,24 +282,24 @@ App::init() $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); - if (! $fileSecurity && ! $valid) { + if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } $parts = explode('/', $data['resource']); $fileId = $parts[1] ?? null; - if ($fileSecurity && ! $valid) { - $file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId); + if ($fileSecurity && !$valid) { + $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -306,10 +308,11 @@ App::init() } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp).' GMT') + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT') ->addHeader('X-Appwrite-Cache', 'hit') ->setContentType($data['contentType']) - ->send(base64_decode($data['payload'])); + ->send(base64_decode($data['payload'])) + ; $route->setIsActive(false); } else { @@ -324,6 +327,7 @@ App::init() ->inject('request') ->inject('project') ->action(function (App $utopia, Request $request, Document $project) { + $route = $utopia->match($request); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -427,9 +431,10 @@ App::shutdown() ->inject('mode') ->inject('dbForConsole') ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, Func $queueForFunctions, Usage $queueForUsage, string $mode, Database $dbForConsole) use ($parseLabel) { + $responsePayload = $response->getPayload(); - if (! empty($events->getEvent())) { + if (!empty($events->getEvent())) { if (empty($events->getPayload())) { $events->setPayload($responsePayload); } @@ -478,7 +483,7 @@ App::shutdown() roles: $target['roles'], options: [ 'permissionsChanged' => $target['permissionsChanged'], - 'userId' => $events->getParam('userId'), + 'userId' => $events->getParam('userId') ] ); } @@ -491,24 +496,24 @@ App::shutdown() * Audit labels */ $pattern = $route->getLabel('audits.resource', null); - if (! empty($pattern)) { + if (!empty($pattern)) { $resource = $parseLabel($pattern, $responsePayload, $requestParams, $user); - if (! empty($resource) && $resource !== $pattern) { + if (!empty($resource) && $resource !== $pattern) { $audits->setResource($resource); } } - if (! $user->isEmpty()) { + if (!$user->isEmpty()) { $audits->setUser($user); } - if (! empty($audits->getResource()) && ! empty($audits->getUser()->getId())) { + if (!empty($audits->getResource()) && !empty($audits->getUser()->getId())) { /** * audits.payload is switched to default true * in order to auto audit payload for all endpoints */ $pattern = $route->getLabel('audits.payload', true); - if (! empty($pattern)) { + if (!empty($pattern)) { $audits->setPayload($responsePayload); } @@ -518,11 +523,11 @@ App::shutdown() $audits->trigger(); } - if (! empty($deletes->getType())) { + if (!empty($deletes->getType())) { $deletes->trigger(); } - if (! empty($database->getType())) { + if (!empty($database->getType())) { $database->trigger(); } @@ -534,35 +539,35 @@ App::shutdown() $resource = $resourceType = null; $data = $response->getPayload(); - if (! empty($data['payload'])) { + if (!empty($data['payload'])) { $pattern = $route->getLabel('cache.resource', null); - if (! empty($pattern)) { + if (!empty($pattern)) { $resource = $parseLabel($pattern, $responsePayload, $requestParams, $user); } $pattern = $route->getLabel('cache.resourceType', null); - if (! empty($pattern)) { + if (!empty($pattern)) { $resourceType = $parseLabel($pattern, $responsePayload, $requestParams, $user); } - $key = md5($request->getURI().implode('*', $request->getParams())).'*'.APP_CACHE_BUSTER; + $key = md5($request->getURI() . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER; $data = json_encode([ 'resourceType' => $resourceType, 'resource' => $resource, 'contentType' => $response->getContentType(), 'payload' => base64_encode($data['payload']), - ]); + ]) ; $signature = md5($data); - $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); + $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); $accessedAt = $cacheLog->getAttribute('accessedAt', ''); $now = DateTime::now(); if ($cacheLog->isEmpty()) { Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([ - '$id' => $key, - 'resource' => $resource, - 'accessedAt' => $now, - 'signature' => $signature, + '$id' => $key, + 'resource' => $resource, + 'accessedAt' => $now, + 'signature' => $signature, ]))); } elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) { $cacheLog->setAttribute('accessedAt', $now); @@ -571,18 +576,20 @@ App::shutdown() if ($signature !== $cacheLog->getAttribute('signature')) { $cache = new Cache( - new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$project->getId()) + new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId()) ); $cache->save($key, $data); } } } + + if ($project->getId() !== 'console') { if ($mode !== APP_MODE_ADMIN) { $fileSize = 0; $file = $request->getFiles('file'); - if (! empty($file)) { + if (!empty($file)) { $fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size']; } @@ -600,7 +607,7 @@ App::shutdown() /** * Update user last activity */ - if (! $user->isEmpty()) { + if (!$user->isEmpty()) { $accessedAt = $user->getAttribute('accessedAt', ''); if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_USER_ACCCESS)) > $accessedAt) { $user->setAttribute('accessedAt', DateTime::now()); diff --git a/app/controllers/shared/api/auth.php b/app/controllers/shared/api/auth.php index acb8410804..5b1af0d36c 100644 --- a/app/controllers/shared/api/auth.php +++ b/app/controllers/shared/api/auth.php @@ -1,9 +1,9 @@ inject('request') ->inject('project') ->action(function (App $utopia, Request $request, Document $project) { + $route = $utopia->match($request); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index 37914dda37..dcf9c80a51 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -11,9 +11,9 @@ App::init() ->action(function (Request $request, Response $response) { $response ->addHeader('X-Frame-Options', 'SAMEORIGIN') // Avoid console and homepage from showing in iframes - ->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url='.\urlencode($request->getURI())) + ->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url=' . \urlencode($request->getURI())) ->addHeader('X-UA-Compatible', 'IE=Edge') // Deny IE browsers from going into quirks mode -; + ; }); App::get('/console/*') @@ -30,41 +30,41 @@ App::get('/console/*') ->inject('request') ->inject('response') ->action(function (Request $request, Response $response) { - $fallback = file_get_contents(__DIR__.'/../../../console/index.html'); + $fallback = file_get_contents(__DIR__ . '/../../../console/index.html'); // Card SSR if (\str_starts_with($request->getURI(), '/card')) { $urlCunks = \explode('/', $request->getURI()); $userId = $urlCunks[\count($urlCunks) - 1] ?? ''; - $domain = $request->getProtocol().'://'.$request->getHostname(); + $domain = $request->getProtocol() . '://' . $request->getHostname(); - if (! empty($userId)) { - $ogImageUrl = $domain.'/v1/cards/cloud-og?userId='.$userId; + if (!empty($userId)) { + $ogImageUrl = $domain . '/v1/cards/cloud-og?userId=' . $userId; } else { - $ogImageUrl = $domain.'/v1/cards/cloud-og?mock=normal'; + $ogImageUrl = $domain . '/v1/cards/cloud-og?mock=normal'; } $ogTags = [ 'Appwrite Cloud Card', '', - '', + '', '', '', '', '', '', '', - '', + '', '', - '', - '', + '', + '', '', '', '', '', '', - '', + '', ]; $fallback = \str_replace('', \implode('', $ogTags), $fallback); diff --git a/app/controllers/web/home.php b/app/controllers/web/home.php index fb33350792..e90f3ec25b 100644 --- a/app/controllers/web/home.php +++ b/app/controllers/web/home.php @@ -24,14 +24,14 @@ App::get('/versions') continue; } - if (isset($language['enabled']) && ! $language['enabled']) { + if (isset($language['enabled']) && !$language['enabled']) { continue; } $platformKey = $platform['key'] ?? ''; $languageKey = $language['key'] ?? ''; $version = $language['version'] ?? ''; - $versions[$platformKey.'-'.$languageKey] = $version; + $versions[$platformKey . '-' . $languageKey] = $version; } } diff --git a/app/http.php b/app/http.php index 88ee35ff1f..8ce7b6f017 100644 --- a/app/http.php +++ b/app/http.php @@ -1,30 +1,30 @@ on('WorkerStart', function ($server, $workerId) { - Console::success('Worker '.++$workerId.' started successfully'); + Console::success('Worker ' . ++$workerId . ' started successfully'); }); $http->on('BeforeReload', function ($server, $workerId) { @@ -53,16 +53,16 @@ $http->on('AfterReload', function ($server, $workerId) { Console::success('Reload completed...'); }); -Files::load(__DIR__.'/../console'); +Files::load(__DIR__ . '/../console'); -include __DIR__.'/controllers/general.php'; +include __DIR__ . '/controllers/general.php'; $http->on('start', function (Server $http) use ($payloadSize, $register) { $app = new App('UTC'); go(function () use ($register, $app) { $pools = $register->get('pools'); /** @var Group $pools */ - App::setResource('pools', fn () => $pools); + App::setResource('pools', fn() => $pools); // wait for database to be ready $attempts = 0; @@ -77,7 +77,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { } catch (\Exception $e) { Console::warning("Database not ready. Retrying connection ({$attempts})..."); if ($attempts >= $max) { - throw new \Exception('Failed to connect to database: '.$e->getMessage()); + throw new \Exception('Failed to connect to database: ' . $e->getMessage()); } sleep($sleep); } @@ -98,7 +98,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { } if ($dbForConsole->getCollection(TimeLimit::COLLECTION)->isEmpty()) { - $adapter = new TimeLimit('', 0, 1, $dbForConsole); + $adapter = new TimeLimit("", 0, 1, $dbForConsole); $adapter->setup(); } @@ -109,11 +109,11 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { if (($collection['$collection'] ?? '') !== Database::METADATA) { continue; } - if (! $dbForConsole->getCollection($key)->isEmpty()) { + if (!$dbForConsole->getCollection($key)->isEmpty()) { continue; } - Console::success('[Setup] - Creating collection: '.$collection['$id'].'...'); + Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...'); $attributes = []; $indexes = []; @@ -128,7 +128,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '', + 'format' => $attribute['format'] ?? '' ]); } @@ -145,7 +145,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { $dbForConsole->createCollection($key, $attributes, $indexes); } - if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && ! $dbForConsole->exists($dbForConsole->getDefaultDatabase(), 'bucket_1')) { + if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && !$dbForConsole->exists($dbForConsole->getDefaultDatabase(), 'bucket_1')) { Console::success('[Setup] - Creating default bucket...'); $dbForConsole->createDocument('buckets', new Document([ '$id' => ID::custom('default'), @@ -188,7 +188,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { 'array' => $attribute['array'], 'filters' => $attribute['filters'], 'default' => $attribute['default'] ?? null, - 'format' => $attribute['format'] ?? '', + 'format' => $attribute['format'] ?? '' ]); } @@ -202,7 +202,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { ]); } - $dbForConsole->createCollection('bucket_'.$bucket->getInternalId(), $attributes, $indexes); + $dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes); } $pools->reclaim(); @@ -210,7 +210,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { Console::success('[Setup] - Server database init completed...'); }); - Console::success('Server started successfully (max payload is '.number_format($payloadSize).' bytes)'); + Console::success('Server started successfully (max payload is ' . number_format($payloadSize) . ' bytes)'); Console::info("Master pid {$http->master_pid}, manager pid {$http->manager_pid}"); // listen ctrl + c @@ -229,8 +229,8 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $response ->setContentType(Files::getFileMimeType($request->getURI())) - ->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', 'public, max-age=' . $time) + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache ->send(Files::getFileContents($request->getURI())); return; @@ -239,7 +239,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $app = new App('UTC'); $pools = $register->get('pools'); - App::setResource('pools', fn () => $pools); + App::setResource('pools', fn() => $pools); try { Authorization::cleanRoles(); @@ -249,7 +249,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo } catch (\Throwable $th) { $version = App::getEnv('_APP_VERSION', 'UNKNOWN'); - $logger = $app->getResource('logger'); + $logger = $app->getResource("logger"); if ($logger) { try { /** @var Utopia\Database\Document $user */ @@ -258,16 +258,16 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo // All good, user is optional information for logger } - $loggerBreadcrumbs = $app->getResource('loggerBreadcrumbs'); + $loggerBreadcrumbs = $app->getResource("loggerBreadcrumbs"); $route = $app->match($request); $log = new Utopia\Logger\Log(); - if (isset($user) && ! $user->isEmpty()) { + if (isset($user) && !$user->isEmpty()) { $log->setUser(new User($user->getId())); } - $log->setNamespace('http'); + $log->setNamespace("http"); $log->setServer(\gethostname()); $log->setVersion($version); $log->setType(Log::TYPE_ERROR); @@ -279,7 +279,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $log->addTag('code', $th->getCode()); // $log->addTag('projectId', $project->getId()); // TODO: Figure out how to get ProjectID, if it becomes relevant $log->addTag('hostname', $request->getHostname()); - $log->addTag('locale', (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', ''))); + $log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', ''))); $log->addExtra('file', $th->getFile()); $log->addExtra('line', $th->getLine()); @@ -287,7 +287,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $log->addExtra('detailedTrace', $th->getTrace()); $log->addExtra('roles', Authorization::getRoles()); - $action = $route->getLabel('sdk.namespace', 'UNKNOWN_NAMESPACE').'.'.$route->getLabel('sdk.method', 'UNKNOWN_METHOD'); + $action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD"); $log->setAction($action); $isProduction = App::getEnv('_APP_ENV', 'development') === 'production'; @@ -298,18 +298,18 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo } $responseCode = $logger->addLog($log); - Console::info('Log pushed with status code: '.$responseCode); + Console::info('Log pushed with status code: ' . $responseCode); } - Console::error('[Error] Type: '.get_class($th)); - Console::error('[Error] Message: '.$th->getMessage()); - Console::error('[Error] File: '.$th->getFile()); - Console::error('[Error] Line: '.$th->getLine()); + Console::error('[Error] Type: ' . get_class($th)); + Console::error('[Error] Message: ' . $th->getMessage()); + Console::error('[Error] File: ' . $th->getFile()); + Console::error('[Error] Line: ' . $th->getLine()); $swooleResponse->setStatusCode(500); $output = ((App::isDevelopment())) ? [ - 'message' => 'Error: '.$th->getMessage(), + 'message' => 'Error: ' . $th->getMessage(), 'code' => 500, 'file' => $th->getFile(), 'line' => $th->getLine(), diff --git a/app/init.php b/app/init.php index 2eb066e737..ea3a039ec9 100644 --- a/app/init.php +++ b/app/init.php @@ -5,9 +5,11 @@ * * Initializes both Appwrite API entry point, queue workers, and CLI tasks. * Set configuration, framework resources & app constants + * */ -if (\file_exists(__DIR__.'/../vendor/autoload.php')) { - require_once __DIR__.'/../vendor/autoload.php'; + +if (\file_exists(__DIR__ . '/../vendor/autoload.php')) { + require_once __DIR__ . '/../vendor/autoload.php'; } ini_set('memory_limit', '512M'); @@ -16,54 +18,41 @@ ini_set('display_startup_errors', 1); ini_set('default_socket_timeout', -1); error_reporting(E_ALL); -use Ahc\Jwt\JWT; -use Ahc\Jwt\JWTException; +use Appwrite\Event\Usage; +use Appwrite\Extend\Exception; use Appwrite\Auth\Auth; use Appwrite\Event\Audit; use Appwrite\Event\Database as EventDatabase; -use Appwrite\Event\Delete; use Appwrite\Event\Event; -use Appwrite\Event\Func; use Appwrite\Event\Mail; use Appwrite\Event\Phone; -use Appwrite\Event\Usage; -use Appwrite\Extend\Exception; -use Appwrite\GraphQL\Promises\Adapter\Swoole; +use Appwrite\Event\Delete; use Appwrite\GraphQL\Schema; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\Origin; use Appwrite\OpenSSL\OpenSSL; use Appwrite\URL\URL as AppwriteURL; -use MaxMind\Db\Reader; -use PHPMailer\PHPMailer\PHPMailer; -use Swoole\Database\PDOProxy; use Utopia\App; +use Utopia\Logger\Logger; use Utopia\Cache\Adapter\Redis as RedisCache; -use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; use Utopia\Config\Config; -use Utopia\Database\Adapter\MariaDB; -use Utopia\Database\Adapter\MySQL; +use Utopia\Database\Helpers\ID; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Helpers\ID; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Structure; -use Utopia\DSN\DSN; use Utopia\Locale\Locale; -use Utopia\Logger\Logger; +use Utopia\DSN\DSN; use Utopia\Messaging\Adapters\SMS\Mock; +use Appwrite\GraphQL\Promises\Adapter\Swoole; use Utopia\Messaging\Adapters\SMS\Msg91; use Utopia\Messaging\Adapters\SMS\Telesign; use Utopia\Messaging\Adapters\SMS\TextMagic; use Utopia\Messaging\Adapters\SMS\Twilio; use Utopia\Messaging\Adapters\SMS\Vonage; -use Utopia\Pools\Group; -use Utopia\Pools\Pool; -use Utopia\Queue; -use Utopia\Queue\Connection; use Utopia\Registry\Registry; use Utopia\Storage\Device; use Utopia\Storage\Device\Backblaze; @@ -72,9 +61,22 @@ use Utopia\Storage\Device\Linode; use Utopia\Storage\Device\Local; use Utopia\Storage\Device\S3; use Utopia\Storage\Device\Wasabi; +use Utopia\Cache\Adapter\Sharding; +use Utopia\Database\Adapter\MariaDB; +use Utopia\Database\Adapter\MySQL; +use Utopia\Pools\Group; +use Utopia\Pools\Pool; +use Ahc\Jwt\JWT; +use Ahc\Jwt\JWTException; +use Appwrite\Event\Func; +use MaxMind\Db\Reader; +use PHPMailer\PHPMailer\PHPMailer; +use Swoole\Database\PDOProxy; +use Utopia\Queue; +use Utopia\Queue\Connection; use Utopia\Storage\Storage; -use Utopia\Validator\IP; use Utopia\Validator\Range; +use Utopia\Validator\IP; use Utopia\Validator\URL; use Utopia\Validator\WhiteList; @@ -82,7 +84,7 @@ const APP_NAME = 'Appwrite'; const APP_DOMAIN = 'appwrite.io'; const APP_EMAIL_TEAM = 'team@localhost.test'; // Default email address const APP_EMAIL_SECURITY = ''; // Default security email address -const APP_USERAGENT = APP_NAME.'-Server v%s. Please report abuse at %s'; +const APP_USERAGENT = APP_NAME . '-Server v%s. Please report abuse at %s'; const APP_MODE_DEFAULT = 'default'; const APP_MODE_ADMIN = 'admin'; const APP_PAGING_LIMIT = 12; @@ -160,7 +162,7 @@ const DELETE_TYPE_REALTIME = 'realtime'; const DELETE_TYPE_BUCKETS = 'buckets'; const DELETE_TYPE_SESSIONS = 'sessions'; const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp'; -const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; +const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; const DELETE_TYPE_SCHEDULES = 'schedules'; // Compression type const COMPRESSION_TYPE_NONE = 'none'; @@ -182,7 +184,7 @@ const MAX_OUTPUT_CHUNK_SIZE = 2 * 1024 * 1024; // 2MB // Usage metrics const METRIC_TEAMS = 'teams'; const METRIC_USERS = 'users'; -const METRIC_SESSIONS = 'sessions'; +const METRIC_SESSIONS = 'sessions'; const METRIC_DATABASES = 'databases'; const METRIC_COLLECTIONS = 'collections'; const METRIC_DATABASE_ID_COLLECTIONS = '{databaseInternalId}.collections'; @@ -190,28 +192,28 @@ const METRIC_DOCUMENTS = 'documents'; const METRIC_DATABASE_ID_DOCUMENTS = '{databaseInternalId}.documents'; const METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS = '{databaseInternalId}.{collectionInternalId}.documents'; const METRIC_BUCKETS = 'buckets'; -const METRIC_FILES = 'files'; -const METRIC_FILES_STORAGE = 'files.storage'; +const METRIC_FILES = 'files'; +const METRIC_FILES_STORAGE = 'files.storage'; const METRIC_BUCKET_ID_FILES = '{bucketInternalId}.files'; -const METRIC_BUCKET_ID_FILES_STORAGE = '{bucketInternalId}.files.storage'; -const METRIC_FUNCTIONS = 'functions'; -const METRIC_DEPLOYMENTS = 'deployments'; -const METRIC_DEPLOYMENTS_STORAGE = 'deployments.storage'; -const METRIC_BUILDS = 'builds'; -const METRIC_BUILDS_STORAGE = 'builds.storage'; -const METRIC_BUILDS_COMPUTE = 'builds.compute'; -const METRIC_FUNCTION_ID_BUILDS = '{functionInternalId}.builds'; +const METRIC_BUCKET_ID_FILES_STORAGE = '{bucketInternalId}.files.storage'; +const METRIC_FUNCTIONS = 'functions'; +const METRIC_DEPLOYMENTS = 'deployments'; +const METRIC_DEPLOYMENTS_STORAGE = 'deployments.storage'; +const METRIC_BUILDS = 'builds'; +const METRIC_BUILDS_STORAGE = 'builds.storage'; +const METRIC_BUILDS_COMPUTE = 'builds.compute'; +const METRIC_FUNCTION_ID_BUILDS = '{functionInternalId}.builds'; const METRIC_FUNCTION_ID_BUILDS_STORAGE = '{functionInternalId}.builds.storage'; -const METRIC_FUNCTION_ID_BUILDS_COMPUTE = '{functionInternalId}.builds.compute'; -const METRIC_FUNCTION_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments'; -const METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage'; -const METRIC_EXECUTIONS = 'executions'; -const METRIC_EXECUTIONS_COMPUTE = 'executions.compute'; -const METRIC_FUNCTION_ID_EXECUTIONS = '{functionInternalId}.executions'; -const METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE = '{functionInternalId}.executions.compute'; -const METRIC_NETWORK_REQUESTS = 'network.requests'; -const METRIC_NETWORK_INBOUND = 'network.inbound'; -const METRIC_NETWORK_OUTBOUND = 'network.outbound'; +const METRIC_FUNCTION_ID_BUILDS_COMPUTE = '{functionInternalId}.builds.compute'; +const METRIC_FUNCTION_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments'; +const METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage'; +const METRIC_EXECUTIONS = 'executions'; +const METRIC_EXECUTIONS_COMPUTE = 'executions.compute'; +const METRIC_FUNCTION_ID_EXECUTIONS = '{functionInternalId}.executions'; +const METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE = '{functionInternalId}.executions.compute'; +const METRIC_NETWORK_REQUESTS = 'network.requests'; +const METRIC_NETWORK_INBOUND = 'network.inbound'; +const METRIC_NETWORK_OUTBOUND = 'network.outbound'; $register = new Registry(); @@ -220,42 +222,42 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION)); /* * ENV vars */ -Config::load('events', __DIR__.'/config/events.php'); -Config::load('auth', __DIR__.'/config/auth.php'); -Config::load('errors', __DIR__.'/config/errors.php'); -Config::load('authProviders', __DIR__.'/config/authProviders.php'); -Config::load('platforms', __DIR__.'/config/platforms.php'); -Config::load('collections', __DIR__.'/config/collections.php'); -Config::load('runtimes', __DIR__.'/config/runtimes.php'); -Config::load('usage', __DIR__.'/config/usage.php'); -Config::load('roles', __DIR__.'/config/roles.php'); // User roles and scopes -Config::load('scopes', __DIR__.'/config/scopes.php'); // User roles and scopes -Config::load('services', __DIR__.'/config/services.php'); // List of services -Config::load('variables', __DIR__.'/config/variables.php'); // List of env variables -Config::load('regions', __DIR__.'/config/regions.php'); // List of available regions -Config::load('avatar-browsers', __DIR__.'/config/avatars/browsers.php'); -Config::load('avatar-credit-cards', __DIR__.'/config/avatars/credit-cards.php'); -Config::load('avatar-flags', __DIR__.'/config/avatars/flags.php'); -Config::load('locale-codes', __DIR__.'/config/locale/codes.php'); -Config::load('locale-currencies', __DIR__.'/config/locale/currencies.php'); -Config::load('locale-eu', __DIR__.'/config/locale/eu.php'); -Config::load('locale-languages', __DIR__.'/config/locale/languages.php'); -Config::load('locale-phones', __DIR__.'/config/locale/phones.php'); -Config::load('locale-countries', __DIR__.'/config/locale/countries.php'); -Config::load('locale-continents', __DIR__.'/config/locale/continents.php'); -Config::load('locale-templates', __DIR__.'/config/locale/templates.php'); -Config::load('storage-logos', __DIR__.'/config/storage/logos.php'); -Config::load('storage-mimes', __DIR__.'/config/storage/mimes.php'); -Config::load('storage-inputs', __DIR__.'/config/storage/inputs.php'); -Config::load('storage-outputs', __DIR__.'/config/storage/outputs.php'); -Config::load('messagingProviders', __DIR__.'/config/messagingProviders.php'); +Config::load('events', __DIR__ . '/config/events.php'); +Config::load('auth', __DIR__ . '/config/auth.php'); +Config::load('errors', __DIR__ . '/config/errors.php'); +Config::load('authProviders', __DIR__ . '/config/authProviders.php'); +Config::load('platforms', __DIR__ . '/config/platforms.php'); +Config::load('collections', __DIR__ . '/config/collections.php'); +Config::load('runtimes', __DIR__ . '/config/runtimes.php'); +Config::load('usage', __DIR__ . '/config/usage.php'); +Config::load('roles', __DIR__ . '/config/roles.php'); // User roles and scopes +Config::load('scopes', __DIR__ . '/config/scopes.php'); // User roles and scopes +Config::load('services', __DIR__ . '/config/services.php'); // List of services +Config::load('variables', __DIR__ . '/config/variables.php'); // List of env variables +Config::load('regions', __DIR__ . '/config/regions.php'); // List of available regions +Config::load('avatar-browsers', __DIR__ . '/config/avatars/browsers.php'); +Config::load('avatar-credit-cards', __DIR__ . '/config/avatars/credit-cards.php'); +Config::load('avatar-flags', __DIR__ . '/config/avatars/flags.php'); +Config::load('locale-codes', __DIR__ . '/config/locale/codes.php'); +Config::load('locale-currencies', __DIR__ . '/config/locale/currencies.php'); +Config::load('locale-eu', __DIR__ . '/config/locale/eu.php'); +Config::load('locale-languages', __DIR__ . '/config/locale/languages.php'); +Config::load('locale-phones', __DIR__ . '/config/locale/phones.php'); +Config::load('locale-countries', __DIR__ . '/config/locale/countries.php'); +Config::load('locale-continents', __DIR__ . '/config/locale/continents.php'); +Config::load('locale-templates', __DIR__ . '/config/locale/templates.php'); +Config::load('storage-logos', __DIR__ . '/config/storage/logos.php'); +Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php'); +Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php'); +Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php'); +Config::load('messagingProviders', __DIR__ . '/config/messagingProviders.php'); $user = App::getEnv('_APP_REDIS_USER', ''); $pass = App::getEnv('_APP_REDIS_PASS', ''); -if (! empty($user) || ! empty($pass)) { - Resque::setBackend('redis://'.$user.':'.$pass.'@'.App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', '')); +if (!empty($user) || !empty($pass)) { + Resque::setBackend('redis://' . $user . ':' . $pass . '@' . App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', '')); } else { - Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', '')); + Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', '')); } /** @@ -311,7 +313,8 @@ Database::addFilter( if (isset($formatOptions['min']) || isset($formatOptions['max'])) { $attribute ->setAttribute('min', $formatOptions['min']) - ->setAttribute('max', $formatOptions['max']); + ->setAttribute('max', $formatOptions['max']) + ; } return $value; @@ -434,7 +437,7 @@ Database::addFilter( return null; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn () => $database + return Authorization::skip(fn() => $database ->find('tokens', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -448,7 +451,7 @@ Database::addFilter( return null; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn () => $database + return Authorization::skip(fn() => $database ->find('memberships', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -490,7 +493,7 @@ Database::addFilter( return null; } $value = json_decode($value, true); - $key = App::getEnv('_APP_OPENSSL_KEY_V'.$value['version']); + $key = App::getEnv('_APP_OPENSSL_KEY_V' . $value['version']); return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag'])); } @@ -503,11 +506,11 @@ Database::addFilter( $user->getId(), $user->getAttribute('email', ''), $user->getAttribute('name', ''), - $user->getAttribute('phone', ''), + $user->getAttribute('phone', '') ]; foreach ($user->getAttribute('labels', []) as $label) { - $searchValues[] = 'label:'.$label; + $searchValues[] = 'label:' . $label; } $search = implode(' ', \array_filter($searchValues)); @@ -525,7 +528,7 @@ Database::addFilter( return null; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn () => $database + return Authorization::skip(fn() => $database ->find('targets', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -539,7 +542,7 @@ Database::addFilter( return null; }, function (mixed $value, Document $document, Database $database) { - $provider = Authorization::skip(fn () => $database + $provider = Authorization::skip(fn() => $database ->findOne('providers', [ Query::equal('$id', [$document->getAttribute('providerId')]), Query::select(['type']), @@ -548,7 +551,6 @@ Database::addFilter( if ($provider) { return $provider->getAttribute('type'); } - return null; } ); @@ -566,7 +568,6 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_DATETIME, function () { Structure::addFormat(APP_DATABASE_ATTRIBUTE_ENUM, function ($attribute) { $elements = $attribute['formatOptions']['elements']; - return new WhiteList($elements, true); }, Database::VAR_STRING); @@ -581,14 +582,12 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_URL, function () { Structure::addFormat(APP_DATABASE_ATTRIBUTE_INT_RANGE, function ($attribute) { $min = $attribute['formatOptions']['min'] ?? -INF; $max = $attribute['formatOptions']['max'] ?? INF; - return new Range($min, $max, Range::TYPE_INTEGER); }, Database::VAR_INTEGER); Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function ($attribute) { $min = $attribute['formatOptions']['min'] ?? -INF; $max = $attribute['formatOptions']['max'] ?? INF; - return new Range($min, $max, Range::TYPE_FLOAT); }, Database::VAR_FLOAT); @@ -604,13 +603,12 @@ $register->set('logger', function () { return null; } - if (! Logger::hasProvider($providerName)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Logging provider not supported. Logging is disabled'); + if (!Logger::hasProvider($providerName)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled"); } - $classname = '\\Utopia\\Logger\\Adapter\\'.\ucfirst($providerName); + $classname = '\\Utopia\\Logger\\Adapter\\' . \ucfirst($providerName); $adapter = new $classname($providerConfig); - return new Logger($adapter); }); $register->set('pools', function () { @@ -679,7 +677,7 @@ $register->set('pools', function () { throw new \Exception('Pool size is too small. Increase the number of allowed database connections or decrease the number of workers.', 500); } - $poolSize = (int) ($instanceConnections / $workerCount); + $poolSize = (int)($instanceConnections / $workerCount); foreach ($connections as $key => $connection) { $type = $connection['type'] ?? ''; @@ -690,7 +688,7 @@ $register->set('pools', function () { $dsns = explode(',', $connection['dsns'] ?? ''); foreach ($dsns as &$dsn) { $dsn = explode('=', $dsn); - $name = ($multipe) ? $key.'_'.$dsn[0] : $key; + $name = ($multipe) ? $key . '_' . $dsn[0] : $key; $dsn = $dsn[1] ?? ''; $config[] = $name; if (empty($dsn)) { @@ -706,8 +704,8 @@ $register->set('pools', function () { $dsnScheme = $dsn->getScheme(); $dsnDatabase = $dsn->getPath(); - if (! in_array($dsnScheme, $schemes)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Invalid console database scheme'); + if (!in_array($dsnScheme, $schemes)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme"); } /** @@ -722,21 +720,21 @@ $register->set('pools', function () { case 'mariadb': $resource = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { - return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, [ + return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array( PDO::ATTR_TIMEOUT => 3, // Seconds PDO::ATTR_PERSISTENT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed PDO::ATTR_EMULATE_PREPARES => true, - PDO::ATTR_STRINGIFY_FETCHES => true, - ]); + PDO::ATTR_STRINGIFY_FETCHES => true + )); }); }; break; case 'redis': $resource = function () use ($dsnHost, $dsnPort, $dsnPass) { $redis = new Redis(); - @$redis->pconnect($dsnHost, (int) $dsnPort); + @$redis->pconnect($dsnHost, (int)$dsnPort); if ($dsnPass) { $redis->auth($dsnPass); } @@ -747,7 +745,7 @@ $register->set('pools', function () { break; default: - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Invalid scheme'); + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid scheme"); break; } @@ -781,7 +779,7 @@ $register->set('pools', function () { break; default: - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Server error: Missing adapter implementation.'); + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); break; } @@ -791,7 +789,7 @@ $register->set('pools', function () { $group->add($pool); } - Config::setParam('pools-'.$key, $config); + Config::setParam('pools-' . $key, $config); } return $group; @@ -808,14 +806,14 @@ $register->set('smtp', function () { $mail->XMailer = 'Appwrite Mailer'; $mail->Host = App::getEnv('_APP_SMTP_HOST', 'smtp'); $mail->Port = App::getEnv('_APP_SMTP_PORT', 25); - $mail->SMTPAuth = (! empty($username) && ! empty($password)); + $mail->SMTPAuth = (!empty($username) && !empty($password)); $mail->Username = $username; $mail->Password = $password; $mail->SMTPSecure = App::getEnv('_APP_SMTP_SECURE', false); $mail->SMTPAutoTLS = false; $mail->CharSet = 'UTF-8'; - $from = \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')); + $from = \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')); $email = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); $mail->setFrom($email, $from); @@ -826,13 +824,12 @@ $register->set('smtp', function () { return $mail; }); $register->set('geodb', function () { - return new Reader(__DIR__.'/assets/dbip/dbip-country-lite-2023-01.mmdb'); + return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2023-01.mmdb'); }); $register->set('passwordsDictionary', function () { - $content = \file_get_contents(__DIR__.'/assets/security/10k-common-passwords'); + $content = \file_get_contents(__DIR__ . '/assets/security/10k-common-passwords'); $content = explode("\n", $content); $content = array_flip($content); - return $content; }); $register->set('promiseAdapter', function () { @@ -848,12 +845,12 @@ $locales = Config::getParam('locale-codes', []); foreach ($locales as $locale) { $code = $locale['code']; - $path = __DIR__.'/config/locale/translations/'.$code.'.json'; + $path = __DIR__ . '/config/locale/translations/' . $code . '.json'; - if (! \file_exists($path)) { - $path = __DIR__.'/config/locale/translations/'.\substr($code, 0, 2).'.json'; // if `ar-ae` doesn't exist, look for `ar` - if (! \file_exists($path)) { - $path = __DIR__.'/config/locale/translations/en.json'; // if none translation exists, use default from `en.json` + if (!\file_exists($path)) { + $path = __DIR__ . '/config/locale/translations/' . \substr($code, 0, 2) . '.json'; // if `ar-ae` doesn't exist, look for `ar` + if (!\file_exists($path)) { + $path = __DIR__ . '/config/locale/translations/en.json'; // if none translation exists, use default from `en.json` } } @@ -881,20 +878,20 @@ App::setResource('loggerBreadcrumbs', function () { return []; }); -App::setResource('register', fn () => $register); -App::setResource('locale', fn () => new Locale(App::getEnv('_APP_LOCALE', 'en'))); +App::setResource('register', fn() => $register); +App::setResource('locale', fn() => new Locale(App::getEnv('_APP_LOCALE', 'en'))); App::setResource('localeCodes', function () { - return array_map(fn ($locale) => $locale['code'], Config::getParam('locale-codes', [])); + return array_map(fn($locale) => $locale['code'], Config::getParam('locale-codes', [])); }); // Queues -App::setResource('events', fn () => new Event('', '')); -App::setResource('audits', fn () => new Audit()); -App::setResource('mails', fn () => new Mail()); -App::setResource('deletes', fn () => new Delete()); -App::setResource('database', fn () => new EventDatabase()); -App::setResource('messaging', fn () => new Phone()); +App::setResource('events', fn() => new Event('', '')); +App::setResource('audits', fn() => new Audit()); +App::setResource('mails', fn() => new Mail()); +App::setResource('deletes', fn() => new Delete()); +App::setResource('database', fn() => new EventDatabase()); +App::setResource('messaging', fn() => new Phone()); App::setResource('queue', function (Group $pools) { return $pools->get('queue')->pop()->getResource(); }, ['pools']); @@ -920,7 +917,7 @@ App::setResource('clients', function ($request, $console, $project) { fn ($node) => $node['hostname'], \array_filter( $console->getAttribute('platforms', []), - fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && isset($node['hostname']) && ! empty($node['hostname'])) + fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && isset($node['hostname']) && !empty($node['hostname'])) ) ); @@ -931,7 +928,7 @@ App::setResource('clients', function ($request, $console, $project) { fn ($node) => $node['hostname'], \array_filter( $project->getAttribute('platforms', []), - fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB || $node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) && isset($node['hostname']) && ! empty($node['hostname'])) + fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB || $node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) && isset($node['hostname']) && !empty($node['hostname'])) ) ) ) @@ -947,22 +944,23 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons /** @var Utopia\Database\Database $dbForProject */ /** @var Utopia\Database\Database $dbForConsole */ /** @var string $mode */ + Authorization::setDefaultStatus(true); - Auth::setCookieName('a_session_'.$project->getId()); + Auth::setCookieName('a_session_' . $project->getId()); $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; if (APP_MODE_ADMIN === $mode) { - Auth::setCookieName('a_session_'.$console->getId()); + Auth::setCookieName('a_session_' . $console->getId()); $authDuration = Auth::TOKEN_EXPIRATION_LOGIN_LONG; } $session = Auth::decodeSession( $request->getCookie( Auth::$cookieName, // Get sessions - $request->getCookie(Auth::$cookieName.'_legacy', '') + $request->getCookie(Auth::$cookieName . '_legacy', '') ) - ); // Get fallback session from old clients (no SameSite support) + );// Get fallback session from old clients (no SameSite support) // Get fallback session from clients who block 3rd-party cookies if ($response) { @@ -993,7 +991,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons if ( $user->isEmpty() // Check a document has been found in the DB - || ! Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) + || !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) ) { // Validate user has valid login token $user = new Document([]); } @@ -1008,13 +1006,13 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons $authJWT = $request->getHeader('x-appwrite-jwt', ''); - if (! empty($authJWT) && ! $project->isEmpty()) { // JWT authentication + if (!empty($authJWT) && !$project->isEmpty()) { // JWT authentication $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. try { $payload = $jwt->decode($authJWT); } catch (JWTException $error) { - throw new Exception(Exception::USER_JWT_INVALID, 'Failed to verify JWT. '.$error->getMessage()); + throw new Exception(Exception::USER_JWT_INVALID, 'Failed to verify JWT. ' . $error->getMessage()); } $jwtUserId = $payload['userId'] ?? ''; @@ -1036,13 +1034,14 @@ App::setResource('project', function ($dbForConsole, $request, $console) { /** @var Appwrite\Utopia\Request $request */ /** @var Utopia\Database\Database $dbForConsole */ /** @var Utopia\Database\Document $console */ + $projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', '')); if (empty($projectId) || $projectId === 'console') { return $console; } - $project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId)); + $project = Authorization::skip(fn() => $dbForConsole->getDocument('projects', $projectId)); return $project; }, ['dbForConsole', 'request', 'console']); @@ -1077,12 +1076,12 @@ App::setResource('console', function () { 'limit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, // 1 Year in seconds ], - 'authWhitelistEmails' => (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [], - 'authWhitelistIPs' => (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [], + 'authWhitelistEmails' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [], + 'authWhitelistIPs' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [], 'authProviders' => [ 'githubEnabled' => true, 'githubSecret' => App::getEnv('_APP_CONSOLE_GITHUB_SECRET', ''), - 'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', ''), + 'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', '') ], ]); }, []); @@ -1095,10 +1094,11 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole, $dbAdapter = $pools ->get($project->getAttribute('database')) ->pop() - ->getResource(); + ->getResource() + ; $database = new Database($dbAdapter, $cache); - $database->setNamespace('_'.$project->getInternalId()); + $database->setNamespace('_' . $project->getInternalId()); return $database; }, ['pools', 'dbForConsole', 'cache', 'project']); @@ -1107,7 +1107,8 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) { $dbAdapter = $pools ->get('console') ->pop() - ->getResource(); + ->getResource() + ; $database = new Database($dbAdapter, $cache); @@ -1124,7 +1125,8 @@ App::setResource('cache', function (Group $pools) { $adapters[] = $pools ->get($value) ->pop() - ->getResource(); + ->getResource() + ; } return new Cache(new Sharding($adapters)); @@ -1135,15 +1137,15 @@ App::setResource('deviceLocal', function () { }); App::setResource('deviceFiles', function ($project) { - return getDevice(APP_STORAGE_UPLOADS.'/app-'.$project->getId()); + return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId()); }, ['project']); App::setResource('deviceFunctions', function ($project) { - return getDevice(APP_STORAGE_FUNCTIONS.'/app-'.$project->getId()); + return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId()); }, ['project']); App::setResource('deviceBuilds', function ($project) { - return getDevice(APP_STORAGE_BUILDS.'/app-'.$project->getId()); + return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId()); }, ['project']); function getDevice($root): Device @@ -1165,7 +1167,7 @@ function getDevice($root): Device $bucket = $dsn->getPath(); $region = $dsn->getParam('region'); } catch (\Exception $e) { - Console::error($e->getMessage().'Invalid DSN. Defaulting to Local device.'); + Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); } switch ($device) { @@ -1238,6 +1240,7 @@ App::setResource('promiseAdapter', function ($register) { }, ['register']); App::setResource('schema', function ($utopia, $dbForProject) { + $complexity = function (int $complexity, array $args) { $queries = Query::parseQueries($args['queries'] ?? []); $query = Query::getByType($queries, [Query::TYPE_LIMIT])[0] ?? null; @@ -1247,7 +1250,7 @@ App::setResource('schema', function ($utopia, $dbForProject) { }; $attributes = function (int $limit, int $offset) use ($dbForProject) { - $attrs = Authorization::skip(fn () => $dbForProject->find('attributes', [ + $attrs = Authorization::skip(fn() => $dbForProject->find('attributes', [ Query::limit($limit), Query::offset($offset), ])); @@ -1277,7 +1280,7 @@ App::setResource('schema', function ($utopia, $dbForProject) { $params = [ 'list' => function (string $databaseId, string $collectionId, array $args) { - return ['queries' => $args['queries']]; + return [ 'queries' => $args['queries']]; }, 'create' => function (string $databaseId, string $collectionId, array $args) { $id = $args['id'] ?? 'unique()'; @@ -1325,21 +1328,18 @@ App::setResource('schema', function ($utopia, $dbForProject) { App::setResource('contributors', function () { $path = 'app/config/cloud/contributors.json'; $list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : []; - return $list; }, []); App::setResource('employees', function () { $path = 'app/config/cloud/employees.json'; $list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : []; - return $list; }, []); App::setResource('heroes', function () { $path = 'app/config/cloud/heroes.json'; $list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : []; - return $list; }, []); @@ -1347,13 +1347,12 @@ App::setResource('requestTimestamp', function ($request) { //TODO: Move this to the Request class itself $timestampHeader = $request->getHeader('x-appwrite-timestamp'); $requestTimestamp = null; - if (! empty($timestampHeader)) { + if (!empty($timestampHeader)) { try { $requestTimestamp = new \DateTime($timestampHeader); } catch (\Throwable $e) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid X-Appwrite-Timestamp header value'); } } - return $requestTimestamp; }, ['request']); diff --git a/app/preload.php b/app/preload.php index cec44d4a7d..e587bfaed5 100644 --- a/app/preload.php +++ b/app/preload.php @@ -5,36 +5,38 @@ * * Inializes both Appwrite API entry point, queue workers, and CLI tasks. * Set configuration, framework resources, app constants + * */ + ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); -if (file_exists(__DIR__.'/../vendor/autoload.php')) { - require __DIR__.'/../vendor/autoload.php'; +if (file_exists(__DIR__ . '/../vendor/autoload.php')) { + require __DIR__ . '/../vendor/autoload.php'; } use Utopia\Preloader\Preloader; -include __DIR__.'/controllers/general.php'; +include __DIR__ . '/controllers/general.php'; $preloader = new Preloader(); foreach ( [ - realpath(__DIR__.'/../vendor/composer'), - realpath(__DIR__.'/../vendor/amphp'), - realpath(__DIR__.'/../vendor/felixfbecker'), - realpath(__DIR__.'/../vendor/twig/twig'), - realpath(__DIR__.'/../vendor/guzzlehttp/guzzle'), - realpath(__DIR__.'/../vendor/slickdeals'), - realpath(__DIR__.'/../vendor/psr/log'), - realpath(__DIR__.'/../vendor/matomo'), - realpath(__DIR__.'/../vendor/symfony'), - realpath(__DIR__.'/../vendor/mongodb'), - realpath(__DIR__.'/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload - realpath(__DIR__.'/../vendor/utopia-php/cache'), // TODO: remove memcached autoload - realpath(__DIR__.'/../vendor/utopia-php/queue/src/Queue/Adapter/Workerman.php'), // TODO: remove workerman autoload + realpath(__DIR__ . '/../vendor/composer'), + realpath(__DIR__ . '/../vendor/amphp'), + realpath(__DIR__ . '/../vendor/felixfbecker'), + realpath(__DIR__ . '/../vendor/twig/twig'), + realpath(__DIR__ . '/../vendor/guzzlehttp/guzzle'), + realpath(__DIR__ . '/../vendor/slickdeals'), + realpath(__DIR__ . '/../vendor/psr/log'), + realpath(__DIR__ . '/../vendor/matomo'), + realpath(__DIR__ . '/../vendor/symfony'), + realpath(__DIR__ . '/../vendor/mongodb'), + realpath(__DIR__ . '/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload + realpath(__DIR__ . '/../vendor/utopia-php/cache'), // TODO: remove memcached autoload + realpath(__DIR__ . '/../vendor/utopia-php/queue/src/Queue/Adapter/Workerman.php'), // TODO: remove workerman autoload ] as $key => $value ) { if ($value !== false) { @@ -43,7 +45,7 @@ foreach ( } $preloader - ->paths(realpath(__DIR__.'/../app/config')) - ->paths(realpath(__DIR__.'/../app/controllers')) - ->paths(realpath(__DIR__.'/../src')) + ->paths(realpath(__DIR__ . '/../app/config')) + ->paths(realpath(__DIR__ . '/../app/controllers')) + ->paths(realpath(__DIR__ . '/../src')) ->load(); diff --git a/app/realtime.php b/app/realtime.php index 24def0ec61..772eee49d6 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -3,7 +3,6 @@ use Appwrite\Auth\Auth; use Appwrite\Messaging\Adapter\Realtime; use Appwrite\Network\Validator\Origin; -use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; @@ -13,22 +12,23 @@ use Swoole\Timer; use Utopia\Abuse\Abuse; use Utopia\Abuse\Adapters\TimeLimit; use Utopia\App; -use Utopia\Cache\Adapter\Sharding; -use Utopia\Cache\Cache; 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\Helpers\Role; +use Utopia\Logger\Log; +use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; -use Utopia\Logger\Log; -use Utopia\WebSocket\Adapter; +use Appwrite\Utopia\Request; +use Utopia\Cache\Adapter\Sharding; +use Utopia\Cache\Cache; +use Utopia\Config\Config; +use Utopia\Database\Database; use Utopia\WebSocket\Server; +use Utopia\WebSocket\Adapter; -require_once __DIR__.'/init.php'; +require_once __DIR__ . '/init.php'; Runtime::enableCoroutine(SWOOLE_HOOK_ALL); @@ -42,7 +42,8 @@ function getConsoleDB(): Database $dbAdapter = $pools ->get('console') ->pop() - ->getResource(); + ->getResource() + ; $database = new Database($dbAdapter, getCache()); @@ -65,10 +66,11 @@ function getProjectDB(Document $project): Database $dbAdapter = $pools ->get($project->getAttribute('database')) ->pop() - ->getResource(); + ->getResource() + ; $database = new Database($dbAdapter, getCache()); - $database->setNamespace('_'.$project->getInternalId()); + $database->setNamespace('_' . $project->getInternalId()); return $database; } @@ -78,6 +80,7 @@ function getCache(): Cache global $register; $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + $list = Config::getParam('pools-cache', []); $adapters = []; @@ -85,7 +88,8 @@ function getCache(): Cache $adapters[] = $pools ->get($value) ->pop() - ->getResource(); + ->getResource() + ; } return new Cache(new Sharding($adapters)); @@ -122,7 +126,7 @@ $logError = function (Throwable $error, string $action) use ($register) { $version = App::getEnv('_APP_VERSION', 'UNKNOWN'); $log = new Log(); - $log->setNamespace('realtime'); + $log->setNamespace("realtime"); $log->setServer(\gethostname()); $log->setVersion($version); $log->setType(Log::TYPE_ERROR); @@ -142,13 +146,13 @@ $logError = function (Throwable $error, string $action) use ($register) { $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); $responseCode = $logger->addLog($log); - Console::info('Realtime log pushed with status code: '.$responseCode); + Console::info('Realtime log pushed with status code: ' . $responseCode); } - Console::error('[Error] Type: '.get_class($error)); - Console::error('[Error] Message: '.$error->getMessage()); - Console::error('[Error] File: '.$error->getFile()); - Console::error('[Error] Line: '.$error->getLine()); + Console::error('[Error] Type: ' . get_class($error)); + Console::error('[Error] Message: ' . $error->getMessage()); + Console::error('[Error] File: ' . $error->getFile()); + Console::error('[Error] Line: ' . $error->getLine()); }; $server->error($logError); @@ -173,7 +177,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume '$permissions' => [], 'container' => $containerId, 'timestamp' => DateTime::now(), - 'value' => '{}', + 'value' => '{}' ]); $statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document)); @@ -207,7 +211,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument)); } catch (\Throwable $th) { - call_user_func($logError, $th, 'updateWorkerDocument'); + call_user_func($logError, $th, "updateWorkerDocument"); } finally { $register->get('pools')->reclaim(); } @@ -215,12 +219,12 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume }); $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime, $logError) { - Console::success('Worker '.$workerId.' started successfully'); + Console::success('Worker ' . $workerId . ' started successfully'); $attempts = 0; $start = time(); - Timer::tick(5000, function () use ($server, $register, $realtime, $stats) { + Timer::tick(5000, function () use ($server, $register, $realtime, $stats, $logError) { /** * Sending current connections to project channels on the console project every 5 seconds. */ @@ -239,34 +243,34 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, foreach ($list as $document) { foreach (json_decode($document->getAttribute('value')) as $projectId => $value) { if (array_key_exists($projectId, $payload)) { - $payload[$projectId] += $value; + $payload[$projectId] += $value; } else { - $payload[$projectId] = $value; + $payload[$projectId] = $value; } } } foreach ($stats as $projectId => $value) { - if (! array_key_exists($projectId, $payload)) { + if (!array_key_exists($projectId, $payload)) { continue; } $event = [ 'project' => 'console', - 'roles' => ['team:'.$stats->get($projectId, 'teamId')], + 'roles' => ['team:' . $stats->get($projectId, 'teamId')], 'data' => [ 'events' => ['stats.connections'], 'channels' => ['project'], 'timestamp' => DateTime::formatTz(DateTime::now()), 'payload' => [ - $projectId => $payload[$projectId], - ], - ], + $projectId => $payload[$projectId] + ] + ] ]; $server->send($realtime->getSubscribers($event), json_encode([ 'type' => 'event', - 'data' => $event['data'], + 'data' => $event['data'] ])); } @@ -285,13 +289,13 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, 'events' => ['test.event'], 'channels' => ['tests'], 'timestamp' => DateTime::formatTz(DateTime::now()), - 'payload' => $payload, - ], + 'payload' => $payload + ] ]; $server->send($realtime->getSubscribers($event), json_encode([ 'type' => 'event', - 'data' => $event['data'], + 'data' => $event['data'] ])); } }); @@ -299,8 +303,8 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, while ($attempts < 300) { try { if ($attempts > 0) { - Console::error('Pub/sub connection lost (lasted '.(time() - $start).' seconds, worker: '.$workerId.'). - Attempting restart in 5 seconds (attempt #'.$attempts.')'); + Console::error('Pub/sub connection lost (lasted ' . (time() - $start) . ' seconds, worker: ' . $workerId . '). + Attempting restart in 5 seconds (attempt #' . $attempts . ')'); sleep(5); // 5 sec delay between connection attempts } $start = time(); @@ -310,9 +314,9 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, if ($redis->ping(true)) { $attempts = 0; - Console::success('Pub/sub connection established (worker: '.$workerId.')'); + Console::success('Pub/sub connection established (worker: ' . $workerId . ')'); } else { - Console::error('Pub/sub failed (worker: '.$workerId.')'); + Console::error('Pub/sub failed (worker: ' . $workerId . ')'); } $redis->subscribe(['realtime'], function (Redis $redis, string $channel, string $payload) use ($server, $workerId, $stats, $register, $realtime) { @@ -322,10 +326,10 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $projectId = $event['project']; $userId = $event['userId']; - if ($realtime->hasSubscriber($projectId, 'user:'.$userId)) { - $connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:'.$userId])); + if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) { + $connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId])); $consoleDatabase = getConsoleDB(); - $project = Authorization::skip(fn () => $consoleDatabase->getDocument('projects', $projectId)); + $project = Authorization::skip(fn() => $consoleDatabase->getDocument('projects', $projectId)); $database = getProjectDB($project); $user = $database->getDocument('users', $userId); @@ -340,17 +344,17 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $receivers = $realtime->getSubscribers($event); - if (App::isDevelopment() && ! empty($receivers)) { - Console::log("[Debug][Worker {$workerId}] Receivers: ".count($receivers)); - Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: ".json_encode($receivers)); - Console::log("[Debug][Worker {$workerId}] Event: ".$payload); + if (App::isDevelopment() && !empty($receivers)) { + Console::log("[Debug][Worker {$workerId}] Receivers: " . count($receivers)); + Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: " . json_encode($receivers)); + Console::log("[Debug][Worker {$workerId}] Event: " . $payload); } $server->send( $receivers, json_encode([ 'type' => 'event', - 'data' => $event['data'], + 'data' => $event['data'] ]) ); @@ -359,12 +363,11 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, } }); } catch (\Throwable $th) { - call_user_func($logError, $th, 'pubSubConnection'); + call_user_func($logError, $th, "pubSubConnection"); - Console::error('Pub/sub error: '.$th->getMessage()); + Console::error('Pub/sub error: ' . $th->getMessage()); $attempts++; sleep(DATABASE_RECONNECT_SLEEP); - continue; } finally { $register->get('pools')->reclaim(); @@ -381,9 +384,9 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, Console::info("Connection open (user: {$connection})"); - App::setResource('pools', fn () => $register->get('pools')); - App::setResource('request', fn () => $request); - App::setResource('response', fn () => $response); + App::setResource('pools', fn() => $register->get('pools')); + App::setResource('request', fn() => $request); + App::setResource('response', fn() => $response); try { /** @var \Utopia\Database\Document $project */ @@ -424,7 +427,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, $origin = $request->getOrigin(); $originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', []))); - if (! $originValidator->isValid($origin) && $project->getId() !== 'console') { + if (!$originValidator->isValid($origin) && $project->getId() !== 'console') { throw new Exception($originValidator->getDescription(), 1008); } @@ -447,25 +450,25 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, 'type' => 'connected', 'data' => [ 'channels' => array_keys($channels), - 'user' => $user, - ], + 'user' => $user + ] ])); $stats->set($project->getId(), [ 'projectId' => $project->getId(), - 'teamId' => $project->getAttribute('teamId'), + 'teamId' => $project->getAttribute('teamId') ]); $stats->incr($project->getId(), 'connections'); $stats->incr($project->getId(), 'connectionsTotal'); } catch (\Throwable $th) { - call_user_func($logError, $th, 'initServer'); + call_user_func($logError, $th, "initServer"); $response = [ 'type' => 'error', 'data' => [ 'code' => $th->getCode(), - 'message' => $th->getMessage(), - ], + 'message' => $th->getMessage() + ] ]; $server->send([$connection], json_encode($response)); @@ -473,8 +476,8 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, if (App::isDevelopment()) { Console::error('[Error] Connection Error'); - Console::error('[Error] Code: '.$response['data']['code']); - Console::error('[Error] Message: '.$response['data']['message']); + Console::error('[Error] Code: ' . $response['data']['code']); + Console::error('[Error] Message: ' . $response['data']['message']); } } finally { $register->get('pools')->reclaim(); @@ -489,7 +492,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re $database = getConsoleDB(); if ($projectId !== 'console') { - $project = Authorization::skip(fn () => $database->getDocument('projects', $projectId)); + $project = Authorization::skip(fn() => $database->getDocument('projects', $projectId)); $database = getProjectDB($project); } @@ -512,16 +515,16 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re $message = json_decode($message, true); - if (is_null($message) || (! array_key_exists('type', $message) && ! array_key_exists('data', $message))) { + if (is_null($message) || (!array_key_exists('type', $message) && !array_key_exists('data', $message))) { throw new Exception('Message format is not valid.', 1003); } switch ($message['type']) { - /** + /** * This type is used to authenticate. */ case 'authentication': - if (! array_key_exists('session', $message['data'])) { + if (!array_key_exists('session', $message['data'])) { throw new Exception('Payload is not valid.', 1003); } @@ -534,7 +537,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re if ( empty($user->getId()) // Check a document has been found in the DB - || ! Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) // Validate user has valid login token + || !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) // Validate user has valid login token ) { // cookie not valid throw new Exception('Session is not valid.', 1003); @@ -550,8 +553,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re 'data' => [ 'to' => 'authentication', 'success' => true, - 'user' => $user, - ], + 'user' => $user + ] ])); break; @@ -564,8 +567,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re 'type' => 'error', 'data' => [ 'code' => $th->getCode(), - 'message' => $th->getMessage(), - ], + 'message' => $th->getMessage() + ] ]; $server->send([$connection], json_encode($response)); @@ -584,7 +587,7 @@ $server->onClose(function (int $connection) use ($realtime, $stats) { } $realtime->unsubscribe($connection); - Console::info('Connection close: '.$connection); + Console::info('Connection close: ' . $connection); }); $server->start(); diff --git a/app/worker.php b/app/worker.php index bd7cf7970d..ea086fa43d 100644 --- a/app/worker.php +++ b/app/worker.php @@ -1,6 +1,6 @@ $register); +Server::setResource('register', fn() => $register); Server::setResource('dbForConsole', function (Cache $cache, Registry $register) { $pools = $register->get('pools'); $database = $pools ->get('console') ->pop() - ->getResource(); + ->getResource() + ; $adapter = new Database($database, $cache); $adapter->setNamespace('console'); @@ -51,11 +52,11 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register, $database = $pools ->get($project->getAttribute('database')) ->pop() - ->getResource(); + ->getResource() + ; $adapter = new Database($database, $cache); - $adapter->setNamespace('_'.$project->getInternalId()); - + $adapter->setNamespace('_' . $project->getInternalId()); return $adapter; }, ['cache', 'register', 'message', 'dbForConsole']); @@ -68,7 +69,8 @@ Server::setResource('cache', function (Registry $register) { $adapters[] = $pools ->get($value) ->pop() - ->getResource(); + ->getResource() + ; } return new Cache(new Sharding($adapters)); @@ -76,7 +78,6 @@ Server::setResource('cache', function (Registry $register) { Server::setResource('queueForFunctions', function (Registry $register) { $pools = $register->get('pools'); - return new Func( $pools ->get('queue') @@ -87,7 +88,6 @@ Server::setResource('queueForFunctions', function (Registry $register) { Server::setResource('queueForUsage', function (Registry $register) { $pools = $register->get('pools'); - return new Usage( $pools ->get('queue') @@ -96,7 +96,7 @@ Server::setResource('queueForUsage', function (Registry $register) { ); }, ['register']); -Server::setResource('log', fn () => new Log()); +Server::setResource('log', fn() => new Log()); Server::setResource('logger', function ($register) { return $register->get('logger'); @@ -137,12 +137,12 @@ $server } if ($logger && ($error->getCode() >= 500 || $error->getCode() === 0)) { - $log->setNamespace('appwrite-worker'); + $log->setNamespace("appwrite-worker"); $log->setServer(\gethostname()); $log->setVersion($version); $log->setType(Log::TYPE_ERROR); $log->setMessage($error->getMessage()); - $log->setAction('appwrite-queue-'.App::getEnv('QUEUE')); + $log->setAction('appwrite-queue-' . App::getEnv('QUEUE')); $log->addTag('verboseType', get_class($error)); $log->addTag('code', $error->getCode()); $log->addExtra('file', $error->getFile()); @@ -155,11 +155,11 @@ $server $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); $responseCode = $logger->addLog($log); - Console::info('Usage stats log pushed with status code: '.$responseCode); + Console::info('Usage stats log pushed with status code: ' . $responseCode); } - Console::error('[Error] Type: '.get_class($error)); - Console::error('[Error] Message: '.$error->getMessage()); - Console::error('[Error] File: '.$error->getFile()); - Console::error('[Error] Line: '.$error->getLine()); + Console::error('[Error] Type: ' . get_class($error)); + Console::error('[Error] Message: ' . $error->getMessage()); + Console::error('[Error] File: ' . $error->getFile()); + Console::error('[Error] Line: ' . $error->getLine()); }); diff --git a/app/workers/audits.php b/app/workers/audits.php index a304fd70bb..8369ec74ec 100644 --- a/app/workers/audits.php +++ b/app/workers/audits.php @@ -5,16 +5,16 @@ use Utopia\Audit\Audit; use Utopia\CLI\Console; use Utopia\Database\Document; -require_once __DIR__.'/../init.php'; +require_once __DIR__ . '/../init.php'; Console::title('Audits V1 Worker'); -Console::success(APP_NAME.' audits worker v1 has started'); +Console::success(APP_NAME . ' audits worker v1 has started'); class AuditsV1 extends Worker { public function getName(): string { - return 'audits'; + return "audits"; } public function init(): void diff --git a/app/workers/builds.php b/app/workers/builds.php index 41c3cbdcc7..972eb5dd18 100644 --- a/app/workers/builds.php +++ b/app/workers/builds.php @@ -6,20 +6,20 @@ use Appwrite\Messaging\Adapter\Realtime; use Appwrite\Resque\Worker; use Appwrite\Utopia\Response\Model\Deployment; use Executor\Executor; +use Utopia\Database\DateTime; use Utopia\App; use Utopia\CLI\Console; -use Utopia\Config\Config; -use Utopia\Database\DateTime; -use Utopia\Database\Document; use Utopia\Database\Helpers\ID; -use Utopia\Database\Validator\Authorization; use Utopia\DSN\DSN; +use Utopia\Database\Document; +use Utopia\Config\Config; +use Utopia\Database\Validator\Authorization; use Utopia\Storage\Storage; -require_once __DIR__.'/../init.php'; +require_once __DIR__ . '/../init.php'; Console::title('Builds V1 Worker'); -Console::success(APP_NAME.' build worker v1 has started'); +Console::success(APP_NAME . ' build worker v1 has started'); // TODO: Executor should return appropriate response codes. class BuildsV1 extends Worker @@ -28,7 +28,7 @@ class BuildsV1 extends Worker public function getName(): string { - return 'builds'; + return "builds"; } public function init(): void @@ -46,7 +46,7 @@ class BuildsV1 extends Worker switch ($type) { case BUILD_TYPE_DEPLOYMENT: case BUILD_TYPE_RETRY: - Console::info('Creating build for deployment: '.$deployment->getId()); + Console::info('Creating build for deployment: ' . $deployment->getId()); $this->buildDeployment($project, $resource, $deployment); break; @@ -81,7 +81,7 @@ class BuildsV1 extends Worker $key = $function->getAttribute('runtime'); $runtime = isset($runtimes[$key]) ? $runtimes[$key] : null; if (\is_null($runtime)) { - throw new Exception('Runtime "'.$function->getAttribute('runtime', '').'" is not supported'); + throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); } $connection = App::getEnv('_APP_CONNECTIONS_STORAGE', ''); /** @TODO : move this to the registry or someplace else */ @@ -90,7 +90,7 @@ class BuildsV1 extends Worker $dsn = new DSN($connection); $device = $dsn->getScheme(); } catch (\Exception $e) { - Console::error($e->getMessage().'Invalid DSN. Defaulting to Local device.'); + Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); } $buildId = $deployment->getAttribute('buildId', ''); @@ -111,7 +111,7 @@ class BuildsV1 extends Worker 'stdout' => '', 'stderr' => '', 'endTime' => null, - 'duration' => 0, + 'duration' => 0 ])); $deployment->setAttribute('buildId', $build->getId()); $deployment->setAttribute('buildInternalId', $build->getInternalId()); @@ -150,7 +150,7 @@ class BuildsV1 extends Worker /** Trigger Realtime */ $allEvents = Event::generateEvents('functions.[functionId].deployments.[deploymentId].update', [ 'functionId' => $function->getId(), - 'deploymentId' => $deployment->getId(), + 'deploymentId' => $deployment->getId() ]); $target = Realtime::fromPayload( // Pass first, most verbose event pattern @@ -171,7 +171,6 @@ class BuildsV1 extends Worker $vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { $carry[$var->getAttribute('key')] = $var->getAttribute('value'); - return $carry; }, []); @@ -184,12 +183,12 @@ class BuildsV1 extends Worker remove: true, entrypoint: $deployment->getAttribute('entrypoint'), workdir: '/usr/code', - destination: APP_STORAGE_BUILDS."/app-{$project->getId()}", + destination: APP_STORAGE_BUILDS . "/app-{$project->getId()}", variables: $vars, commands: [ 'sh', '-c', 'tar -zxf /tmp/code.tar.gz -C /usr/code && \ - cd /usr/local/src/ && ./build.sh', + cd /usr/local/src/ && ./build.sh' ] ); @@ -223,7 +222,8 @@ class BuildsV1 extends Worker $schedule ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment'))); + ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); + Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); } catch (\Throwable $th) { @@ -261,11 +261,12 @@ class BuildsV1 extends Worker ->setProject($project) ->addMetric(METRIC_BUILDS, 1) // per project ->addMetric(METRIC_BUILDS_STORAGE, $build->getAttribute('size', 0)) - ->addMetric(METRIC_BUILDS_COMPUTE, (int) $build->getAttribute('duration', 0) * 1000) + ->addMetric(METRIC_BUILDS_COMPUTE, (int)$build->getAttribute('duration', 0) * 1000) ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS), 1) // per function ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE), $build->getAttribute('size', 0)) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int) $build->getAttribute('duration', 0) * 1000) - ->trigger(); + ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int)$build->getAttribute('duration', 0) * 1000) + ->trigger() + ; } public function shutdown(): void diff --git a/app/workers/certificates.php b/app/workers/certificates.php index fc72f6d4e6..824a296b75 100644 --- a/app/workers/certificates.php +++ b/app/workers/certificates.php @@ -7,17 +7,17 @@ use Appwrite\Template\Template; use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Database; -use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; use Utopia\Domains\Domain; use Utopia\Locale\Locale; -require_once __DIR__.'/../init.php'; +require_once __DIR__ . '/../init.php'; Console::title('Certificates V1 Worker'); -Console::success(APP_NAME.' certificates worker v1 has started'); +Console::success(APP_NAME . ' certificates worker v1 has started'); class CertificatesV1 extends Worker { @@ -30,7 +30,7 @@ class CertificatesV1 extends Worker public function getName(): string { - return 'certificates'; + return "certificates"; } public function init(): void @@ -68,6 +68,7 @@ class CertificatesV1 extends Worker * * Note: Renewals are checked and scheduled from maintenence worker */ + $this->dbForConsole = $this->getConsoleDB(); $skipCheck = $this->args['skipRenewCheck'] ?? false; // If true, we won't double-check expiry from cert file @@ -78,7 +79,7 @@ class CertificatesV1 extends Worker $certificate = $this->dbForConsole->findOne('certificates', [Query::equal('domain', [$domain->get()])]); // If we don't have certificate for domain yet, let's create new document. At the end we save it - if (! $certificate) { + if (!$certificate) { $certificate = new Document(); $certificate->setAttribute('domain', $domain->get()); } @@ -91,14 +92,14 @@ class CertificatesV1 extends Worker } // Validate domain and DNS records. Skip if job is forced - if (! $skipCheck) { + if (!$skipCheck) { $mainDomain = $this->getMainDomain(); - $isMainDomain = ! isset($mainDomain) || $domain->get() === $mainDomain; + $isMainDomain = !isset($mainDomain) || $domain->get() === $mainDomain; $this->validateDomain($domain, $isMainDomain); } // If certificate exists already, double-check expiry date. Skip if job is forced - if (! $skipCheck && ! $this->isRenewRequired($domain->get())) { + if (!$skipCheck && !$this->isRenewRequired($domain->get())) { throw new Exception('Renew isn\'t required.'); } @@ -151,15 +152,16 @@ class CertificatesV1 extends Worker /** * Save certificate data into database. * - * @param string $domain Domain name that certificate is for - * @param Document $certificate Certificate document that we need to save + * @param string $domain Domain name that certificate is for + * @param Document $certificate Certificate document that we need to save + * * @return void */ private function saveCertificateDocument(string $domain, Document $certificate): void { // Check if update or insert required $certificateDocument = $this->dbForConsole->findOne('certificates', [Query::equal('domain', [$domain])]); - if (! empty($certificateDocument) && ! $certificateDocument->isEmpty()) { + if (!empty($certificateDocument) && !$certificateDocument->isEmpty()) { // Merge new data with current data $certificate = new Document(\array_merge($certificateDocument->getArrayCopy(), $certificate->getArrayCopy())); @@ -180,7 +182,7 @@ class CertificatesV1 extends Worker private function getMainDomain(): ?string { $envDomain = App::getEnv('_APP_DOMAIN', ''); - if (! empty($envDomain) && $envDomain !== 'localhost') { + if (!empty($envDomain) && $envDomain !== 'localhost') { return $envDomain; } else { $domainDocument = $this->dbForConsole->findOne('domains', [Query::orderAsc('_id')]); @@ -197,8 +199,9 @@ class CertificatesV1 extends Worker * - Domain needs to be public and valid (prevents NFT domains that are not supported by Let's Encrypt) * - Domain must have proper DNS record * - * @param Domain $domain Domain which we validate - * @param bool $isMainDomain In case of master domain, we look for different DNS configurations + * @param Domain $domain Domain which we validate + * @param bool $isMainDomain In case of master domain, we look for different DNS configurations + * * @return void */ private function validateDomain(Domain $domain, bool $isMainDomain): void @@ -207,23 +210,23 @@ class CertificatesV1 extends Worker throw new Exception('Missing certificate domain.'); } - if (! $domain->isKnown() || $domain->isTest()) { + if (!$domain->isKnown() || $domain->isTest()) { throw new Exception('Unknown public suffix for domain.'); } - if (! $isMainDomain) { + if (!$isMainDomain) { // TODO: Would be awesome to also support A/AAAA records here. Maybe dry run? // Validate if domain target is properly configured $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); - if (! $target->isKnown() || $target->isTest()) { - throw new Exception('Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.'); + if (!$target->isKnown() || $target->isTest()) { + throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.'); } // Verify domain with DNS records $validator = new CNAME($target->get()); - if (! $validator->isValid($domain->get())) { + if (!$validator->isValid($domain->get())) { throw new Exception('Failed to verify domain DNS records.'); } } else { @@ -235,12 +238,13 @@ class CertificatesV1 extends Worker /** * Reads expiry date of certificate from file and decides if renewal is required or not. * - * @param string $domain Domain for which we check certificate file + * @param string $domain Domain for which we check certificate file + * * @return bool True, if certificate needs to be renewed */ private function isRenewRequired(string $domain): bool { - $certPath = APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem'; + $certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem'; if (\file_exists($certPath)) { $validTo = null; @@ -264,8 +268,9 @@ class CertificatesV1 extends Worker /** * LetsEncrypt communication to issue certificate (using certbot CLI) * - * @param string $folder Folder into which certificates should be generated - * @param string $domain Domain to generate certificate for + * @param string $folder Folder into which certificates should be generated + * @param string $domain Domain to generate certificate for + * * @return array Named array with keys 'stdout' and 'stderr', both string */ private function issueCertificate(string $folder, string $domain, string $email): array @@ -275,82 +280,83 @@ class CertificatesV1 extends Worker $staging = (App::isProduction()) ? '' : ' --dry-run'; $exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}" - .' --email '.$email - .' --cert-name '.$folder - .' -w '.APP_STORAGE_CERTIFICATES - ." -d {$domain}", '', $stdout, $stderr); + . " --email " . $email + . " --cert-name " . $folder + . " -w " . APP_STORAGE_CERTIFICATES + . " -d {$domain}", '', $stdout, $stderr); // Unexpected error, usually 5XX, API limits, ... if ($exit !== 0) { - throw new Exception('Failed to issue a certificate with message: '.$stderr); + throw new Exception('Failed to issue a certificate with message: ' . $stderr); } return [ 'stdout' => $stdout, - 'stderr' => $stderr, + 'stderr' => $stderr ]; } /** * Read new renew date from certificate file generated by Let's Encrypt * - * @param string $domain Domain which certificate was generated for + * @param string $domain Domain which certificate was generated for + * * @return string */ private function getRenewDate(string $domain): string { - $certPath = APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem'; + $certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem'; $certData = openssl_x509_parse(file_get_contents($certPath)); $validTo = $certData['validTo_time_t'] ?? null; $dt = (new \DateTime())->setTimestamp($validTo); - return DateTime::addSeconds($dt, -60 * 60 * 24 * 30); // -30 days } /** * Method to take files from Let's Encrypt, and put it into Traefik. * - * @param string $domain Domain which certificate was generated for - * @param string $folder Folder in which certificates were generated - * @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error + * @param string $domain Domain which certificate was generated for + * @param string $folder Folder in which certificates were generated + * @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error + * * @return void */ private function applyCertificateFiles(string $folder, string $domain, array $letsEncryptData): void { // Prepare folder in storage for domain - $path = APP_STORAGE_CERTIFICATES.'/'.$domain; - if (! \is_readable($path)) { - if (! \mkdir($path, 0755, true)) { + $path = APP_STORAGE_CERTIFICATES . '/' . $domain; + if (!\is_readable($path)) { + if (!\mkdir($path, 0755, true)) { throw new Exception('Failed to create path for certificate.'); } } // Move generated files - if (! @\rename('/etc/letsencrypt/live/'.$folder.'/cert.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem')) { - throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']); + if (!@\rename('/etc/letsencrypt/live/' . $folder . '/cert.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem')) { + throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']); } - if (! @\rename('/etc/letsencrypt/live/'.$folder.'/chain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/chain.pem')) { - throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']); + if (!@\rename('/etc/letsencrypt/live/' . $folder . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/chain.pem')) { + throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']); } - if (! @\rename('/etc/letsencrypt/live/'.$folder.'/fullchain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/fullchain.pem')) { - throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']); + if (!@\rename('/etc/letsencrypt/live/' . $folder . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/fullchain.pem')) { + throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']); } - if (! @\rename('/etc/letsencrypt/live/'.$folder.'/privkey.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/privkey.pem')) { - throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']); + if (!@\rename('/etc/letsencrypt/live/' . $folder . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/privkey.pem')) { + throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']); } $config = \implode(PHP_EOL, [ - 'tls:', - ' certificates:', + "tls:", + " certificates:", " - certFile: /storage/certificates/{$domain}/fullchain.pem", - " keyFile: /storage/certificates/{$domain}/privkey.pem", + " keyFile: /storage/certificates/{$domain}/privkey.pem" ]); // Save configuration into Traefik using our new cert files - if (! \file_put_contents(APP_STORAGE_CONFIG.'/'.$domain.'.yml', $config)) { + if (!\file_put_contents(APP_STORAGE_CONFIG . '/' . $domain . '.yml', $config)) { throw new Exception('Failed to save Traefik configuration.'); } } @@ -358,38 +364,39 @@ class CertificatesV1 extends Worker /** * Method to make sure information about error is delivered to admnistrator. * - * @param string $domain Domain that caused the error - * @param string $errorMessage Verbose error message - * @param int $attempt How many times it failed already + * @param string $domain Domain that caused the error + * @param string $errorMessage Verbose error message + * @param int $attempt How many times it failed already + * * @return void */ private function notifyError(string $domain, string $errorMessage, int $attempt): void { // Log error into console - Console::warning('Cannot renew domain ('.$domain.') on attempt no. '.$attempt.' certificate: '.$errorMessage); + Console::warning('Cannot renew domain (' . $domain . ') on attempt no. ' . $attempt . ' certificate: ' . $errorMessage); // Send mail to administratore mail $locale = new Locale(App::getEnv('_APP_LOCALE', 'en')); - if (! $locale->getText('emails.sender') || ! $locale->getText('emails.certificate.hello') || ! $locale->getText('emails.certificate.subject') || ! $locale->getText('emails.certificate.body') || ! $locale->getText('emails.certificate.footer') || ! $locale->getText('emails.certificate.thanks') || ! $locale->getText('emails.certificate.signature')) { + if (!$locale->getText('emails.sender') || !$locale->getText("emails.certificate.hello") || !$locale->getText("emails.certificate.subject") || !$locale->getText("emails.certificate.body") || !$locale->getText("emails.certificate.footer") || !$locale->getText("emails.certificate.thanks") || !$locale->getText("emails.certificate.signature")) { $locale->setDefault('en'); } - $body = Template::fromFile(__DIR__.'/../config/locale/templates/email-base.tpl'); + $body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl'); - $subject = \sprintf($locale->getText('emails.certificate.subject'), $domain); - $body->setParam('{{domain}}', $domain); - $body->setParam('{{error}}', $errorMessage); - $body->setParam('{{attempt}}', $attempt); + $subject = \sprintf($locale->getText("emails.certificate.subject"), $domain); + $body->setParam('{{domain}}', $domain); + $body->setParam('{{error}}', $errorMessage); + $body->setParam('{{attempt}}', $attempt); $body ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText('emails.certificate.hello')) - ->setParam('{{body}}', $locale->getText('emails.certificate.body')) - ->setParam('{{redirect}}', 'https://'.$domain) - ->setParam('{{footer}}', $locale->getText('emails.certificate.footer')) - ->setParam('{{thanks}}', $locale->getText('emails.certificate.thanks')) - ->setParam('{{signature}}', $locale->getText('emails.certificate.signature')) + ->setParam('{{hello}}', $locale->getText("emails.certificate.hello")) + ->setParam('{{body}}', $locale->getText("emails.certificate.body")) + ->setParam('{{redirect}}', 'https://' . $domain) + ->setParam('{{footer}}', $locale->getText("emails.certificate.footer")) + ->setParam('{{thanks}}', $locale->getText("emails.certificate.thanks")) + ->setParam('{{signature}}', $locale->getText("emails.certificate.signature")) ->setParam('{{project}}', 'Console') ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{bg-body}}', '#f7f7f7') @@ -411,8 +418,9 @@ class CertificatesV1 extends Worker * - when renew creates new document? It might? * - overall makes it more reliable * - * @param string $certificateId ID of a new or updated certificate document - * @param string $domain Domain that is affected by new certificate + * @param string $certificateId ID of a new or updated certificate document + * @param string $domain Domain that is affected by new certificate + * * @return void */ private function updateDomainDocuments(string $certificateId, string $domain): void diff --git a/app/workers/databases.php b/app/workers/databases.php index 6490c7a8d9..764f668f33 100644 --- a/app/workers/databases.php +++ b/app/workers/databases.php @@ -9,10 +9,10 @@ use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Exception as DatabaseException; -require_once __DIR__.'/../init.php'; +require_once __DIR__ . '/../init.php'; Console::title('Database V1 Worker'); -Console::success(APP_NAME.' database worker v1 has started'."\n"); +Console::success(APP_NAME . ' database worker v1 has started' . "\n"); class DatabaseV1 extends Worker { @@ -51,7 +51,7 @@ class DatabaseV1 extends Worker break; default: - Console::error('No database operation for type: '.$type); + Console::error('No database operation for type: ' . $type); break; } } @@ -61,10 +61,10 @@ class DatabaseV1 extends Worker } /** - * @param Document $database - * @param Document $collection - * @param Document $attribute - * @param Document $project + * @param Document $database + * @param Document $collection + * @param Document $attribute + * @param Document $project */ protected function createAttribute(Document $database, Document $collection, Document $attribute, Document $project): void { @@ -75,7 +75,7 @@ class DatabaseV1 extends Worker $events = Event::generateEvents('databases.[databaseId].collections.[collectionId].attributes.[attributeId].update', [ 'databaseId' => $database->getId(), 'collectionId' => $collection->getId(), - 'attributeId' => $attribute->getId(), + 'attributeId' => $attribute->getId() ]); /** * Fetch attribute from the database, since with Resque float values are loosing informations. @@ -99,15 +99,15 @@ class DatabaseV1 extends Worker try { switch ($type) { case Database::VAR_RELATIONSHIP: - $relatedCollection = $dbForProject->getDocument('database_'.$database->getInternalId(), $options['relatedCollection']); + $relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']); if ($relatedCollection->isEmpty()) { throw new DatabaseException('Collection not found'); } if ( - ! $dbForProject->createRelationship( - collection: 'database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), - relatedCollection: 'database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId(), + !$dbForProject->createRelationship( + collection: 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), + relatedCollection: 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), type: $options['relationType'], twoWay: $options['twoWay'], id: $key, @@ -119,12 +119,12 @@ class DatabaseV1 extends Worker } if ($options['twoWay']) { - $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$options['twoWayKey']); + $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']); $dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'available')); } break; default: - if (! $dbForProject->createAttribute('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) { + if (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) { throw new Exception('Failed to create Attribute'); } } @@ -170,24 +170,23 @@ class DatabaseV1 extends Worker options: [ 'projectId' => $projectId, 'databaseId' => $database->getId(), - 'collectionId' => $collection->getId(), + 'collectionId' => $collection->getId() ] ); } if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) { - $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $relatedCollection->getId()); + $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); } - $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId); + $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId); } /** - * @param Document $database - * @param Document $collection - * @param Document $attribute - * @param Document $project - * + * @param Document $database + * @param Document $collection + * @param Document $attribute + * @param Document $project * @throws Throwable */ protected function deleteAttribute(Document $database, Document $collection, Document $attribute, Document $project): void @@ -199,7 +198,7 @@ class DatabaseV1 extends Worker $events = Event::generateEvents('databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete', [ 'databaseId' => $database->getId(), 'collectionId' => $collection->getId(), - 'attributeId' => $attribute->getId(), + 'attributeId' => $attribute->getId() ]); $collectionId = $collection->getId(); $key = $attribute->getAttribute('key', ''); @@ -220,25 +219,25 @@ class DatabaseV1 extends Worker if ($status !== 'failed') { if ($type === Database::VAR_RELATIONSHIP) { if ($options['twoWay']) { - $relatedCollection = $dbForProject->getDocument('database_'.$database->getInternalId(), $options['relatedCollection']); + $relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']); if ($relatedCollection->isEmpty()) { throw new DatabaseException('Collection not found'); } - $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$options['twoWayKey']); + $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']); } - if (! $dbForProject->deleteRelationship('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) { + if (!$dbForProject->deleteRelationship('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { $dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'stuck')); throw new DatabaseException('Failed to delete Relationship'); } - } elseif (! $dbForProject->deleteAttribute('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) { + } elseif (!$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { throw new DatabaseException('Failed to delete Attribute'); } } $dbForProject->deleteDocument('attributes', $attribute->getId()); - if (! $relatedAttribute->isEmpty()) { + if (!$relatedAttribute->isEmpty()) { $dbForProject->deleteDocument('attributes', $relatedAttribute->getId()); } } catch (\Exception $e) { @@ -246,7 +245,7 @@ class DatabaseV1 extends Worker if ($e instanceof DatabaseException) { $attribute->setAttribute('error', $e->getMessage()); - if (! $relatedAttribute->isEmpty()) { + if (!$relatedAttribute->isEmpty()) { $relatedAttribute->setAttribute('error', $e->getMessage()); } } @@ -255,7 +254,7 @@ class DatabaseV1 extends Worker $attribute->getId(), $attribute->setAttribute('status', 'stuck') ); - if (! $relatedAttribute->isEmpty()) { + if (!$relatedAttribute->isEmpty()) { $dbForProject->updateDocument( 'attributes', $relatedAttribute->getId(), @@ -279,7 +278,7 @@ class DatabaseV1 extends Worker options: [ 'projectId' => $projectId, 'databaseId' => $database->getId(), - 'collectionId' => $collection->getId(), + 'collectionId' => $collection->getId() ] ); } @@ -335,21 +334,20 @@ class DatabaseV1 extends Worker } } - $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId); - $dbForProject->deleteCachedCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId()); + $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId); + $dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId()); - if (! $relatedCollection->isEmpty() && ! $relatedAttribute->isEmpty()) { - $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $relatedCollection->getId()); - $dbForProject->deleteCachedCollection('database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId()); + if (!$relatedCollection->isEmpty() && !$relatedAttribute->isEmpty()) { + $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); + $dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); } } /** - * @param Document $database - * @param Document $collection - * @param Document $index - * @param Document $project - * + * @param Document $database + * @param Document $collection + * @param Document $index + * @param Document $project * @throws \Exception */ protected function createIndex(Document $database, Document $collection, Document $index, Document $project): void @@ -361,7 +359,7 @@ class DatabaseV1 extends Worker $events = Event::generateEvents('databases.[databaseId].collections.[collectionId].indexes.[indexId].update', [ 'databaseId' => $database->getId(), 'collectionId' => $collection->getId(), - 'indexId' => $index->getId(), + 'indexId' => $index->getId() ]); $collectionId = $collection->getId(); $key = $index->getAttribute('key', ''); @@ -372,7 +370,7 @@ class DatabaseV1 extends Worker $project = $dbForConsole->getDocument('projects', $projectId); try { - if (! $dbForProject->createIndex('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) { + if (!$dbForProject->createIndex('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) { throw new DatabaseException('Failed to create Index'); } $dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available')); @@ -404,19 +402,19 @@ class DatabaseV1 extends Worker options: [ 'projectId' => $projectId, 'databaseId' => $database->getId(), - 'collectionId' => $collection->getId(), + 'collectionId' => $collection->getId() ] ); } - $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId); + $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId); } /** - * @param Document $database - * @param Document $collection - * @param Document $index - * @param Document $project + * @param Document $database + * @param Document $collection + * @param Document $index + * @param Document $project */ protected function deleteIndex(Document $database, Document $collection, Document $index, Document $project): void { @@ -427,14 +425,14 @@ class DatabaseV1 extends Worker $events = Event::generateEvents('databases.[databaseId].collections.[collectionId].indexes.[indexId].delete', [ 'databaseId' => $database->getId(), 'collectionId' => $collection->getId(), - 'indexId' => $index->getId(), + 'indexId' => $index->getId() ]); $key = $index->getAttribute('key'); $status = $index->getAttribute('status', ''); $project = $dbForConsole->getDocument('projects', $projectId); try { - if ($status !== 'failed' && ! $dbForProject->deleteIndex('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) { + if ($status !== 'failed' && !$dbForProject->deleteIndex('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { throw new DatabaseException('Failed to delete index'); } $dbForProject->deleteDocument('indexes', $index->getId()); @@ -466,11 +464,11 @@ class DatabaseV1 extends Worker options: [ 'projectId' => $projectId, 'databaseId' => $database->getId(), - 'collectionId' => $collection->getId(), + 'collectionId' => $collection->getId() ] ); } - $dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collection->getId()); + $dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collection->getId()); } } diff --git a/app/workers/deletes.php b/app/workers/deletes.php index 7d276f22cf..7f426bf4f4 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -1,29 +1,29 @@ deleteCollection($document, $project); break; } - Console::error('No lazy delete operation available for document of type: '.$document->getCollection()); + Console::error('No lazy delete operation available for document of type: ' . $document->getCollection()); break; } break; @@ -82,14 +82,14 @@ class DeletesV1 extends Worker case DELETE_TYPE_AUDIT: $datetime = $this->args['datetime'] ?? null; - if (! empty($datetime)) { + if (!empty($datetime)) { $this->deleteAuditLogs($datetime); } $document = new Document($this->args['document'] ?? []); - if (! $document->isEmpty()) { - $this->deleteAuditLogsByResource('document/'.$document->getId(), $project); + if (!$document->isEmpty()) { + $this->deleteAuditLogsByResource('document/' . $document->getId(), $project); } break; @@ -125,7 +125,7 @@ class DeletesV1 extends Worker $this->deleteSchedules($this->args['datetime']); break; default: - Console::error('No delete operation for type: '.$type); + Console::error('No delete operation for type: ' . $type); break; } } @@ -153,8 +153,7 @@ class DeletesV1 extends Worker if ($project->isEmpty()) { $this->getConsoleDB()->deleteDocument('schedules', $document->getId()); - Console::success('Deleted schedule for deleted project '.$document->getAttribute('projectId')); - + Console::success('Deleted schedule for deleted project ' . $document->getAttribute('projectId')); return; } @@ -162,16 +161,15 @@ class DeletesV1 extends Worker if ($function->isEmpty()) { $this->getConsoleDB()->deleteDocument('schedules', $document->getId()); - Console::success('Deleted schedule for function '.$document->getAttribute('resourceId')); + Console::success('Deleted schedule for function ' . $document->getAttribute('resourceId')); } } ); } /** - * @param Document $project - * @param string $resource - * + * @param Document $project + * @param string $resource * @throws Exception */ protected function deleteCacheByResource(Document $project, string $resource): void @@ -182,19 +180,19 @@ class DeletesV1 extends Worker if ($document) { $cache = new Cache( - new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId) + new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId) ); $this->deleteById( $document, $dbForProject, function ($document) use ($cache, $projectId) { - $path = APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId.DIRECTORY_SEPARATOR.$document->getId(); + $path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId(); if ($cache->purge($document->getId())) { - Console::success('Deleting cache file: '.$path); + Console::success('Deleting cache file: ' . $path); } else { - Console::error('Failed to delete cache file: '.$path); + Console::error('Failed to delete cache file: ' . $path); } } ); @@ -202,8 +200,7 @@ class DeletesV1 extends Worker } /** - * @param string $datetime - * + * @param string $datetime * @throws Exception */ protected function deleteCacheByDate(string $datetime): void @@ -212,7 +209,7 @@ class DeletesV1 extends Worker $projectId = $project->getId(); $dbForProject = $this->getProjectDB($project); $cache = new Cache( - new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId) + new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId) ); $query = [ @@ -224,21 +221,22 @@ class DeletesV1 extends Worker $query, $dbForProject, function (Document $document) use ($cache, $projectId) { - $path = APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId.DIRECTORY_SEPARATOR.$document->getId(); + $path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId(); if ($cache->purge($document->getId())) { - Console::success('Deleting cache file: '.$path); + Console::success('Deleting cache file: ' . $path); } else { - Console::error('Failed to delete cache file: '.$path); + Console::error('Failed to delete cache file: ' . $path); } } ); }); } + /** - * @param Document $document database document - * @param Document $project + * @param Document $document database document + * @param Document $project */ protected function deleteDatabase(Document $document, Document $project): void { @@ -247,18 +245,18 @@ class DeletesV1 extends Worker $dbForProject = $this->getProjectDB($project); - $this->deleteByGroup('database_'.$document->getInternalId(), [], $dbForProject, function ($document) use ($project) { + $this->deleteByGroup('database_' . $document->getInternalId(), [], $dbForProject, function ($document) use ($project) { $this->deleteCollection($document, $project); }); - $dbForProject->deleteCollection('database_'.$document->getInternalId()); + $dbForProject->deleteCollection('database_' . $document->getInternalId()); - $this->deleteAuditLogsByResource('database/'.$databaseId, $project); + $this->deleteAuditLogsByResource('database/' . $databaseId, $project); } /** - * @param Document $document teams document - * @param Document $project + * @param Document $document teams document + * @param Document $project */ protected function deleteCollection(Document $document, Document $project): void { @@ -275,33 +273,32 @@ class DeletesV1 extends Worker ); foreach ($relationships as $relationship) { - if (! $relationship['twoWay']) { + if (!$relationship['twoWay']) { continue; } - $relatedCollection = $dbForProject->getDocument('database_'.$databaseInternalId, $relationship['relatedCollection']); - $dbForProject->deleteDocument('attributes', $databaseInternalId.'_'.$relatedCollection->getInternalId().'_'.$relationship['twoWayKey']); - $dbForProject->deleteCachedDocument('database_'.$databaseInternalId, $relatedCollection->getId()); - $dbForProject->deleteCachedCollection('database_'.$databaseInternalId.'_collection_'.$relatedCollection->getInternalId()); + $relatedCollection = $dbForProject->getDocument('database_' . $databaseInternalId, $relationship['relatedCollection']); + $dbForProject->deleteDocument('attributes', $databaseInternalId . '_' . $relatedCollection->getInternalId() . '_' . $relationship['twoWayKey']); + $dbForProject->deleteCachedDocument('database_' . $databaseInternalId, $relatedCollection->getId()); + $dbForProject->deleteCachedCollection('database_' . $databaseInternalId . '_collection_' . $relatedCollection->getInternalId()); } - $dbForProject->deleteCollection('database_'.$databaseInternalId.'_collection_'.$document->getInternalId()); + $dbForProject->deleteCollection('database_' . $databaseInternalId . '_collection_' . $document->getInternalId()); $this->deleteByGroup('attributes', [ Query::equal('databaseInternalId', [$databaseInternalId]), - Query::equal('collectionInternalId', [$collectionInternalId]), + Query::equal('collectionInternalId', [$collectionInternalId]) ], $dbForProject); $this->deleteByGroup('indexes', [ Query::equal('databaseInternalId', [$databaseInternalId]), - Query::equal('collectionInternalId', [$collectionInternalId]), + Query::equal('collectionInternalId', [$collectionInternalId]) ], $dbForProject); - $this->deleteAuditLogsByResource('database/'.$databaseId.'/collection/'.$collectionId, $project); + $this->deleteAuditLogsByResource('database/' . $databaseId . '/collection/' . $collectionId, $project); } /** - * @param string $hourlyUsageRetentionDatetime - * + * @param string $hourlyUsageRetentionDatetime * @throws Exception */ protected function deleteUsageStats(string $hourlyUsageRetentionDatetime) @@ -317,8 +314,8 @@ class DeletesV1 extends Worker } /** - * @param Document $document teams document - * @param Document $project + * @param Document $document teams document + * @param Document $project */ protected function deleteMemberships(Document $document, Document $project): void { @@ -329,7 +326,7 @@ class DeletesV1 extends Worker $this->deleteByGroup( 'memberships', [ - Query::equal('teamInternalId', [$teamInternalId]), + Query::equal('teamInternalId', [$teamInternalId]) ], $dbForProject, function (Document $membership) use ($dbForProject) { @@ -340,9 +337,8 @@ class DeletesV1 extends Worker } /** - * @param \Utopia\Database\Document $document + * @param \Utopia\Database\Document $document * @return void - * * @throws \Exception */ protected function deleteProjectsByTeam(Document $document): void @@ -350,7 +346,7 @@ class DeletesV1 extends Worker $dbForConsole = $this->getConsoleDB(); $projects = $dbForConsole->find('projects', [ - Query::equal('teamInternalId', [$document->getInternalId()]), + Query::equal('teamInternalId', [$document->getInternalId()]) ]); foreach ($projects as $project) { @@ -360,8 +356,7 @@ class DeletesV1 extends Worker } /** - * @param Document $document project document - * + * @param Document $document project document * @throws Exception */ protected function deleteProject(Document $document): void @@ -373,7 +368,7 @@ class DeletesV1 extends Worker $dbForConsole = $this->getConsoleDB(); $domains = $dbForConsole->find('domains', [ - Query::equal('projectInternalId', [$projectInternalId]), + Query::equal('projectInternalId', [$projectInternalId]) ]); foreach ($domains as $domain) { @@ -397,22 +392,22 @@ class DeletesV1 extends Worker // Delete Platforms $this->deleteByGroup('platforms', [ - Query::equal('projectInternalId', [$projectInternalId]), + Query::equal('projectInternalId', [$projectInternalId]) ], $dbForConsole); // Delete Domains $this->deleteByGroup('domains', [ - Query::equal('projectInternalId', [$projectInternalId]), + Query::equal('projectInternalId', [$projectInternalId]) ], $dbForConsole); // Delete Keys $this->deleteByGroup('keys', [ - Query::equal('projectInternalId', [$projectInternalId]), + Query::equal('projectInternalId', [$projectInternalId]) ], $dbForConsole); // Delete Webhooks $this->deleteByGroup('webhooks', [ - Query::equal('projectInternalId', [$projectInternalId]), + Query::equal('projectInternalId', [$projectInternalId]) ], $dbForConsole); // Delete metadata tables @@ -436,8 +431,8 @@ class DeletesV1 extends Worker } /** - * @param Document $document user document - * @param Document $project + * @param Document $document user document + * @param Document $project */ protected function deleteUser(Document $document, Document $project): void { @@ -448,19 +443,19 @@ class DeletesV1 extends Worker // Delete all sessions of this user from the sessions table and update the sessions field of the user record $this->deleteByGroup('sessions', [ - Query::equal('userInternalId', [$userInternalId]), + Query::equal('userInternalId', [$userInternalId]) ], $dbForProject); $dbForProject->deleteCachedDocument('users', $userId); // Delete Memberships and decrement team membership counts $this->deleteByGroup('memberships', [ - Query::equal('userInternalId', [$userInternalId]), + Query::equal('userInternalId', [$userInternalId]) ], $dbForProject, function (Document $document) use ($dbForProject) { if ($document->getAttribute('confirm')) { // Count only confirmed members $teamId = $document->getAttribute('teamId'); $team = $dbForProject->getDocument('teams', $teamId); - if (! $team->isEmpty()) { + if (!$team->isEmpty()) { $team = $dbForProject->updateDocument( 'teams', $teamId, @@ -473,18 +468,17 @@ class DeletesV1 extends Worker // Delete tokens $this->deleteByGroup('tokens', [ - Query::equal('userInternalId', [$userInternalId]), + Query::equal('userInternalId', [$userInternalId]) ], $dbForProject); // Delete identities $this->deleteByGroup('identities', [ - Query::equal('userInternalId', [$userInternalId]), + Query::equal('userInternalId', [$userInternalId]) ], $dbForProject); } /** - * @param string $datetime - * + * @param string $datetime * @throws Exception */ protected function deleteExecutionLogs(string $datetime): void @@ -493,7 +487,7 @@ class DeletesV1 extends Worker $dbForProject = $this->getProjectDB($project); // Delete Executions $this->deleteByGroup('executions', [ - Query::lessThan('$createdAt', $datetime), + Query::lessThan('$createdAt', $datetime) ], $dbForProject); }); } @@ -511,14 +505,13 @@ class DeletesV1 extends Worker // Delete Sessions $this->deleteByGroup('sessions', [ - Query::lessThan('$createdAt', $expired), + Query::lessThan('$createdAt', $expired) ], $dbForProject); }); } /** - * @param string $datetime - * + * @param string $datetime * @throws Exception */ protected function deleteRealtimeUsage(string $datetime): void @@ -527,14 +520,13 @@ class DeletesV1 extends Worker $dbForProject = $this->getProjectDB($project); // Delete Dead Realtime Logs $this->deleteByGroup('realtime', [ - Query::lessThan('timestamp', $datetime), + Query::lessThan('timestamp', $datetime) ], $dbForProject); }); } /** - * @param string $datetime - * + * @param string $datetime * @throws Exception */ protected function deleteAbuseLogs(string $datetime): void @@ -546,18 +538,17 @@ class DeletesV1 extends Worker $this->deleteForProjectIds(function (Document $project) use ($datetime) { $projectId = $project->getId(); $dbForProject = $this->getProjectDB($project); - $timeLimit = new TimeLimit('', 0, 1, $dbForProject); + $timeLimit = new TimeLimit("", 0, 1, $dbForProject); $abuse = new Abuse($timeLimit); $status = $abuse->cleanup($datetime); - if (! $status) { - throw new Exception('Failed to delete Abuse logs for project '.$projectId); + if (!$status) { + throw new Exception('Failed to delete Abuse logs for project ' . $projectId); } }); } /** - * @param string $datetime - * + * @param string $datetime * @throws Exception */ protected function deleteAuditLogs(string $datetime): void @@ -571,28 +562,28 @@ class DeletesV1 extends Worker $dbForProject = $this->getProjectDB($project); $audit = new Audit($dbForProject); $status = $audit->cleanup($datetime); - if (! $status) { - throw new Exception('Failed to delete Audit logs for project'.$projectId); + if (!$status) { + throw new Exception('Failed to delete Audit logs for project' . $projectId); } }); } /** - * @param string $resource - * @param Document $project + * @param string $resource + * @param Document $project */ protected function deleteAuditLogsByResource(string $resource, Document $project): void { $dbForProject = $this->getProjectDB($project); $this->deleteByGroup(Audit::COLLECTION, [ - Query::equal('resource', [$resource]), + Query::equal('resource', [$resource]) ], $dbForProject); } /** - * @param Document $document function document - * @param Document $project + * @param Document $document function document + * @param Document $project */ protected function deleteFunction(Document $document, Document $project): void { @@ -604,41 +595,41 @@ class DeletesV1 extends Worker /** * Delete Variables */ - Console::info('Deleting variables for function '.$functionId); + Console::info("Deleting variables for function " . $functionId); $this->deleteByGroup('variables', [ - Query::equal('functionInternalId', [$functionInternalId]), + Query::equal('functionInternalId', [$functionInternalId]) ], $dbForProject); /** * Delete Deployments */ - Console::info('Deleting deployments for function '.$functionId); + Console::info("Deleting deployments for function " . $functionId); $storageFunctions = $this->getFunctionsDevice($projectId); $deploymentIds = []; $this->deleteByGroup('deployments', [ - Query::equal('resourceId', [$functionId]), + Query::equal('resourceId', [$functionId]) ], $dbForProject, function (Document $document) use ($storageFunctions, &$deploymentIds) { $deploymentIds[] = $document->getId(); if ($storageFunctions->delete($document->getAttribute('path', ''), true)) { - Console::success('Deleted deployment files: '.$document->getAttribute('path', '')); + Console::success('Deleted deployment files: ' . $document->getAttribute('path', '')); } else { - Console::error('Failed to delete deployment files: '.$document->getAttribute('path', '')); + Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', '')); } }); /** * Delete builds */ - Console::info('Deleting builds for function '.$functionId); + Console::info("Deleting builds for function " . $functionId); $storageBuilds = $this->getBuildsDevice($projectId); foreach ($deploymentIds as $deploymentId) { $this->deleteByGroup('builds', [ - Query::equal('deploymentId', [$deploymentId]), - ], $dbForProject, function (Document $document) use ($storageBuilds) { + Query::equal('deploymentId', [$deploymentId]) + ], $dbForProject, function (Document $document) use ($storageBuilds, $deploymentId) { if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) { - Console::success('Deleted build files: '.$document->getAttribute('outputPath', '')); + Console::success('Deleted build files: ' . $document->getAttribute('outputPath', '')); } else { - Console::error('Failed to delete build files: '.$document->getAttribute('outputPath', '')); + Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', '')); } }); } @@ -646,17 +637,17 @@ class DeletesV1 extends Worker /** * Delete Executions */ - Console::info('Deleting executions for function '.$functionId); + Console::info("Deleting executions for function " . $functionId); $this->deleteByGroup('executions', [ - Query::equal('functionId', [$functionId]), + Query::equal('functionId', [$functionId]) ], $dbForProject); // TODO: Request executor to delete runtime } /** - * @param Document $document deployment document - * @param Document $project + * @param Document $document deployment document + * @param Document $project */ protected function deleteDeployment(Document $document, Document $project): void { @@ -668,44 +659,45 @@ class DeletesV1 extends Worker /** * Delete deployment files */ - Console::info('Deleting deployment files for deployment '.$deploymentId); + Console::info("Deleting deployment files for deployment " . $deploymentId); $storageFunctions = $this->getFunctionsDevice($projectId); if ($storageFunctions->delete($document->getAttribute('path', ''), true)) { - Console::success('Deleted deployment files: '.$document->getAttribute('path', '')); + Console::success('Deleted deployment files: ' . $document->getAttribute('path', '')); } else { - Console::error('Failed to delete deployment files: '.$document->getAttribute('path', '')); + Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', '')); } /** * Delete builds */ - Console::info('Deleting builds for deployment '.$deploymentId); + Console::info("Deleting builds for deployment " . $deploymentId); $storageBuilds = $this->getBuildsDevice($projectId); $this->deleteByGroup('builds', [ - Query::equal('deploymentId', [$deploymentId]), + Query::equal('deploymentId', [$deploymentId]) ], $dbForProject, function (Document $document) use ($storageBuilds) { if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) { - Console::success('Deleted build files: '.$document->getAttribute('outputPath', '')); + Console::success('Deleted build files: ' . $document->getAttribute('outputPath', '')); } else { - Console::error('Failed to delete build files: '.$document->getAttribute('outputPath', '')); + Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', '')); } }); // TODO: Request executor to delete runtime } + /** - * @param Document $document to be deleted - * @param Database $database to delete it from - * @param callable|null $callback to perform after document is deleted - * @return bool + * @param Document $document to be deleted + * @param Database $database to delete it from + * @param callable|null $callback to perform after document is deleted * + * @return bool * @throws \Utopia\Database\Exception\Authorization */ protected function deleteById(Document $document, Database $database, callable $callback = null): bool { if ($database->deleteDocument($document->getCollection(), $document->getId())) { - Console::success('Deleted document "'.$document->getId().'" successfully'); + Console::success('Deleted document "' . $document->getId() . '" successfully'); if (is_callable($callback)) { $callback($document); @@ -713,15 +705,13 @@ class DeletesV1 extends Worker return true; } else { - Console::error('Failed to delete document: '.$document->getId()); - + Console::error('Failed to delete document: ' . $document->getId()); return false; } } /** - * @param callable $callback - * + * @param callable $callback * @throws Exception */ protected function deleteForProjectIds(callable $callback): void @@ -743,7 +733,7 @@ class DeletesV1 extends Worker /** @var string[] $projectIds */ $sum = count($projects); - Console::info('Executing delete function for chunk #'.$chunk.'. Found '.$sum.' projects'); + Console::info('Executing delete function for chunk #' . $chunk . '. Found ' . $sum . ' projects'); foreach ($projects as $project) { $callback($project); $count++; @@ -751,15 +741,14 @@ class DeletesV1 extends Worker } $executionEnd = \microtime(true); - Console::info("Found {$count} projects ".($executionEnd - $executionStart).' seconds'); + Console::info("Found {$count} projects " . ($executionEnd - $executionStart) . " seconds"); } /** - * @param string $collection collectionID - * @param array $queries - * @param Database $database - * @param callable|null $callback - * + * @param string $collection collectionID + * @param array $queries + * @param Database $database + * @param callable|null $callback * @throws Exception */ protected function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null): void @@ -780,7 +769,7 @@ class DeletesV1 extends Worker $sum = count($results); - Console::info('Deleting chunk #'.$chunk.'. Found '.$sum.' documents in collection '.$database->getNamespace().'_'.$collection); + Console::info('Deleting chunk #' . $chunk . '. Found ' . $sum . ' documents in collection ' . $database->getNamespace() . '_' . $collection); foreach ($results as $document) { $this->deleteById($document, $database, $callback); @@ -793,14 +782,14 @@ class DeletesV1 extends Worker $executionEnd = \microtime(true); - Console::info("Deleted {$count} document by group in ".($executionEnd - $executionStart).' seconds'); + Console::info("Deleted {$count} document by group in " . ($executionEnd - $executionStart) . " seconds"); } /** - * @param string $collection collectionID - * @param Query[] $queries - * @param Database $database - * @param callable $callback + * @param string $collection collectionID + * @param Query[] $queries + * @param Database $database + * @param callable $callback */ protected function listByGroup(string $collection, array $queries, Database $database, callable $callback = null): void { @@ -840,12 +829,11 @@ class DeletesV1 extends Worker $executionEnd = \microtime(true); - Console::info("Listed {$count} document by group in ".($executionEnd - $executionStart).' seconds'); + Console::info("Listed {$count} document by group in " . ($executionEnd - $executionStart) . " seconds"); } /** - * @param Document $document certificates document - * + * @param Document $document certificates document * @throws \Utopia\Database\Exception\Authorization */ protected function deleteCertificates(Document $document): void @@ -855,10 +843,10 @@ class DeletesV1 extends Worker // If domain has certificate generated if (isset($document['certificateId'])) { $domainUsingCertificate = $consoleDB->findOne('domains', [ - Query::equal('certificateId', [$document['certificateId']]), + Query::equal('certificateId', [$document['certificateId']]) ]); - if (! $domainUsingCertificate) { + if (!$domainUsingCertificate) { $mainDomain = App::getEnv('_APP_DOMAIN_TARGET', ''); if ($mainDomain === $document->getAttribute('domain')) { $domainUsingCertificate = $mainDomain; @@ -868,14 +856,13 @@ class DeletesV1 extends Worker // If certificate is still used by some domain, mark we can't delete. // Current domain should not be found, because we only have copy. Original domain is already deleted from database. if ($domainUsingCertificate) { - Console::warning('Skipping certificate deletion, because a domain is still using it.'); - + Console::warning("Skipping certificate deletion, because a domain is still using it."); return; } } $domain = $document->getAttribute('domain'); - $directory = APP_STORAGE_CERTIFICATES.'/'.$domain; + $directory = APP_STORAGE_CERTIFICATES . '/' . $domain; $checkTraversal = realpath($directory) === $directory; if ($domain && $checkTraversal && is_dir($directory)) { @@ -885,7 +872,7 @@ class DeletesV1 extends Worker } // Delete files, so Traefik is aware of change - array_map('unlink', glob($directory.'/*.*')); + array_map('unlink', glob($directory . '/*.*')); rmdir($directory); Console::info("Deleted certificate files for {$domain}"); } else { @@ -897,7 +884,7 @@ class DeletesV1 extends Worker { $projectId = $project->getId(); $dbForProject = $this->getProjectDB($project); - $dbForProject->deleteCollection('bucket_'.$document->getInternalId()); + $dbForProject->deleteCollection('bucket_' . $document->getInternalId()); $device = $this->getFilesDevice($projectId); diff --git a/app/workers/functions.php b/app/workers/functions.php index d5aab70534..7dec0ce90c 100644 --- a/app/workers/functions.php +++ b/app/workers/functions.php @@ -1,10 +1,11 @@ getAttribute('runtime'), $runtimes)) { - throw new Exception('Runtime "'.$function->getAttribute('runtime', '').'" is not supported'); + if (!\array_key_exists($function->getAttribute('runtime'), $runtimes)) { + throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); } $runtime = $runtimes[$function->getAttribute('runtime')]; @@ -109,6 +109,7 @@ Server::setResource('execute', function () { /** * Usage */ + $queueForUsage ->addMetric(METRIC_EXECUTIONS, 1) // per project ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1); // per function @@ -119,7 +120,6 @@ Server::setResource('execute', function () { $vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { $carry[$var->getAttribute('key')] = $var->getAttribute('value'); - return $carry; }, []); @@ -164,7 +164,7 @@ Server::setResource('execute', function () { } catch (\Throwable $th) { $interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt())); $execution - ->setAttribute('duration', (float) $interval->format('%s.%f')) + ->setAttribute('duration', (float)$interval->format('%s.%f')) ->setAttribute('status', 'failed') ->setAttribute('statusCode', $th->getCode()) ->setAttribute('stderr', $th->getMessage()); @@ -195,7 +195,7 @@ Server::setResource('execute', function () { /** Trigger realtime event */ $allEvents = Event::generateEvents('functions.[functionId].executions.[executionId].update', [ 'functionId' => $function->getId(), - 'executionId' => $execution->getId(), + 'executionId' => $execution->getId() ]); $target = Realtime::fromPayload( // Pass first, most verbose event pattern @@ -220,9 +220,10 @@ Server::setResource('execute', function () { /** Trigger usage queue */ $queueForUsage ->setProject($project) - ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int) ($execution->getAttribute('duration') * 1000))// per project - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int) ($execution->getAttribute('duration') * 1000)) - ->trigger(); + ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000))// per project + ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) + ->trigger() + ; }; }); @@ -252,7 +253,7 @@ $server->job() return; } - if (! empty($events)) { + if (!empty($events)) { $limit = 30; $sum = 30; $offset = 0; @@ -261,19 +262,19 @@ $server->job() while ($sum >= $limit) { $functions = $dbForProject->find('functions', [ Query::limit($limit), - Query::offset($offset), + Query::offset($offset) ]); $sum = \count($functions); $offset = $offset + $limit; - Console::log('Fetched '.$sum.' functions...'); + Console::log('Fetched ' . $sum . ' functions...'); foreach ($functions as $function) { - if (! array_intersect($events, $function->getAttribute('events', []))) { + if (!array_intersect($events, $function->getAttribute('events', []))) { continue; } - Console::success('Iterating function: '.$function->getAttribute('name')); + Console::success('Iterating function: ' . $function->getAttribute('name')); try { $execute( log: $log, @@ -290,13 +291,12 @@ $server->job() executionId: null, jwt: null ); - Console::success('Triggered function: '.$events[0]); + Console::success('Triggered function: ' . $events[0]); } catch (\Throwable $th) { - Console::error('Failed to execute '.$function->getId().' with error: '.$th->getMessage()); + Console::error("Failed to execute " . $function->getId() . " with error: " . $th->getMessage()); } } } - return; } diff --git a/app/workers/mails.php b/app/workers/mails.php index d8949c0222..e1ce8307ac 100644 --- a/app/workers/mails.php +++ b/app/workers/mails.php @@ -1,20 +1,20 @@ args['recipient']; $subject = $this->args['subject']; $name = $this->args['name']; @@ -49,7 +49,7 @@ class MailsV1 extends Worker $mail->clearBCCs(); $mail->clearCCs(); - $mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')) : $from)); + $mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from)); $mail->addAddress($recipient, $name); if (isset($smtp['replyTo'])) { $mail->addReplyTo($smtp['replyTo']); @@ -61,7 +61,7 @@ class MailsV1 extends Worker try { $mail->send(); } catch (\Exception $error) { - throw new Exception('Error sending mail: '.$error->getMessage(), 500); + throw new Exception('Error sending mail: ' . $error->getMessage(), 500); } } @@ -77,14 +77,14 @@ class MailsV1 extends Worker $mail->XMailer = 'Appwrite Mailer'; $mail->Host = $smtp['host']; $mail->Port = $smtp['port']; - $mail->SMTPAuth = (! empty($username) && ! empty($password)); + $mail->SMTPAuth = (!empty($username) && !empty($password)); $mail->Username = $username; $mail->Password = $password; $mail->SMTPSecure = $smtp['secure'] === 'tls'; $mail->SMTPAutoTLS = false; $mail->CharSet = 'UTF-8'; - $from = \urldecode($smtp['senderName'] ?? App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')); + $from = \urldecode($smtp['senderName'] ?? App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')); $email = $smtp['senderEmail'] ?? App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); $mail->setFrom($email, $from); diff --git a/app/workers/messaging.php b/app/workers/messaging.php index b826dc1c3f..84af6fa802 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -2,43 +2,41 @@ use Appwrite\Resque\Worker; use Utopia\CLI\Console; -use Utopia\Messaging\Adapters\Email as EmailAdapter; -use Utopia\Messaging\Adapters\Email\Mailgun; -use Utopia\Messaging\Adapters\Email\SendGrid; -use Utopia\Messaging\Adapters\Push\APNS; -use Utopia\Messaging\Adapters\Push as PushAdapter; -use Utopia\Messaging\Adapters\Push\FCM; use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Adapters\SMS\Msg91; use Utopia\Messaging\Adapters\SMS\Telesign; use Utopia\Messaging\Adapters\SMS\TextMagic; use Utopia\Messaging\Adapters\SMS\Twilio; use Utopia\Messaging\Adapters\SMS\Vonage; +use Utopia\Messaging\Adapters\Push as PushAdapter; +use Utopia\Messaging\Adapters\Push\APNS; +use Utopia\Messaging\Adapters\Push\FCM; +use Utopia\Messaging\Adapters\Email as EmailAdapter; +use Utopia\Messaging\Adapters\Email\Mailgun; +use Utopia\Messaging\Adapters\Email\SendGrid; -require_once __DIR__.'/../init.php'; +require_once __DIR__ . '/../init.php'; Console::title('Messaging V1 Worker'); -Console::success(APP_NAME.' messaging worker v1 has started'."\n"); +Console::success(APP_NAME . ' messaging worker v1 has started' . "\n"); class MessagingV1 extends Worker { protected ?SMSAdapter $sms = null; - protected ?PushAdapter $push = null; - protected ?EmailAdapter $email = null; + protected ?string $from = null; public function getName(): string { - return 'mails'; + return "mails"; } public function sms($record): ?SMSAdapter { $credentials = $record->getAttribute('credentials'); - return match ($record->getAttribute('provider')) { 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), 'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']), @@ -52,7 +50,6 @@ class MessagingV1 extends Worker public function push($record): ?PushAdapter { $credentials = $record->getAttribute('credentials'); - return match ($record->getAttribute('provider')) { 'apns' => new APNS( $credentials['authKey'], @@ -69,7 +66,6 @@ class MessagingV1 extends Worker public function email($record): ?EmailAdapter { $credentials = $record->getAttribute('credentials'); - return match ($record->getAttribute('provider')) { 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain']), 'sendgrid' => new SendGrid($credentials['apiKey']), @@ -96,9 +92,9 @@ class MessagingV1 extends Worker default => null }; - // Query for the provider - // switch on provider name - // call function passing needed credentials returns required provider. + // Query for the provider + // switch on provider name + // call function passing needed credentials returns required provider. $messageId = $this->args['messageId']; $messageRecord = @@ -113,6 +109,7 @@ class MessagingV1 extends Worker default => null }; + $provider->send($message); } @@ -144,7 +141,7 @@ class MessagingV1 extends Worker return [ 'from' => $from, 'to' => $to, - 'body' => $body, + 'body' => $body ]; } @@ -159,7 +156,7 @@ class MessagingV1 extends Worker 'to' => $to, 'title' => $title, 'body' => $body, - 'data' => $data, + 'data' => $data ]; } } diff --git a/app/workers/migrations.php b/app/workers/migrations.php index 99529d4fb2..0f8194acf8 100644 --- a/app/workers/migrations.php +++ b/app/workers/migrations.php @@ -18,10 +18,10 @@ use Utopia\Migration\Sources\NHost; use Utopia\Migration\Sources\Supabase; use Utopia\Migration\Transfer; -require_once __DIR__.'/../init.php'; +require_once __DIR__ . '/../init.php'; Console::title('Migrations V1 Worker'); -Console::success(APP_NAME.' Migrations worker v1 has started'); +Console::success(APP_NAME . ' Migrations worker v1 has started'); class MigrationsV1 extends Worker { diff --git a/app/workers/usage.php b/app/workers/usage.php index 3e76d8e8e7..0c9dcbc5aa 100644 --- a/app/workers/usage.php +++ b/app/workers/usage.php @@ -1,17 +1,17 @@ setNamespace('_'.$projectInternalId); + $dbForProject->setNamespace('_' . $projectInternalId); switch (true) { case $document->getCollection() === 'users': // users $sessions = count($document->getAttribute(METRIC_SESSIONS, 0)); - if (! empty($sessions)) { + if (!empty($sessions)) { $metrics[] = [ 'key' => METRIC_SESSIONS, 'value' => ($sessions * -1), @@ -55,28 +55,28 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools } break; case $document->getCollection() === 'databases': // databases - $collections = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS))); - $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS))); - if (! empty($collections['value'])) { + $collections = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS))); + $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS))); + if (!empty($collections['value'])) { $metrics[] = [ 'key' => METRIC_COLLECTIONS, 'value' => ($collections['value'] * -1), ]; } - if (! empty($documents['value'])) { + if (!empty($documents['value'])) { $metrics[] = [ 'key' => METRIC_DOCUMENTS, 'value' => ($documents['value'] * -1), ]; } break; - case str_starts_with($document->getCollection(), 'database_') && ! str_contains($document->getCollection(), 'collection'): //collections + case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections $parts = explode('_', $document->getCollection()); $databaseInternalId = $parts[1] ?? 0; - $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $document->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS))); + $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $document->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS))); - if (! empty($documents['value'])) { + if (!empty($documents['value'])) { $metrics[] = [ 'key' => METRIC_DOCUMENTS, 'value' => ($documents['value'] * -1), @@ -89,17 +89,17 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools break; case $document->getCollection() === 'buckets': - $files = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES))); - $storage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE))); + $files = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES))); + $storage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE))); - if (! empty($files['value'])) { + if (!empty($files['value'])) { $metrics[] = [ 'key' => METRIC_FILES, 'value' => ($files['value'] * -1), ]; } - if (! empty($storage['value'])) { + if (!empty($storage['value'])) { $metrics[] = [ 'key' => METRIC_FILES_STORAGE, 'value' => ($storage['value'] * -1), @@ -108,57 +108,57 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools break; case $document->getCollection() === 'functions': - $deployments = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS))); - $deploymentsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE))); - $builds = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS))); - $buildsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE))); - $buildsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE))); - $executions = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS))); - $executionsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE))); + $deployments = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS))); + $deploymentsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE))); + $builds = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS))); + $buildsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE))); + $buildsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE))); + $executions = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS))); + $executionsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE))); - if (! empty($deployments['value'])) { + if (!empty($deployments['value'])) { $metrics[] = [ 'key' => METRIC_DEPLOYMENTS, 'value' => ($deployments['value'] * -1), ]; } - if (! empty($deploymentsStorage['value'])) { + if (!empty($deploymentsStorage['value'])) { $metrics[] = [ 'key' => METRIC_DEPLOYMENTS_STORAGE, 'value' => ($deploymentsStorage['value'] * -1), ]; } - if (! empty($builds['value'])) { + if (!empty($builds['value'])) { $metrics[] = [ 'key' => METRIC_BUILDS, 'value' => ($builds['value'] * -1), ]; } - if (! empty($buildsStorage['value'])) { + if (!empty($buildsStorage['value'])) { $metrics[] = [ 'key' => METRIC_BUILDS_STORAGE, 'value' => ($buildsStorage['value'] * -1), ]; } - if (! empty($buildsCompute['value'])) { + if (!empty($buildsCompute['value'])) { $metrics[] = [ 'key' => METRIC_BUILDS_COMPUTE, 'value' => ($buildsCompute['value'] * -1), ]; } - if (! empty($executions['value'])) { + if (!empty($executions['value'])) { $metrics[] = [ 'key' => METRIC_EXECUTIONS, 'value' => ($executions['value'] * -1), ]; } - if (! empty($executionsCompute['value'])) { + if (!empty($executionsCompute['value'])) { $metrics[] = [ 'key' => METRIC_EXECUTIONS_COMPUTE, 'value' => ($executionsCompute['value'] * -1), @@ -169,18 +169,20 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools break; } } catch (\Exception $e) { - console::error('[reducer] '.' {DateTime::now()} '." {$projectInternalId} "." {$e->getMessage()}"); + console::error("[reducer] " . " {DateTime::now()} " . " {$projectInternalId} " . " {$e->getMessage()}"); } finally { $pools->reclaim(); } }; }, ['cache', 'register', 'pools']); + $server->job() ->inject('message') ->inject('reduce') ->action(function (Message $message, callable $reduce) use (&$stats) { + $payload = $message->getPayload() ?? []; $project = new Document($payload['project'] ?? []); $projectId = $project->getInternalId(); @@ -189,19 +191,18 @@ $server->job() continue; } - $reduce( - database: $project->getAttribute('database'), - projectInternalId: $project->getInternalId(), - document: new Document($document), - metrics: $payload['metrics'], - ); + $reduce( + database: $project->getAttribute('database'), + projectInternalId: $project->getInternalId(), + document: new Document($document), + metrics: $payload['metrics'], + ); } $stats[$projectId]['database'] = $project->getAttribute('database'); foreach ($payload['metrics'] ?? [] as $metric) { - if (! isset($stats[$projectId]['keys'][$metric['key']])) { + if (!isset($stats[$projectId]['keys'][$metric['key']])) { $stats[$projectId]['keys'][$metric['key']] = $metric['value']; - continue; } $stats[$projectId]['keys'][$metric['key']] += $metric['value']; @@ -214,7 +215,8 @@ $server ->inject('cache') ->inject('pools') ->action(function ($register, $cache, $pools) use ($periods, &$stats) { - Timer::tick(30000, function () use ($cache, $pools, $periods, &$stats) { + Timer::tick(30000, function () use ($register, $cache, $pools, $periods, &$stats) { + $offset = count($stats); $projects = array_slice($stats, 0, $offset, true); array_splice($stats, 0, $offset); @@ -229,7 +231,7 @@ $server $cache ); - $dbForProject->setNamespace('_'.$projectInternalId); + $dbForProject->setNamespace('_' . $projectInternalId); foreach ($project['keys'] ?? [] as $key => $value) { if ($value == 0) { @@ -268,7 +270,7 @@ $server } } } - if (! empty($project['keys'])) { + if (!empty($project['keys'])) { $dbForProject->createDocument('statsLogger', new Document([ 'time' => DateTime::now(), 'metrics' => $project['keys'], @@ -276,7 +278,7 @@ $server } } catch (\Exception $e) { $now = DateTime::now(); - console::error('[Error] '." Time: {$now} "." projectInternalId: {$projectInternalId}"." File: {$e->getFile()}"." Line: {$e->getLine()} "." message: {$e->getMessage()}"); + console::error("[Error] " . " Time: {$now} " . " projectInternalId: {$projectInternalId}" . " File: {$e->getFile()}" . " Line: {$e->getLine()} " . " message: {$e->getMessage()}"); } finally { $pools->reclaim(); } diff --git a/app/workers/webhooks.php b/app/workers/webhooks.php index 33fd4e5f6c..4048581c0c 100644 --- a/app/workers/webhooks.php +++ b/app/workers/webhooks.php @@ -5,10 +5,10 @@ use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Document; -require_once __DIR__.'/../init.php'; +require_once __DIR__ . '/../init.php'; Console::title('Webhooks V1 Worker'); -Console::success(APP_NAME.' webhooks worker v1 has started'); +Console::success(APP_NAME . ' webhooks worker v1 has started'); class WebhooksV1 extends Worker { @@ -16,7 +16,7 @@ class WebhooksV1 extends Worker public function getName(): string { - return 'webhooks'; + return "webhooks"; } public function init(): void @@ -36,7 +36,7 @@ class WebhooksV1 extends Worker } } - if (! empty($this->errors)) { + if (!empty($this->errors)) { throw new Exception(\implode(" / \n\n", $this->errors)); } } @@ -45,7 +45,7 @@ class WebhooksV1 extends Worker { $url = \rawurldecode($webhook->getAttribute('url')); $signatureKey = $webhook->getAttribute('signatureKey'); - $signature = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $signature = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $httpUser = $webhook->getAttribute('httpUser'); $httpPass = $webhook->getAttribute('httpPass'); $ch = \curl_init($webhook->getAttribute('url')); @@ -64,28 +64,28 @@ class WebhooksV1 extends Worker CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', - 'Content-Length: '.\strlen($payload), - 'X-'.APP_NAME.'-Webhook-Id: '.$webhook->getId(), - 'X-'.APP_NAME.'-Webhook-Events: '.implode(',', $events), - 'X-'.APP_NAME.'-Webhook-Name: '.$webhook->getAttribute('name', ''), - 'X-'.APP_NAME.'-Webhook-User-Id: '.$user->getId(), - 'X-'.APP_NAME.'-Webhook-Project-Id: '.$project->getId(), - 'X-'.APP_NAME.'-Webhook-Signature: '.$signature, + 'Content-Length: ' . \strlen($payload), + 'X-' . APP_NAME . '-Webhook-Id: ' . $webhook->getId(), + 'X-' . APP_NAME . '-Webhook-Events: ' . implode(',', $events), + 'X-' . APP_NAME . '-Webhook-Name: ' . $webhook->getAttribute('name', ''), + 'X-' . APP_NAME . '-Webhook-User-Id: ' . $user->getId(), + 'X-' . APP_NAME . '-Webhook-Project-Id: ' . $project->getId(), + 'X-' . APP_NAME . '-Webhook-Signature: ' . $signature, ] ); - if (! $webhook->getAttribute('security', true)) { + if (!$webhook->getAttribute('security', true)) { \curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); \curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - if (! empty($httpUser) && ! empty($httpPass)) { + if (!empty($httpUser) && !empty($httpPass)) { \curl_setopt($ch, CURLOPT_USERPWD, "$httpUser:$httpPass"); \curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } if (false === \curl_exec($ch)) { - $this->errors[] = \curl_error($ch).' in events '.implode(', ', $events).' for webhook '.$webhook->getAttribute('name'); + $this->errors[] = \curl_error($ch) . ' in events ' . implode(', ', $events) . ' for webhook ' . $webhook->getAttribute('name'); } \curl_close($ch); diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index 98a0cf27d8..e97c271ae2 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -9,8 +9,8 @@ use Appwrite\Auth\Hash\Phpass; use Appwrite\Auth\Hash\Scrypt; use Appwrite\Auth\Hash\Scryptmodified; use Appwrite\Auth\Hash\Sha; -use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Roles; @@ -25,69 +25,49 @@ class Auth 'phpass', 'scrypt', 'scryptMod', - 'plaintext', + 'plaintext' ]; public const DEFAULT_ALGO = 'argon2'; - public const DEFAULT_ALGO_OPTIONS = ['type' => 'argon2', 'memoryCost' => 2048, 'timeCost' => 4, 'threads' => 3]; /** * User Roles. */ public const USER_ROLE_ANY = 'any'; - public const USER_ROLE_GUESTS = 'guests'; - public const USER_ROLE_USERS = 'users'; - public const USER_ROLE_ADMIN = 'admin'; - public const USER_ROLE_DEVELOPER = 'developer'; - public const USER_ROLE_OWNER = 'owner'; - public const USER_ROLE_APPS = 'apps'; - public const USER_ROLE_SYSTEM = 'system'; /** * Token Types. */ public const TOKEN_TYPE_LOGIN = 1; // Deprecated - public const TOKEN_TYPE_VERIFICATION = 2; - public const TOKEN_TYPE_RECOVERY = 3; - public const TOKEN_TYPE_INVITE = 4; - public const TOKEN_TYPE_MAGIC_URL = 5; - public const TOKEN_TYPE_PHONE = 6; /** * Session Providers. */ public const SESSION_PROVIDER_EMAIL = 'email'; - public const SESSION_PROVIDER_ANONYMOUS = 'anonymous'; - public const SESSION_PROVIDER_MAGIC_URL = 'magic-url'; - public const SESSION_PROVIDER_PHONE = 'phone'; /** * Token Expiration times. */ public const TOKEN_EXPIRATION_LOGIN_LONG = 31536000; /* 1 year */ - public const TOKEN_EXPIRATION_LOGIN_SHORT = 3600; /* 1 hour */ - public const TOKEN_EXPIRATION_RECOVERY = 3600; /* 1 hour */ - public const TOKEN_EXPIRATION_CONFIRM = 3600 * 24 * 7; /* 7 days */ - public const TOKEN_EXPIRATION_PHONE = 60 * 15; /* 15 minutes */ /** @@ -113,6 +93,7 @@ class Auth * Set Cookie Name. * * @param $string + * * @return string */ public static function setCookieName($string) @@ -123,8 +104,9 @@ class Auth /** * Encode Session. * - * @param string $id - * @param string $secret + * @param string $id + * @param string $secret + * * @return string */ public static function encodeSession($id, $secret) @@ -138,7 +120,8 @@ class Auth /** * Decode Session. * - * @param string $session + * @param string $session + * * @return array * * @throws \Exception @@ -148,7 +131,7 @@ class Auth $session = \json_decode(\base64_decode($session), true); $default = ['id' => null, 'secret' => '']; - if (! \is_array($session)) { + if (!\is_array($session)) { return $default; } @@ -161,6 +144,7 @@ class Auth * One-way encryption * * @param $string + * * @return string */ public static function hash(string $string) @@ -173,9 +157,10 @@ class Auth * * One way string hashing for user passwords * - * @param string $string - * @param string $algo hashing algorithm to use - * @param array $options algo-specific options + * @param string $string + * @param string $algo hashing algorithm to use + * @param array $options algo-specific options + * * @return bool|string|null */ public static function passwordHash(string $string, string $algo, array $options = []) @@ -186,51 +171,45 @@ class Auth $options = Auth::DEFAULT_ALGO_OPTIONS; } - if (! \in_array($algo, Auth::SUPPORTED_ALGOS)) { - throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.'); + if (!\in_array($algo, Auth::SUPPORTED_ALGOS)) { + throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.'); } switch ($algo) { case 'argon2': $hasher = new Argon2($options); - return $hasher->hash($string); case 'bcrypt': $hasher = new Bcrypt($options); - return $hasher->hash($string); case 'md5': $hasher = new Md5($options); - return $hasher->hash($string); case 'sha': $hasher = new Sha($options); - return $hasher->hash($string); case 'phpass': $hasher = new Phpass($options); - return $hasher->hash($string); case 'scrypt': $hasher = new Scrypt($options); - return $hasher->hash($string); case 'scryptMod': $hasher = new Scryptmodified($options); - return $hasher->hash($string); default: - throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.'); + throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.'); } } /** * Password verify. * - * @param string $plain - * @param string $hash - * @param string $algo hashing algorithm used to hash - * @param array $options algo-specific options + * @param string $plain + * @param string $hash + * @param string $algo hashing algorithm used to hash + * @param array $options algo-specific options + * * @return bool */ public static function passwordVerify(string $plain, string $hash, string $algo, array $options = []) @@ -241,41 +220,34 @@ class Auth $options = Auth::DEFAULT_ALGO_OPTIONS; } - if (! \in_array($algo, Auth::SUPPORTED_ALGOS)) { - throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.'); + if (!\in_array($algo, Auth::SUPPORTED_ALGOS)) { + throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.'); } switch ($algo) { case 'argon2': $hasher = new Argon2($options); - return $hasher->verify($plain, $hash); case 'bcrypt': $hasher = new Bcrypt($options); - return $hasher->verify($plain, $hash); case 'md5': $hasher = new Md5($options); - return $hasher->verify($plain, $hash); case 'sha': $hasher = new Sha($options); - return $hasher->verify($plain, $hash); case 'phpass': $hasher = new Phpass($options); - return $hasher->verify($plain, $hash); case 'scrypt': $hasher = new Scrypt($options); - return $hasher->verify($plain, $hash); case 'scryptMod': $hasher = new Scryptmodified($options); - return $hasher->verify($plain, $hash); default: - throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.'); + throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.'); } } @@ -284,7 +256,8 @@ class Auth * * Generate random password string * - * @param int $length + * @param int $length + * * @return string */ public static function passwordGenerator(int $length = 20): string @@ -297,7 +270,8 @@ class Auth * * Generate random password string * - * @param int $length + * @param int $length + * * @return string */ public static function tokenGenerator(int $length = 128): string @@ -310,7 +284,8 @@ class Auth * * Generate random code string * - * @param int $length + * @param int $length + * * @return string */ public static function codeGenerator(int $length = 6): string @@ -327,9 +302,10 @@ class Auth /** * Verify token and check that its not expired. * - * @param array $tokens - * @param int $type - * @param string $secret + * @param array $tokens + * @param int $type + * @param string $secret + * * @return bool|string */ public static function tokenVerify(array $tokens, int $type, string $secret) @@ -344,7 +320,7 @@ class Auth $token->getAttribute('secret') === self::hash($secret) && DateTime::formatTz($token->getAttribute('expire')) >= DateTime::formatTz(DateTime::now()) ) { - return (string) $token->getId(); + return (string)$token->getId(); } } @@ -373,9 +349,10 @@ class Auth /** * Verify session and check that its not expired. * - * @param array $sessions - * @param string $secret - * @param string $expires + * @param array $sessions + * @param string $secret + * @param string $expires + * * @return bool|string */ public static function sessionVerify(array $sessions, string $secret, int $expires) @@ -398,7 +375,8 @@ class Auth /** * Is Privileged User? * - * @param array $roles + * @param array $roles + * * @return bool */ public static function isPrivilegedUser(array $roles): bool @@ -417,7 +395,8 @@ class Auth /** * Is App User? * - * @param array $roles + * @param array $roles + * * @return bool */ public static function isAppUser(array $roles): bool @@ -432,14 +411,14 @@ class Auth /** * Returns all roles for a user. * - * @param Document $user + * @param Document $user * @return array */ public static function getRoles(Document $user): array { $roles = []; - if (! self::isPrivilegedUser(Authorization::getRoles()) && ! self::isAppUser(Authorization::getRoles())) { + if (!self::isPrivilegedUser(Authorization::getRoles()) && !self::isAppUser(Authorization::getRoles())) { if ($user->getId()) { $roles[] = Role::user($user->getId())->toString(); $roles[] = Role::users()->toString(); @@ -460,7 +439,7 @@ class Auth } foreach ($user->getAttribute('memberships', []) as $node) { - if (! isset($node['confirm']) || ! $node['confirm']) { + if (!isset($node['confirm']) || !$node['confirm']) { continue; } @@ -477,7 +456,7 @@ class Auth } foreach ($user->getAttribute('labels', []) as $label) { - $roles[] = 'label:'.$label; + $roles[] = 'label:' . $label; } return $roles; diff --git a/src/Appwrite/Auth/Hash.php b/src/Appwrite/Auth/Hash.php index caf4771fcd..7134057581 100644 --- a/src/Appwrite/Auth/Hash.php +++ b/src/Appwrite/Auth/Hash.php @@ -5,13 +5,13 @@ namespace Appwrite\Auth; abstract class Hash { /** - * @var array Hashing-algo specific options - */ + * @var array $options Hashing-algo specific options + */ protected array $options = []; /** - * @param array $options Hashing-algo specific options - */ + * @param array $options Hashing-algo specific options + */ public function __construct(array $options = []) { $this->setOptions($options); @@ -20,12 +20,11 @@ abstract class Hash /** * Set hashing algo options * - * @param array $options Hashing-algo specific options - */ + * @param array $options Hashing-algo specific options + */ public function setOptions(array $options): self { $this->options = \array_merge([], $this->getDefaultOptions(), $options); - return $this; } @@ -33,22 +32,24 @@ abstract class Hash * Get hashing algo options * * @return array $options Hashing-algo specific options - */ + */ public function getOptions(): array { return $this->options; } /** - * @param string $password Input password to hash + * @param string $password Input password to hash + * * @return string hash */ abstract public function hash(string $password): string; /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * @return bool true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * + * @return boolean true if password matches hash */ abstract public function verify(string $password, string $hash): bool; diff --git a/src/Appwrite/Auth/Hash/Argon2.php b/src/Appwrite/Auth/Hash/Argon2.php index 0e9c2fcf36..c723b077b1 100644 --- a/src/Appwrite/Auth/Hash/Argon2.php +++ b/src/Appwrite/Auth/Hash/Argon2.php @@ -15,7 +15,8 @@ use Appwrite\Auth\Hash; class Argon2 extends Hash { /** - * @param string $password Input password to hash + * @param string $password Input password to hash + * * @return string hash */ public function hash(string $password): string @@ -24,9 +25,10 @@ class Argon2 extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * @return bool true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * + * @return boolean true if password matches hash */ public function verify(string $password, string $hash): bool { diff --git a/src/Appwrite/Auth/Hash/Bcrypt.php b/src/Appwrite/Auth/Hash/Bcrypt.php index c54cf3d452..8b6177f33a 100644 --- a/src/Appwrite/Auth/Hash/Bcrypt.php +++ b/src/Appwrite/Auth/Hash/Bcrypt.php @@ -14,7 +14,8 @@ use Appwrite\Auth\Hash; class Bcrypt extends Hash { /** - * @param string $password Input password to hash + * @param string $password Input password to hash + * * @return string hash */ public function hash(string $password): string @@ -23,9 +24,10 @@ class Bcrypt extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * @return bool true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * + * @return boolean true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -39,6 +41,6 @@ class Bcrypt extends Hash */ public function getDefaultOptions(): array { - return ['cost' => 8]; + return [ 'cost' => 8 ]; } } diff --git a/src/Appwrite/Auth/Hash/Md5.php b/src/Appwrite/Auth/Hash/Md5.php index 0f6fe5c30d..8ade3dd5e2 100644 --- a/src/Appwrite/Auth/Hash/Md5.php +++ b/src/Appwrite/Auth/Hash/Md5.php @@ -12,7 +12,8 @@ use Appwrite\Auth\Hash; class Md5 extends Hash { /** - * @param string $password Input password to hash + * @param string $password Input password to hash + * * @return string hash */ public function hash(string $password): string @@ -21,9 +22,10 @@ class Md5 extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * @return bool true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * + * @return boolean true if password matches hash */ public function verify(string $password, string $hash): bool { diff --git a/src/Appwrite/Auth/Hash/Phpass.php b/src/Appwrite/Auth/Hash/Phpass.php index ded4e407ff..187e4a27a6 100644 --- a/src/Appwrite/Auth/Hash/Phpass.php +++ b/src/Appwrite/Auth/Hash/Phpass.php @@ -39,7 +39,6 @@ class Phpass extends Hash * Alphabet used in itoa64 conversions. * * @var string - * * @since 0.1.0 */ protected string $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; @@ -60,7 +59,8 @@ class Phpass extends Hash } /** - * @param string $password Input password to hash + * @param string $password Input password to hash + * * @return string hash */ public function hash(string $password): string @@ -68,7 +68,7 @@ class Phpass extends Hash $options = $this->getDefaultOptions(); $random = ''; - if (CRYPT_BLOWFISH === 1 && ! $options['portable_hashes']) { + if (CRYPT_BLOWFISH === 1 && !$options['portable_hashes']) { $random = $this->getRandomBytes(16, $options); $hash = crypt($password, $this->gensaltBlowfish($random, $options)); if (strlen($hash) === 60) { @@ -92,9 +92,10 @@ class Phpass extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * @return bool true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * + * @return boolean true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -113,16 +114,15 @@ class Phpass extends Hash } /** - * @param int $count - * @return string $output + * @param int $count * + * @return String $output * @since 0.1.0 - * * @throws Exception Thows an Exception if the $count parameter is not a positive integer. */ protected function getRandomBytes(int $count, array $options): string { - if (! is_int($count) || $count < 1) { + if (!is_int($count) || $count < 1) { throw new \Exception('Argument count must be a positive integer'); } $output = ''; @@ -135,7 +135,7 @@ class Phpass extends Hash $output = ''; for ($i = 0; $i < $count; $i += 16) { - $options['iteration_count_log2'] = md5(microtime().$options['iteration_count_log2']); + $options['iteration_count_log2'] = md5(microtime() . $options['iteration_count_log2']); $output .= md5($options['iteration_count_log2'], true); } @@ -146,48 +146,47 @@ class Phpass extends Hash } /** - * @param string $input - * @param int $count - * @return string $output + * @param String $input + * @param int $count * + * @return String $output * @since 0.1.0 - * * @throws Exception Thows an Exception if the $count parameter is not a positive integer. */ protected function encode64($input, $count) { - if (! is_int($count) || $count < 1) { + if (!is_int($count) || $count < 1) { throw new \Exception('Argument count must be a positive integer'); } $output = ''; $i = 0; do { $value = ord($input[$i++]); - $output .= $this->itoa64[$value & 0x3F]; + $output .= $this->itoa64[$value & 0x3f]; if ($i < $count) { $value |= ord($input[$i]) << 8; } - $output .= $this->itoa64[($value >> 6) & 0x3F]; + $output .= $this->itoa64[($value >> 6) & 0x3f]; if ($i++ >= $count) { break; } if ($i < $count) { $value |= ord($input[$i]) << 16; } - $output .= $this->itoa64[($value >> 12) & 0x3F]; + $output .= $this->itoa64[($value >> 12) & 0x3f]; if ($i++ >= $count) { break; } - $output .= $this->itoa64[($value >> 18) & 0x3F]; + $output .= $this->itoa64[($value >> 18) & 0x3f]; } while ($i < $count); return $output; } /** - * @param string $input - * @return string $output + * @param String $input * + * @return String $output * @since 0.1.0 */ private function gensaltPrivate($input, $options) @@ -200,10 +199,10 @@ class Phpass extends Hash } /** - * @param string $password - * @param string $setting - * @return string $output + * @param String $password + * @param String $setting * + * @return String $output * @since 0.1.0 */ private function cryptPrivate($password, $setting) @@ -234,9 +233,9 @@ class Phpass extends Hash * consequently in lower iteration counts and hashes that are * quicker to crack (by non-PHP code). */ - $hash = md5($salt.$password, true); + $hash = md5($salt . $password, true); do { - $hash = md5($hash.$password, true); + $hash = md5($hash . $password, true); } while (--$count); $output = substr($setting, 0, 12); $output .= $this->encode64($hash, 16); @@ -245,9 +244,9 @@ class Phpass extends Hash } /** - * @param string $input - * @return string $output + * @param String $input * + * @return String $output * @since 0.1.0 */ private function gensaltBlowfish($input, $options) @@ -279,11 +278,11 @@ class Phpass extends Hash $c2 = ord($input[$i++]); $c1 |= $c2 >> 4; $output .= $itoa64[$c1]; - $c1 = ($c2 & 0x0F) << 2; + $c1 = ($c2 & 0x0f) << 2; $c2 = ord($input[$i++]); $c1 |= $c2 >> 6; $output .= $itoa64[$c1]; - $output .= $itoa64[$c2 & 0x3F]; + $output .= $itoa64[$c2 & 0x3f]; } while (1); return $output; diff --git a/src/Appwrite/Auth/Hash/Scrypt.php b/src/Appwrite/Auth/Hash/Scrypt.php index 8c50c16341..821b1fba69 100644 --- a/src/Appwrite/Auth/Hash/Scrypt.php +++ b/src/Appwrite/Auth/Hash/Scrypt.php @@ -17,7 +17,8 @@ use Appwrite\Auth\Hash; class Scrypt extends Hash { /** - * @param string $password Input password to hash + * @param string $password Input password to hash + * * @return string hash */ public function hash(string $password): string @@ -28,9 +29,10 @@ class Scrypt extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * @return bool true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * + * @return boolean true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -44,6 +46,6 @@ class Scrypt extends Hash */ public function getDefaultOptions(): array { - return ['costCpu' => 8, 'costMemory' => 14, 'costParallel' => 1, 'length' => 64]; + return [ 'costCpu' => 8, 'costMemory' => 14, 'costParallel' => 1, 'length' => 64 ]; } } diff --git a/src/Appwrite/Auth/Hash/Scryptmodified.php b/src/Appwrite/Auth/Hash/Scryptmodified.php index 9260913aed..2d1cd4f165 100644 --- a/src/Appwrite/Auth/Hash/Scryptmodified.php +++ b/src/Appwrite/Auth/Hash/Scryptmodified.php @@ -16,7 +16,8 @@ use Appwrite\Auth\Hash; class Scryptmodified extends Hash { /** - * @param string $password Input password to hash + * @param string $password Input password to hash + * * @return string hash */ public function hash(string $password): string @@ -32,9 +33,10 @@ class Scryptmodified extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * @return bool true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * + * @return boolean true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -48,7 +50,7 @@ class Scryptmodified extends Hash */ public function getDefaultOptions(): array { - return []; + return [ ]; } private function generateDerivedKey(string $password) @@ -58,7 +60,7 @@ class Scryptmodified extends Hash $saltBytes = \base64_decode($options['salt']); $saltSeparatorBytes = \base64_decode($options['saltSeparator']); - $derivedKey = \scrypt(\utf8_encode($password), $saltBytes.$saltSeparatorBytes, 16384, 8, 1, 64); + $derivedKey = \scrypt(\utf8_encode($password), $saltBytes . $saltSeparatorBytes, 16384, 8, 1, 64); $derivedKey = \hex2bin($derivedKey); return $derivedKey; diff --git a/src/Appwrite/Auth/Hash/Sha.php b/src/Appwrite/Auth/Hash/Sha.php index 331c4fe6f2..c2ae3b52c1 100644 --- a/src/Appwrite/Auth/Hash/Sha.php +++ b/src/Appwrite/Auth/Hash/Sha.php @@ -16,7 +16,8 @@ use Appwrite\Auth\Hash; class Sha extends Hash { /** - * @param string $password Input password to hash + * @param string $password Input password to hash + * * @return string hash */ public function hash(string $password): string @@ -27,9 +28,10 @@ class Sha extends Hash } /** - * @param string $password Input password to validate - * @param string $hash Hash to verify password against - * @return bool true if password matches hash + * @param string $password Input password to validate + * @param string $hash Hash to verify password against + * + * @return boolean true if password matches hash */ public function verify(string $password, string $hash): bool { @@ -43,6 +45,6 @@ class Sha extends Hash */ public function getDefaultOptions(): array { - return ['version' => 'sha3-512']; + return [ 'version' => 'sha3-512' ]; } } diff --git a/src/Appwrite/Auth/OAuth2.php b/src/Appwrite/Auth/OAuth2.php index 37f6416fb5..c737e183f8 100644 --- a/src/Appwrite/Auth/OAuth2.php +++ b/src/Appwrite/Auth/OAuth2.php @@ -34,11 +34,11 @@ abstract class OAuth2 /** * OAuth2 constructor. * - * @param string $appId - * @param string $appSecret - * @param string $callback - * @param array $state - * @param array $scopes + * @param string $appId + * @param string $appSecret + * @param string $callback + * @param array $state + * @param array $scopes */ public function __construct(string $appId, string $appSecret, string $callback, array $state = [], array $scopes = []) { @@ -62,25 +62,29 @@ abstract class OAuth2 abstract public function getLoginURL(): string; /** - * @param string $code + * @param string $code + * * @return array */ abstract protected function getTokens(string $code): array; /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ abstract public function refreshTokens(string $refreshToken): array; /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ abstract public function getUserID(string $accessToken): string; /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ abstract public function getUserEmail(string $accessToken): string; @@ -88,25 +92,28 @@ abstract class OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ abstract public function isEmailVerified(string $accessToken): bool; /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ abstract public function getUserName(string $accessToken): string; /** * @param $scope + * * @return $this */ protected function addScope(string $scope): OAuth2 { // Add a scope to the scopes array if it isn't already present - if (! \in_array($scope, $this->scopes)) { + if (!\in_array($scope, $this->scopes)) { $this->scopes[] = $scope; } @@ -122,7 +129,8 @@ abstract class OAuth2 } /** - * @param string $code + * @param string $code + * * @return string */ public function getAccessToken(string $code): string @@ -133,7 +141,8 @@ abstract class OAuth2 } /** - * @param string $code + * @param string $code + * * @return string */ public function getRefreshToken(string $code): string @@ -144,7 +153,8 @@ abstract class OAuth2 } /** - * @param string $code + * @param string $code + * * @return string */ public function getAccessTokenExpiry(string $code): int @@ -159,6 +169,7 @@ abstract class OAuth2 // json_decoding /** * @param $state + * * @return array */ public function parseState(string $state) @@ -167,10 +178,11 @@ abstract class OAuth2 } /** - * @param string $method - * @param string $url - * @param array $headers - * @param string $payload + * @param string $method + * @param string $url + * @param array $headers + * @param string $payload + * * @return string */ protected function request(string $method, string $url = '', array $headers = [], string $payload = ''): string @@ -182,11 +194,11 @@ abstract class OAuth2 \curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); \curl_setopt($ch, CURLOPT_USERAGENT, 'Appwrite OAuth2'); - if (! empty($payload)) { + if (!empty($payload)) { \curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); } - $headers[] = 'Content-length: '.\strlen($payload); + $headers[] = 'Content-length: ' . \strlen($payload); \curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // Send the request & save response to $response @@ -200,6 +212,6 @@ abstract class OAuth2 throw new Exception($response, $code); } - return (string) $response; + return (string)$response; } } diff --git a/src/Appwrite/Auth/OAuth2/Amazon.php b/src/Appwrite/Auth/OAuth2/Amazon.php index c2cdedf2f1..d1d2cb5a38 100644 --- a/src/Appwrite/Auth/OAuth2/Amazon.php +++ b/src/Appwrite/Auth/OAuth2/Amazon.php @@ -25,7 +25,7 @@ class Amazon extends OAuth2 * @var array */ protected array $scopes = [ - 'profile', + "profile" ]; /** @@ -37,7 +37,8 @@ class Amazon extends OAuth2 } /** - * @param string $state + * @param string $state + * * @return array */ public function parseState(string $state) @@ -45,22 +46,24 @@ class Amazon extends OAuth2 return \json_decode(\html_entity_decode($state), true); } + /** * @return string */ public function getLoginURL(): string { - return 'https://www.amazon.com/ap/oa?'.\http_build_query([ + return 'https://www.amazon.com/ap/oa?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state), - 'redirect_uri' => $this->callback, + 'redirect_uri' => $this->callback ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -76,7 +79,7 @@ class Amazon extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'redirect_uri' => $this->callback, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -85,7 +88,8 @@ class Amazon extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -99,7 +103,7 @@ class Amazon extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken, + 'refresh_token' => $refreshToken ]) ), true); @@ -111,7 +115,8 @@ class Amazon extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -122,7 +127,8 @@ class Amazon extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -137,18 +143,20 @@ class Amazon extends OAuth2 * * If present, the email is verified. This was verfied through a manual Amazon sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -159,16 +167,16 @@ class Amazon extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token='.\urlencode($accessToken)); + $user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token=' . \urlencode($accessToken)); $this->user = \json_decode($user, true); } - return $this->user; } } diff --git a/src/Appwrite/Auth/OAuth2/Apple.php b/src/Appwrite/Auth/OAuth2/Apple.php index 27f41543ae..2abf61c947 100644 --- a/src/Appwrite/Auth/OAuth2/Apple.php +++ b/src/Appwrite/Auth/OAuth2/Apple.php @@ -24,8 +24,8 @@ class Apple extends OAuth2 * @var array */ protected array $scopes = [ - 'name', - 'email', + "name", + "email" ]; /** @@ -46,18 +46,19 @@ class Apple extends OAuth2 */ public function getLoginURL(): string { - return 'https://appleid.apple.com/auth/authorize?'.\http_build_query([ + return 'https://appleid.apple.com/auth/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'response_type' => 'code', 'response_mode' => 'form_post', - 'scope' => \implode(' ', $this->getScopes()), + 'scope' => \implode(' ', $this->getScopes()) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -85,7 +86,8 @@ class Apple extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -114,7 +116,8 @@ class Apple extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -123,7 +126,8 @@ class Apple extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -136,7 +140,8 @@ class Apple extends OAuth2 * * @link https://developer.apple.com/forums/thread/121411 * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -149,14 +154,15 @@ class Apple extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string { if ( isset($this->claims['email']) && - ! empty($this->claims['email']) && + !empty($this->claims['email']) && isset($this->claims['email_verified']) && $this->claims['email_verified'] === 'true' ) { @@ -177,7 +183,7 @@ class Apple extends OAuth2 $keyfile = (isset($secret['p8'])) ? $secret['p8'] : ''; // Your p8 Key file $keyID = (isset($secret['keyID'])) ? $secret['keyID'] : ''; // Your Key ID $teamID = (isset($secret['teamID'])) ? $secret['teamID'] : ''; // Your Team ID (see Developer Portal) - $bundleID = $this->appID; // Your Bundle ID + $bundleID = $this->appID; // Your Bundle ID $headers = [ 'alg' => 'ES256', @@ -194,21 +200,22 @@ class Apple extends OAuth2 $pkey = \openssl_pkey_get_private($keyfile); - $payload = $this->encode(\json_encode($headers)).'.'.$this->encode(\json_encode($claims)); + $payload = $this->encode(\json_encode($headers)) . '.' . $this->encode(\json_encode($claims)); $signature = ''; $success = \openssl_sign($payload, $signature, $pkey, OPENSSL_ALGO_SHA256); - if (! $success) { + if (!$success) { return ''; } - return $payload.'.'.$this->encode($this->fromDER($signature, 64)); + return $payload . '.' . $this->encode($this->fromDER($signature, 64)); } /** - * @param string $data + * @param string $data + * * @return string */ protected function encode($data): string @@ -217,7 +224,7 @@ class Apple extends OAuth2 } /** - * @param string $data + * @param string $data */ protected function retrievePositiveInteger(string $data): string { @@ -229,8 +236,8 @@ class Apple extends OAuth2 } /** - * @param string $der - * @param int $partLength + * @param string $der + * @param int $partLength */ protected function fromDER(string $der, int $partLength): string { @@ -263,6 +270,6 @@ class Apple extends OAuth2 $S = $this->retrievePositiveInteger(\mb_substr($hex, 4, $Sl * 2, '8bit')); $S = \str_pad($S, $partLength, '0', STR_PAD_LEFT); - return \pack('H*', $R.$S); + return \pack('H*', $R . $S); } } diff --git a/src/Appwrite/Auth/OAuth2/Auth0.php b/src/Appwrite/Auth/OAuth2/Auth0.php index e2615017bd..eba7d18b5f 100644 --- a/src/Appwrite/Auth/OAuth2/Auth0.php +++ b/src/Appwrite/Auth/OAuth2/Auth0.php @@ -16,7 +16,7 @@ class Auth0 extends OAuth2 'openid', 'profile', 'email', - 'offline_access', + 'offline_access' ]; /** @@ -42,17 +42,18 @@ class Auth0 extends OAuth2 */ public function getLoginURL(): string { - return 'https://'.$this->getAuth0Domain().'/authorize?'.\http_build_query([ + return 'https://' . $this->getAuth0Domain() . '/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), - 'response_type' => 'code', + 'response_type' => 'code' ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -61,7 +62,7 @@ class Auth0 extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://'.$this->getAuth0Domain().'/oauth/token', + 'https://' . $this->getAuth0Domain() . '/oauth/token', $headers, \http_build_query([ 'code' => $code, @@ -69,7 +70,7 @@ class Auth0 extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -77,8 +78,10 @@ class Auth0 extends OAuth2 return $this->tokens; } + /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -86,13 +89,13 @@ class Auth0 extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://'.$this->getAuth0Domain().'/oauth/token', + 'https://' . $this->getAuth0Domain() . '/oauth/token', $headers, \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -104,7 +107,8 @@ class Auth0 extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -115,7 +119,8 @@ class Auth0 extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -130,7 +135,8 @@ class Auth0 extends OAuth2 * * @link https://auth0.com/docs/api/authentication?javascript#user-profile * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -145,7 +151,8 @@ class Auth0 extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -156,14 +163,15 @@ class Auth0 extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; - $user = $this->request('GET', 'https://'.$this->getAuth0Domain().'/userinfo', $headers); + $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $user = $this->request('GET', 'https://' . $this->getAuth0Domain() . '/userinfo', $headers); $this->user = \json_decode($user, true); } @@ -206,7 +214,6 @@ class Auth0 extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } - return $secret; } } diff --git a/src/Appwrite/Auth/OAuth2/Authentik.php b/src/Appwrite/Auth/OAuth2/Authentik.php index 8a6b13cdef..16822e2c9f 100644 --- a/src/Appwrite/Auth/OAuth2/Authentik.php +++ b/src/Appwrite/Auth/OAuth2/Authentik.php @@ -16,7 +16,7 @@ class Authentik extends OAuth2 'openid', 'profile', 'email', - 'offline_access', + 'offline_access' ]; /** @@ -42,17 +42,18 @@ class Authentik extends OAuth2 */ public function getLoginURL(): string { - return 'https://'.$this->getAuthentikDomain().'/application/o/authorize?'.\http_build_query([ + return 'https://' . $this->getAuthentikDomain() . '/application/o/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), - 'response_type' => 'code', + 'response_type' => 'code' ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -61,7 +62,7 @@ class Authentik extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://'.$this->getAuthentikDomain().'/application/o/token/', + 'https://' . $this->getAuthentikDomain() . '/application/o/token/', $headers, \http_build_query([ 'code' => $code, @@ -69,16 +70,17 @@ class Authentik extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } - return $this->tokens; } + /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -86,13 +88,13 @@ class Authentik extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://'.$this->getAuthentikDomain().'/application/o/token/', + 'https://' . $this->getAuthentikDomain() . '/application/o/token/', $headers, \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -104,7 +106,8 @@ class Authentik extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -119,7 +122,8 @@ class Authentik extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -136,7 +140,8 @@ class Authentik extends OAuth2 /** * Check if the User email is verified * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -151,7 +156,8 @@ class Authentik extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -165,15 +171,16 @@ class Authentik extends OAuth2 return ''; } - /** - * @param string $accessToken + /** + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; - $user = $this->request('GET', 'https://'.$this->getAuthentikDomain().'/application/o/userinfo/', $headers); + $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $user = $this->request('GET', 'https://' . $this->getAuthentikDomain() . '/application/o/userinfo/', $headers); $this->user = \json_decode($user, true); } @@ -192,7 +199,7 @@ class Authentik extends OAuth2 return $secret['clientSecret'] ?? ''; } - /** + /** * Extracts the authentik Domain from the JSON stored in appSecret * * @return string @@ -200,7 +207,6 @@ class Authentik extends OAuth2 protected function getAuthentikDomain(): string { $secret = $this->getAppSecret(); - return $secret['authentikDomain'] ?? ''; } @@ -216,7 +222,6 @@ class Authentik extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } - return $secret; } } diff --git a/src/Appwrite/Auth/OAuth2/Autodesk.php b/src/Appwrite/Auth/OAuth2/Autodesk.php index 071eee7dcb..0b268ead3b 100644 --- a/src/Appwrite/Auth/OAuth2/Autodesk.php +++ b/src/Appwrite/Auth/OAuth2/Autodesk.php @@ -36,17 +36,18 @@ class Autodesk extends OAuth2 */ public function getLoginURL(): string { - return 'https://developer.api.autodesk.com/authentication/v1/authorize?'.\http_build_query([ + return 'https://developer.api.autodesk.com/authentication/v1/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state), 'redirect_uri' => $this->callback, - 'response_type' => 'code', + 'response_type' => 'code' ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -62,7 +63,7 @@ class Autodesk extends OAuth2 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, 'code' => $code, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ); @@ -73,7 +74,8 @@ class Autodesk extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -103,7 +105,8 @@ class Autodesk extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -114,7 +117,8 @@ class Autodesk extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -129,7 +133,8 @@ class Autodesk extends OAuth2 * * @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -144,7 +149,8 @@ class Autodesk extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -155,13 +161,14 @@ class Autodesk extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; + $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; $user = $this->request('GET', 'https://developer.api.autodesk.com/userprofile/v1/users/@me', $headers); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Bitbucket.php b/src/Appwrite/Auth/OAuth2/Bitbucket.php index eea5af4c1b..361bc22b65 100644 --- a/src/Appwrite/Auth/OAuth2/Bitbucket.php +++ b/src/Appwrite/Auth/OAuth2/Bitbucket.php @@ -37,7 +37,7 @@ class Bitbucket extends OAuth2 */ public function getLoginURL(): string { - return 'https://bitbucket.org/site/oauth2/authorize?'.\http_build_query([ + return 'https://bitbucket.org/site/oauth2/authorize?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), @@ -46,7 +46,8 @@ class Bitbucket extends OAuth2 } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -62,7 +63,7 @@ class Bitbucket extends OAuth2 'code' => $code, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -71,7 +72,8 @@ class Bitbucket extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -85,7 +87,7 @@ class Bitbucket extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken, + 'refresh_token' => $refreshToken ]) ), true); @@ -97,7 +99,8 @@ class Bitbucket extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -108,7 +111,8 @@ class Bitbucket extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -121,7 +125,8 @@ class Bitbucket extends OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -136,7 +141,8 @@ class Bitbucket extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -147,16 +153,17 @@ class Bitbucket extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token='.\urlencode($accessToken)); + $user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token=' . \urlencode($accessToken)); $this->user = \json_decode($user, true); - $emails = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token='.\urlencode($accessToken)); + $emails = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token=' . \urlencode($accessToken)); $emails = \json_decode($emails, true); if (isset($emails['values'])) { foreach ($emails['values'] as $email) { @@ -168,7 +175,6 @@ class Bitbucket extends OAuth2 } } } - return $this->user; } } diff --git a/src/Appwrite/Auth/OAuth2/Bitly.php b/src/Appwrite/Auth/OAuth2/Bitly.php index b5521cad39..290876a8cb 100644 --- a/src/Appwrite/Auth/OAuth2/Bitly.php +++ b/src/Appwrite/Auth/OAuth2/Bitly.php @@ -47,16 +47,17 @@ class Bitly extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint.'authorize?'. + return $this->endpoint . 'authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -64,14 +65,14 @@ class Bitly extends OAuth2 if (empty($this->tokens)) { $response = $this->request( 'POST', - $this->resourceEndpoint.'oauth/access_token', - ['Content-Type: application/x-www-form-urlencoded'], + $this->resourceEndpoint . 'oauth/access_token', + ["Content-Type: application/x-www-form-urlencoded"], \http_build_query([ - 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, - 'code' => $code, - 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state), + "client_id" => $this->appID, + "client_secret" => $this->appSecret, + "code" => $code, + "redirect_uri" => $this->callback, + "state" => \json_encode($this->state) ]) ); @@ -84,20 +85,21 @@ class Bitly extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $response = $this->request( 'POST', - $this->resourceEndpoint.'oauth/access_token', - ['Content-Type: application/x-www-form-urlencoded'], + $this->resourceEndpoint . 'oauth/access_token', + ["Content-Type: application/x-www-form-urlencoded"], \http_build_query([ - 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, - 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + "client_id" => $this->appID, + "client_secret" => $this->appSecret, + "refresh_token" => $refreshToken, + 'grant_type' => 'refresh_token' ]) ); @@ -113,7 +115,8 @@ class Bitly extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -124,7 +127,8 @@ class Bitly extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -147,7 +151,8 @@ class Bitly extends OAuth2 * * @link https://dev.bitly.com/api-reference#getUser * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -156,7 +161,8 @@ class Bitly extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -167,18 +173,19 @@ class Bitly extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) { $headers = [ - 'Authorization: Bearer '.\urlencode($accessToken), - 'Accept: application/json', + 'Authorization: Bearer ' . \urlencode($accessToken), + "Accept: application/json" ]; if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', $this->resourceEndpoint.'v4/user', $headers), true); + $this->user = \json_decode($this->request('GET', $this->resourceEndpoint . "v4/user", $headers), true); } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Box.php b/src/Appwrite/Auth/OAuth2/Box.php index 5d2c5e2b38..e88c165833 100644 --- a/src/Appwrite/Auth/OAuth2/Box.php +++ b/src/Appwrite/Auth/OAuth2/Box.php @@ -49,7 +49,7 @@ class Box extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint.'authorize?'. + $url = $this->endpoint . 'authorize?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, @@ -62,7 +62,8 @@ class Box extends OAuth2 } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -71,15 +72,15 @@ class Box extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'token', + $this->endpoint . 'token', $headers, \http_build_query([ - 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, - 'code' => $code, - 'grant_type' => 'authorization_code', - 'scope' => \implode(',', $this->getScopes()), - 'redirect_uri' => $this->callback, + "client_id" => $this->appID, + "client_secret" => $this->appSecret, + "code" => $code, + "grant_type" => "authorization_code", + "scope" => \implode(',', $this->getScopes()), + "redirect_uri" => $this->callback ]) ), true); } @@ -88,7 +89,8 @@ class Box extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -96,13 +98,13 @@ class Box extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'token', + $this->endpoint . 'token', $headers, \http_build_query([ - 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, - 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + "client_id" => $this->appID, + "client_secret" => $this->appSecret, + "refresh_token" => $refreshToken, + "grant_type" => "refresh_token", ]) ), true); @@ -114,7 +116,8 @@ class Box extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -125,7 +128,8 @@ class Box extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -140,18 +144,20 @@ class Box extends OAuth2 * * If present, the email is verified. This was verfied through a manual Box sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -162,18 +168,19 @@ class Box extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { $header = [ - 'Authorization: Bearer '.\urlencode($accessToken), + 'Authorization: Bearer ' . \urlencode($accessToken), ]; if (empty($this->user)) { $user = $this->request( 'GET', - $this->resourceEndpoint.'me', + $this->resourceEndpoint . 'me', $header ); $this->user = \json_decode($user, true); diff --git a/src/Appwrite/Auth/OAuth2/Dailymotion.php b/src/Appwrite/Auth/OAuth2/Dailymotion.php index 5ead308fbe..0fc90e3ca1 100644 --- a/src/Appwrite/Auth/OAuth2/Dailymotion.php +++ b/src/Appwrite/Auth/OAuth2/Dailymotion.php @@ -24,7 +24,7 @@ class Dailymotion extends OAuth2 */ protected array $scopes = [ 'userinfo', - 'email', + 'email' ]; /** @@ -34,7 +34,7 @@ class Dailymotion extends OAuth2 'email', 'id', 'fullname', - 'verified', + 'verified' ]; /** @@ -68,20 +68,21 @@ class Dailymotion extends OAuth2 */ public function getLoginURL(): string { - $url = $this->authEndpoint.'?'. + $url = $this->authEndpoint . '?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'state' => \json_encode($this->state), 'redirect_uri' => $this->callback, - 'scope' => \implode(' ', $this->getScopes()), + 'scope' => \implode(' ', $this->getScopes()) ]); return $url; } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -89,31 +90,33 @@ class Dailymotion extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth/token', - ['Content-Type: application/x-www-form-urlencoded'], + $this->endpoint . '/oauth/token', + ["Content-Type: application/x-www-form-urlencoded"], \http_build_query([ 'grant_type' => 'authorization_code', - 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, - 'redirect_uri' => $this->callback, + "client_id" => $this->appID, + "client_secret" => $this->appSecret, + "redirect_uri" => $this->callback, 'code' => $code, 'scope' => \implode(' ', $this->getScopes()), ]) ), true); } - return $this->tokens; } + /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { + $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth/token', + $this->endpoint . '/oauth/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'refresh_token', @@ -127,11 +130,13 @@ class Dailymotion extends OAuth2 $this->tokens['refresh_token'] = $refreshToken; } + return $this->tokens; } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -144,7 +149,8 @@ class Dailymotion extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -160,7 +166,8 @@ class Dailymotion extends OAuth2 * * @link https://developers.dailymotion.com/api/#user-fields * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -171,20 +178,23 @@ class Dailymotion extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string { $user = $this->getUser($accessToken); + $username = $user['fullname'] ?? ''; return $username; } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array @@ -192,8 +202,8 @@ class Dailymotion extends OAuth2 if (empty($this->user)) { $user = $this->request( 'GET', - $this->endpoint.'/user/me?fields='.\implode(',', $this->getFields()), - ['Authorization: Bearer '.\urlencode($accessToken)], + $this->endpoint . '/user/me?fields=' . \implode(',', $this->getFields()), + ['Authorization: Bearer ' . \urlencode($accessToken)], ); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Discord.php b/src/Appwrite/Auth/OAuth2/Discord.php index b98d5bdc0c..b77ce6a236 100644 --- a/src/Appwrite/Auth/OAuth2/Discord.php +++ b/src/Appwrite/Auth/OAuth2/Discord.php @@ -28,8 +28,8 @@ class Discord extends OAuth2 * @var array */ protected array $scopes = [ - 'identify', - 'email', + 'identify', + 'email' ]; /** @@ -45,20 +45,21 @@ class Discord extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint.'/oauth2/authorize?'. + $url = $this->endpoint . '/oauth2/authorize?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), - 'redirect_uri' => $this->callback, + 'redirect_uri' => $this->callback ]); return $url; } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -66,7 +67,7 @@ class Discord extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth2/token', + $this->endpoint . '/oauth2/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'authorization_code', @@ -74,7 +75,7 @@ class Discord extends OAuth2 'redirect_uri' => $this->callback, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, - 'scope' => \implode(' ', $this->getScopes()), + 'scope' => \implode(' ', $this->getScopes()) ]) ), true); } @@ -83,14 +84,15 @@ class Discord extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth2/token', + $this->endpoint . '/oauth2/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'refresh_token', @@ -108,7 +110,8 @@ class Discord extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -119,7 +122,8 @@ class Discord extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -134,7 +138,8 @@ class Discord extends OAuth2 * * @link https://discord.com/developers/docs/resources/user * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -149,7 +154,8 @@ class Discord extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -160,7 +166,8 @@ class Discord extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array @@ -168,8 +175,8 @@ class Discord extends OAuth2 if (empty($this->user)) { $user = $this->request( 'GET', - $this->endpoint.'/users/@me', - ['Authorization: Bearer '.\urlencode($accessToken)] + $this->endpoint . '/users/@me', + ['Authorization: Bearer ' . \urlencode($accessToken)] ); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Disqus.php b/src/Appwrite/Auth/OAuth2/Disqus.php index eb657298cd..58b7f48914 100644 --- a/src/Appwrite/Auth/OAuth2/Disqus.php +++ b/src/Appwrite/Auth/OAuth2/Disqus.php @@ -45,20 +45,21 @@ class Disqus extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint.'oauth/2.0/authorize/?'. + $url = $this->endpoint . 'oauth/2.0/authorize/?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'state' => \json_encode($this->state), 'redirect_uri' => $this->callback, - 'scope' => \implode(',', $this->getScopes()), + 'scope' => \implode(',', $this->getScopes()) ]); return $url; } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -66,7 +67,7 @@ class Disqus extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'oauth/2.0/access_token/', + $this->endpoint . 'oauth/2.0/access_token/', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'authorization_code', @@ -78,19 +79,19 @@ class Disqus extends OAuth2 ]) ), true); } - return $this->tokens; } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'oauth/2.0/access_token/?', + $this->endpoint . 'oauth/2.0/access_token/?', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'refresh_token', @@ -103,12 +104,12 @@ class Disqus extends OAuth2 if (empty($this->tokens['refresh_token'])) { $this->tokens['refresh_token'] = $refreshToken; } - return $this->tokens; } /** - * @param string $token + * @param string $token + * * @return string */ public function getUserID(string $accessToken): string @@ -121,7 +122,8 @@ class Disqus extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -134,11 +136,13 @@ class Disqus extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { + // Look out for the change in their enpoint. // It's in Beta so they may provide a parameter in the future. // https://disqus.com/api/docs/users/details/ @@ -147,7 +151,8 @@ class Disqus extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -160,7 +165,8 @@ class Disqus extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array @@ -168,10 +174,10 @@ class Disqus extends OAuth2 if (empty($this->user)) { $user = $this->request( 'GET', - $this->endpoint.'3.0/users/details.json?'.\http_build_query([ + $this->endpoint . '3.0/users/details.json?' . \http_build_query([ 'access_token' => $accessToken, 'api_key' => $this->appID, - 'api_secret' => $this->appSecret, + 'api_secret' => $this->appSecret ]), ); $this->user = \json_decode($user, true)['response']; diff --git a/src/Appwrite/Auth/OAuth2/Dropbox.php b/src/Appwrite/Auth/OAuth2/Dropbox.php index 156f93e0ee..ff30b87d8a 100644 --- a/src/Appwrite/Auth/OAuth2/Dropbox.php +++ b/src/Appwrite/Auth/OAuth2/Dropbox.php @@ -38,16 +38,17 @@ class Dropbox extends OAuth2 */ public function getLoginURL(): string { - return 'https://www.dropbox.com/oauth2/authorize?'.\http_build_query([ + return 'https://www.dropbox.com/oauth2/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), - 'response_type' => 'code', + 'response_type' => 'code' ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -63,7 +64,7 @@ class Dropbox extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'redirect_uri' => $this->callback, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -72,7 +73,8 @@ class Dropbox extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -86,7 +88,7 @@ class Dropbox extends OAuth2 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -98,7 +100,8 @@ class Dropbox extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -109,7 +112,8 @@ class Dropbox extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -124,7 +128,8 @@ class Dropbox extends OAuth2 * * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -139,7 +144,8 @@ class Dropbox extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -150,13 +156,14 @@ class Dropbox extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; + $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; $user = $this->request('POST', 'https://api.dropboxapi.com/2/users/get_current_account', $headers); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Etsy.php b/src/Appwrite/Auth/OAuth2/Etsy.php index 7316cdc1d5..7ff16fcb78 100644 --- a/src/Appwrite/Auth/OAuth2/Etsy.php +++ b/src/Appwrite/Auth/OAuth2/Etsy.php @@ -30,8 +30,8 @@ class Etsy extends OAuth2 * @var array */ protected array $scopes = [ - 'email_r', - 'profile_r', + "email_r", + "profile_r", ]; /** @@ -64,7 +64,7 @@ class Etsy extends OAuth2 */ public function getLoginURL(): string { - return 'https://www.etsy.com/oauth/connect/oauth/authorize?'.\http_build_query([ + return 'https://www.etsy.com/oauth/connect/oauth/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'response_type' => 'code', @@ -76,7 +76,8 @@ class Etsy extends OAuth2 } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -86,7 +87,7 @@ class Etsy extends OAuth2 $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth/token', + $this->endpoint . '/oauth/token', $headers, \http_build_query([ 'grant_type' => 'authorization_code', @@ -102,7 +103,8 @@ class Etsy extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -111,7 +113,7 @@ class Etsy extends OAuth2 $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth/token', + $this->endpoint . '/oauth/token', $headers, \http_build_query([ 'grant_type' => 'refresh_token', @@ -129,6 +131,7 @@ class Etsy extends OAuth2 /** * @param $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -140,6 +143,7 @@ class Etsy extends OAuth2 /** * @param $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -152,18 +156,20 @@ class Etsy extends OAuth2 * * OAuth is only allowed if account has been verified through Etsy, itself. * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** * @param $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -172,20 +178,21 @@ class Etsy extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { - if (! empty($this->user)) { + if (!empty($this->user)) { return $this->user; } - $headers = ['Authorization: Bearer '.$accessToken]; + $headers = ['Authorization: Bearer ' . $accessToken]; $this->user = \json_decode($this->request( 'GET', - 'https://api.etsy.com/v3/application/users/'.$this->getUserID($accessToken), + 'https://api.etsy.com/v3/application/users/' . $this->getUserID($accessToken), ), true); return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Exception.php b/src/Appwrite/Auth/OAuth2/Exception.php index eddab9d400..3d5b79d3b0 100644 --- a/src/Appwrite/Auth/OAuth2/Exception.php +++ b/src/Appwrite/Auth/OAuth2/Exception.php @@ -7,9 +7,7 @@ use Appwrite\Extend\Exception as AppwriteException; class Exception extends AppwriteException { protected string $response = ''; - protected string $error = ''; - protected string $errorDescription = ''; public function __construct(string $response = '', int $code = 0, \Throwable $previous = null) @@ -21,11 +19,11 @@ class Exception extends AppwriteException if (\is_array($decoded['error'])) { $this->error = $decoded['error']['status']; $this->errorDescription = $decoded['error']['message']; - $this->message = $this->error.': '.$this->errorDescription; + $this->message = $this->error . ': ' . $this->errorDescription; } else { $this->error = $decoded['error']; $this->errorDescription = $decoded['error_description']; - $this->message = $this->error.': '.$this->errorDescription; + $this->message = $this->error . ': ' . $this->errorDescription; } } $type = match ($code) { diff --git a/src/Appwrite/Auth/OAuth2/Facebook.php b/src/Appwrite/Auth/OAuth2/Facebook.php index 9b10f3be80..90fe8e7388 100644 --- a/src/Appwrite/Auth/OAuth2/Facebook.php +++ b/src/Appwrite/Auth/OAuth2/Facebook.php @@ -25,7 +25,7 @@ class Facebook extends OAuth2 * @var array */ protected array $scopes = [ - 'email', + 'email' ]; /** @@ -41,16 +41,17 @@ class Facebook extends OAuth2 */ public function getLoginURL(): string { - return 'https://www.facebook.com/'.$this->version.'/dialog/oauth?'.\http_build_query([ + return 'https://www.facebook.com/' . $this->version . '/dialog/oauth?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -58,11 +59,11 @@ class Facebook extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'GET', - 'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'.\http_build_query([ + 'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, - 'code' => $code, + 'code' => $code ]) ), true); } @@ -71,19 +72,20 @@ class Facebook extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'GET', - 'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'.\http_build_query([ + 'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -95,7 +97,8 @@ class Facebook extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -106,7 +109,8 @@ class Facebook extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -121,18 +125,20 @@ class Facebook extends OAuth2 * * If present, the email is verified. This was verfied through a manual Facebook sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -143,13 +149,14 @@ class Facebook extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://graph.facebook.com/'.$this->version.'/me?fields=email,name&access_token='.\urlencode($accessToken)); + $user = $this->request('GET', 'https://graph.facebook.com/' . $this->version . '/me?fields=email,name&access_token=' . \urlencode($accessToken)); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Firebase.php b/src/Appwrite/Auth/OAuth2/Firebase.php index 96638e83a3..0a813881be 100644 --- a/src/Appwrite/Auth/OAuth2/Firebase.php +++ b/src/Appwrite/Auth/OAuth2/Firebase.php @@ -24,7 +24,7 @@ class Firebase extends OAuth2 'https://www.googleapis.com/auth/datastore', 'https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/identitytoolkit', - 'https://www.googleapis.com/auth/userinfo.profile', + 'https://www.googleapis.com/auth/userinfo.profile' ]; /** @@ -40,7 +40,7 @@ class Firebase extends OAuth2 */ public function getLoginURL(): string { - return 'https://accounts.google.com/o/oauth2/v2/auth?'.\http_build_query([ + return 'https://accounts.google.com/o/oauth2/v2/auth?' . \http_build_query([ 'access_type' => 'offline', 'client_id' => $this->appID, 'redirect_uri' => $this->callback, @@ -52,7 +52,8 @@ class Firebase extends OAuth2 } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -67,18 +68,19 @@ class Firebase extends OAuth2 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, 'code' => $code, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ); - $this->tokens = \json_decode($response, true); + $this->tokens = \json_decode($response, true); } return $this->tokens; } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -91,7 +93,7 @@ class Firebase extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken, + 'refresh_token' => $refreshToken ]) ); @@ -106,8 +108,10 @@ class Firebase extends OAuth2 return $this->tokens; } + /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -118,7 +122,8 @@ class Firebase extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -128,12 +133,14 @@ class Firebase extends OAuth2 return $user['email'] ?? ''; } + /** * Check if the OAuth email is verified * * @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -148,7 +155,8 @@ class Firebase extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -159,7 +167,8 @@ class Firebase extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) @@ -167,7 +176,7 @@ class Firebase extends OAuth2 if (empty($this->user)) { $response = $this->request( 'GET', - 'https://www.googleapis.com/oauth2/v1/userinfo?access_token='.\urlencode($accessToken), + 'https://www.googleapis.com/oauth2/v1/userinfo?access_token=' . \urlencode($accessToken), [], ); @@ -179,7 +188,7 @@ class Firebase extends OAuth2 public function getProjects(string $accessToken): array { - $projects = $this->request('GET', 'https://firebase.googleapis.com/v1beta1/projects', ['Authorization: Bearer '.\urlencode($accessToken)]); + $projects = $this->request('GET', 'https://firebase.googleapis.com/v1beta1/projects', ['Authorization: Bearer ' . \urlencode($accessToken)]); $projects = \json_decode($projects, true); @@ -192,9 +201,9 @@ class Firebase extends OAuth2 public function assignIAMRoles(string $accessToken, string $email, string $projectId) { // Get IAM Roles - $iamRoles = $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/'.$projectId.':getIamPolicy', [ - 'Authorization: Bearer '.\urlencode($accessToken), - 'Content-Type: application/json', + $iamRoles = $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/' . $projectId . ':getIamPolicy', [ + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' ]); $iamRoles = \json_decode($iamRoles, true); @@ -202,23 +211,23 @@ class Firebase extends OAuth2 $iamRoles['bindings'][] = [ 'role' => 'roles/identitytoolkit.admin', 'members' => [ - 'serviceAccount:'.$email, - ], + 'serviceAccount:' . $email + ] ]; $iamRoles['bindings'][] = [ 'role' => 'roles/firebase.admin', 'members' => [ - 'serviceAccount:'.$email, - ], + 'serviceAccount:' . $email + ] ]; // Set IAM Roles - $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/'.$projectId.':setIamPolicy', [ - 'Authorization: Bearer '.\urlencode($accessToken), - 'Content-Type: application/json', + $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/' . $projectId . ':setIamPolicy', [ + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' ], json_encode([ - 'policy' => $iamRoles, + 'policy' => $iamRoles ])); } @@ -227,16 +236,16 @@ class Firebase extends OAuth2 // Create Service Account $response = $this->request( 'POST', - 'https://iam.googleapis.com/v1/projects/'.$projectId.'/serviceAccounts', + 'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts', [ - 'Authorization: Bearer '.\urlencode($accessToken), - 'Content-Type: application/json', + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' ], json_encode([ 'accountId' => 'appwrite-migrations', 'serviceAccount' => [ - 'displayName' => 'Appwrite Migrations', - ], + 'displayName' => 'Appwrite Migrations' + ] ]) ); @@ -247,10 +256,10 @@ class Firebase extends OAuth2 // Create Service Account Key $responseKey = $this->request( 'POST', - 'https://iam.googleapis.com/v1/projects/'.$projectId.'/serviceAccounts/'.$response['email'].'/keys', + 'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts/' . $response['email'] . '/keys', [ - 'Authorization: Bearer '.\urlencode($accessToken), - 'Content-Type: application/json', + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' ] ); diff --git a/src/Appwrite/Auth/OAuth2/Github.php b/src/Appwrite/Auth/OAuth2/Github.php index ab67e17aa0..8b9208fc06 100644 --- a/src/Appwrite/Auth/OAuth2/Github.php +++ b/src/Appwrite/Auth/OAuth2/Github.php @@ -36,16 +36,17 @@ class Github extends OAuth2 */ public function getLoginURL(): string { - return 'https://github.com/login/oauth/authorize?'.\http_build_query([ + return 'https://github.com/login/oauth/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -59,7 +60,7 @@ class Github extends OAuth2 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, - 'code' => $code, + 'code' => $code ]) ); @@ -72,7 +73,8 @@ class Github extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -85,7 +87,7 @@ class Github extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken, + 'refresh_token' => $refreshToken ]) ); @@ -101,7 +103,8 @@ class Github extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -112,7 +115,8 @@ class Github extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -127,7 +131,8 @@ class Github extends OAuth2 * * @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -142,7 +147,8 @@ class Github extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -153,7 +159,8 @@ class Github extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserSlug(string $accessToken): string @@ -164,15 +171,16 @@ class Github extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) { if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token '.\urlencode($accessToken)]), true); + $this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token ' . \urlencode($accessToken)]), true); - $emails = $this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token '.\urlencode($accessToken)]); + $emails = $this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token ' . \urlencode($accessToken)]); $emails = \json_decode($emails, true); @@ -189,10 +197,10 @@ class Github extends OAuth2 } } - if (! empty($primaryEmail)) { + if (!empty($primaryEmail)) { $this->user['email'] = $primaryEmail['email']; $this->user['verified'] = $primaryEmail['verified']; - } elseif (! empty($verifiedEmail)) { + } elseif (!empty($verifiedEmail)) { $this->user['email'] = $verifiedEmail['email']; $this->user['verified'] = $verifiedEmail['verified']; } diff --git a/src/Appwrite/Auth/OAuth2/Gitlab.php b/src/Appwrite/Auth/OAuth2/Gitlab.php index f96348c98b..7d98bf1921 100644 --- a/src/Appwrite/Auth/OAuth2/Gitlab.php +++ b/src/Appwrite/Auth/OAuth2/Gitlab.php @@ -23,7 +23,7 @@ class Gitlab extends OAuth2 * @var array */ protected array $scopes = [ - 'read_user', + 'read_user' ]; /** @@ -39,17 +39,18 @@ class Gitlab extends OAuth2 */ public function getLoginURL(): string { - return $this->getEndpoint().'/oauth/authorize?'.\http_build_query([ + return $this->getEndpoint() . '/oauth/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state), - 'response_type' => 'code', + 'response_type' => 'code' ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -57,12 +58,12 @@ class Gitlab extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->getEndpoint().'/oauth/token?'.\http_build_query([ + $this->getEndpoint() . '/oauth/token?' . \http_build_query([ 'code' => $code, 'client_id' => $this->appID, 'client_secret' => $this->getAppSecret()['clientSecret'], 'redirect_uri' => $this->callback, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -71,18 +72,19 @@ class Gitlab extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->getEndpoint().'/oauth/token?'.\http_build_query([ + $this->getEndpoint() . '/oauth/token?' . \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getAppSecret()['clientSecret'], - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -94,7 +96,8 @@ class Gitlab extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -109,7 +112,8 @@ class Gitlab extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -124,7 +128,8 @@ class Gitlab extends OAuth2 * * @link https://docs.gitlab.com/ee/api/users.html#list-current-user-for-normal-users * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -139,7 +144,8 @@ class Gitlab extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -150,13 +156,14 @@ class Gitlab extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', $this->getEndpoint().'/api/v4/user?access_token='.\urlencode($accessToken)); + $user = $this->request('GET', $this->getEndpoint() . '/api/v4/user?access_token=' . \urlencode($accessToken)); $this->user = \json_decode($user, true); } @@ -175,10 +182,10 @@ class Gitlab extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } - return $secret; } + /** * Extracts the Tenant Id from the JSON stored in appSecret. Defaults to 'common' as a fallback * @@ -189,7 +196,6 @@ class Gitlab extends OAuth2 $defaultEndpoint = 'https://gitlab.com'; $secret = $this->getAppSecret(); $endpoint = $secret['endpoint'] ?? $defaultEndpoint; - return empty($endpoint) ? $defaultEndpoint : $endpoint; } } diff --git a/src/Appwrite/Auth/OAuth2/Google.php b/src/Appwrite/Auth/OAuth2/Google.php index c56f1660c4..c6f621b814 100644 --- a/src/Appwrite/Auth/OAuth2/Google.php +++ b/src/Appwrite/Auth/OAuth2/Google.php @@ -22,7 +22,7 @@ class Google extends OAuth2 protected array $scopes = [ 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', - 'openid', + 'openid' ]; /** @@ -48,17 +48,18 @@ class Google extends OAuth2 */ public function getLoginURL(): string { - return 'https://accounts.google.com/o/oauth2/v2/auth?'.\http_build_query([ + return 'https://accounts.google.com/o/oauth2/v2/auth?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state), - 'response_type' => 'code', + 'response_type' => 'code' ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -66,13 +67,13 @@ class Google extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - 'https://oauth2.googleapis.com/token?'.\http_build_query([ + 'https://oauth2.googleapis.com/token?' . \http_build_query([ 'code' => $code, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'redirect_uri' => $this->callback, 'scope' => null, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -81,18 +82,19 @@ class Google extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - 'https://oauth2.googleapis.com/token?'.\http_build_query([ + 'https://oauth2.googleapis.com/token?' . \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->appSecret, - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -104,7 +106,8 @@ class Google extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -115,7 +118,8 @@ class Google extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -130,7 +134,8 @@ class Google extends OAuth2 * * @link https://www.oauth.com/oauth2-servers/signing-in-with-google/verifying-the-user-info/ * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -145,7 +150,8 @@ class Google extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -156,13 +162,14 @@ class Google extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://www.googleapis.com/oauth2/v3/userinfo?access_token='.\urlencode($accessToken)); + $user = $this->request('GET', 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' . \urlencode($accessToken)); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Linkedin.php b/src/Appwrite/Auth/OAuth2/Linkedin.php index c4e899b5ca..340cab2df0 100644 --- a/src/Appwrite/Auth/OAuth2/Linkedin.php +++ b/src/Appwrite/Auth/OAuth2/Linkedin.php @@ -50,7 +50,7 @@ class Linkedin extends OAuth2 */ public function getLoginURL(): string { - return 'https://www.linkedin.com/oauth/v2/authorization?'.\http_build_query([ + return 'https://www.linkedin.com/oauth/v2/authorization?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'redirect_uri' => $this->callback, @@ -60,7 +60,8 @@ class Linkedin extends OAuth2 } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -79,12 +80,12 @@ class Linkedin extends OAuth2 ]) ), true); } - return $this->tokens; } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -105,12 +106,12 @@ class Linkedin extends OAuth2 if (empty($this->tokens['refresh_token'])) { $this->tokens['refresh_token'] = $refreshToken; } - return $this->tokens; } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -121,12 +122,13 @@ class Linkedin extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string { - $email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer '.\urlencode($accessToken)]), true); + $email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer ' . \urlencode($accessToken)]), true); return $email['elements'][0]['handle~']['emailAddress'] ?? ''; } @@ -136,18 +138,20 @@ class Linkedin extends OAuth2 * * If present, the email is verified. This was verfied through a manual Linkedin sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -160,20 +164,21 @@ class Linkedin extends OAuth2 } if (isset($user['localizedLastName'])) { - $name = (empty($name)) ? $user['localizedLastName'] : $name.' '.$user['localizedLastName']; + $name = (empty($name)) ? $user['localizedLastName'] : $name . ' ' . $user['localizedLastName']; } return $name; } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) { if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer '.\urlencode($accessToken)]), true); + $this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer ' . \urlencode($accessToken)]), true); } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Microsoft.php b/src/Appwrite/Auth/OAuth2/Microsoft.php index 89b77c1925..bc05843b37 100644 --- a/src/Appwrite/Auth/OAuth2/Microsoft.php +++ b/src/Appwrite/Auth/OAuth2/Microsoft.php @@ -25,7 +25,7 @@ class Microsoft extends OAuth2 */ protected array $scopes = [ 'offline_access', - 'user.read', + 'user.read' ]; /** @@ -41,18 +41,19 @@ class Microsoft extends OAuth2 */ public function getLoginURL(): string { - return 'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/authorize?'.\http_build_query([ + return 'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), 'response_type' => 'code', - 'response_mode' => 'query', + 'response_mode' => 'query' ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -61,7 +62,7 @@ class Microsoft extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/token', + 'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/token', $headers, \http_build_query([ 'code' => $code, @@ -69,7 +70,7 @@ class Microsoft extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -78,7 +79,8 @@ class Microsoft extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -86,13 +88,13 @@ class Microsoft extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/token', + 'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/token', $headers, \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -104,7 +106,8 @@ class Microsoft extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -115,7 +118,8 @@ class Microsoft extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -130,18 +134,20 @@ class Microsoft extends OAuth2 * * If present, the email is verified. This was verfied through a manual Microsoft sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -152,13 +158,14 @@ class Microsoft extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; + $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; $user = $this->request('GET', 'https://graph.microsoft.com/v1.0/me', $headers); $this->user = \json_decode($user, true); } @@ -178,7 +185,6 @@ class Microsoft extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } - return $secret; } diff --git a/src/Appwrite/Auth/OAuth2/Mock.php b/src/Appwrite/Auth/OAuth2/Mock.php index b0b2e3b8d1..d2cb8c1c2a 100644 --- a/src/Appwrite/Auth/OAuth2/Mock.php +++ b/src/Appwrite/Auth/OAuth2/Mock.php @@ -3,6 +3,7 @@ namespace Appwrite\Auth\OAuth2; use Appwrite\Auth\OAuth2; +use Utopia\Exception; class Mock extends OAuth2 { @@ -15,7 +16,7 @@ class Mock extends OAuth2 * @var array */ protected array $scopes = [ - 'email', + 'email' ]; /** @@ -41,16 +42,17 @@ class Mock extends OAuth2 */ public function getLoginURL(): string { - return 'http://localhost/'.$this->version.'/mock/tests/general/oauth2?'.\http_build_query([ + return 'http://localhost/' . $this->version . '/mock/tests/general/oauth2?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -58,12 +60,12 @@ class Mock extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'GET', - 'http://localhost/'.$this->version.'/mock/tests/general/oauth2/token?'. + 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, - 'code' => $code, + 'code' => $code ]) ), true); } @@ -72,19 +74,20 @@ class Mock extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'GET', - 'http://localhost/'.$this->version.'/mock/tests/general/oauth2/token?'. + 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' . \http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -96,7 +99,8 @@ class Mock extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -107,7 +111,8 @@ class Mock extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -120,7 +125,8 @@ class Mock extends OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -129,7 +135,8 @@ class Mock extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -140,13 +147,14 @@ class Mock extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'http://localhost/'.$this->version.'/mock/tests/general/oauth2/user?token='.\urlencode($accessToken)); + $user = $this->request('GET', 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/user?token=' . \urlencode($accessToken)); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Notion.php b/src/Appwrite/Auth/OAuth2/Notion.php index 17c1dd7f18..c2f1ee98e4 100644 --- a/src/Appwrite/Auth/OAuth2/Notion.php +++ b/src/Appwrite/Auth/OAuth2/Notion.php @@ -44,31 +44,32 @@ class Notion extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint.'/oauth/authorize?'.\http_build_query([ + return $this->endpoint . '/oauth/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'response_type' => 'code', 'state' => \json_encode($this->state), - 'owner' => 'user', + 'owner' => 'user' ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { - $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)]; + $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth/token', + $this->endpoint . '/oauth/token', $headers, \http_build_query([ 'grant_type' => 'authorization_code', 'redirect_uri' => $this->callback, - 'code' => $code, + 'code' => $code ]) ), true); } @@ -77,15 +78,16 @@ class Notion extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { - $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)]; + $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth/token', + $this->endpoint . '/oauth/token', $headers, \http_build_query([ 'grant_type' => 'refresh_token', @@ -101,7 +103,8 @@ class Notion extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -112,7 +115,8 @@ class Notion extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -127,18 +131,20 @@ class Notion extends OAuth2 * * If present, the email is verified. This was verfied through a manual Notion sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -149,18 +155,19 @@ class Notion extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { $headers = [ - 'Notion-Version: '.$this->version, - 'Authorization: Bearer '.\urlencode($accessToken), + 'Notion-Version: ' . $this->version, + 'Authorization: Bearer ' . \urlencode($accessToken) ]; if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', $this->endpoint.'/users/me', $headers), true); + $this->user = \json_decode($this->request('GET', $this->endpoint . '/users/me', $headers), true); } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Oidc.php b/src/Appwrite/Auth/OAuth2/Oidc.php index dfdf9aeff0..de2eab65c8 100644 --- a/src/Appwrite/Auth/OAuth2/Oidc.php +++ b/src/Appwrite/Auth/OAuth2/Oidc.php @@ -43,7 +43,7 @@ class Oidc extends OAuth2 */ public function getLoginURL(): string { - return $this->getAuthorizationEndpoint().'?'.\http_build_query([ + return $this->getAuthorizationEndpoint() . '?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), @@ -53,7 +53,8 @@ class Oidc extends OAuth2 } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -70,16 +71,17 @@ class Oidc extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } - return $this->tokens; } + /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -93,7 +95,7 @@ class Oidc extends OAuth2 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -105,7 +107,8 @@ class Oidc extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -120,7 +123,8 @@ class Oidc extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -137,7 +141,8 @@ class Oidc extends OAuth2 /** * Check if the User email is verified * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -148,7 +153,8 @@ class Oidc extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -162,14 +168,15 @@ class Oidc extends OAuth2 return ''; } - /** - * @param string $accessToken + /** + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; + $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; $user = $this->request('GET', $this->getUserinfoEndpoint(), $headers); $this->user = \json_decode($user, true); } @@ -189,7 +196,7 @@ class Oidc extends OAuth2 return $secret['clientSecret'] ?? ''; } - /** + /** * Extracts the well known endpoint from the JSON stored in appSecret. * * @return string @@ -197,14 +204,13 @@ class Oidc extends OAuth2 protected function getWellKnownEndpoint(): string { $secret = $this->getAppSecret(); - return $secret['wellKnownEndpoint'] ?? ''; } /** - * Extracts the authorization endpoint from the JSON stored in appSecret. - * - * If one is not provided, it will be retrieved from the well-known configuration. + * Extracts the authorization endpoint from the JSON stored in appSecret. + * + * If one is not provided, it will be retrieved from the well-known configuration. * * @return string */ @@ -213,59 +219,56 @@ class Oidc extends OAuth2 $secret = $this->getAppSecret(); $endpoint = $secret['authorizationEndpoint'] ?? ''; - if (! empty($endpoint)) { + if (!empty($endpoint)) { return $endpoint; } $wellKnownConfiguration = $this->getWellKnownConfiguration(); - return $wellKnownConfiguration['authorization_endpoint'] ?? ''; } /** - * Extracts the token endpoint from the JSON stored in appSecret. - * - * If one is not provided, it will be retrieved from the well-known configuration. - * - * @return string - */ + * Extracts the token endpoint from the JSON stored in appSecret. + * + * If one is not provided, it will be retrieved from the well-known configuration. + * + * @return string + */ protected function getTokenEndpoint(): string { $secret = $this->getAppSecret(); $endpoint = $secret['tokenEndpoint'] ?? ''; - if (! empty($endpoint)) { + if (!empty($endpoint)) { return $endpoint; } $wellKnownConfiguration = $this->getWellKnownConfiguration(); - return $wellKnownConfiguration['token_endpoint'] ?? ''; } /** - * Extracts the userinfo endpoint from the JSON stored in appSecret. - * - * If one is not provided, it will be retrieved from the well-known configuration. - * - * @return string - */ + * Extracts the userinfo endpoint from the JSON stored in appSecret. + * + * If one is not provided, it will be retrieved from the well-known configuration. + * + * @return string + */ protected function getUserinfoEndpoint(): string { $secret = $this->getAppSecret(); $endpoint = $secret['userinfoEndpoint'] ?? ''; - if (! empty($endpoint)) { + if (!empty($endpoint)) { return $endpoint; } $wellKnownConfiguration = $this->getWellKnownConfiguration(); - return $wellKnownConfiguration['userinfo_endpoint'] ?? ''; } - /** - * Get the well-known configuration using the well known endpoint - */ + /** + * Get the well-known configuration using the well known endpoint + */ protected function getWellKnownConfiguration(): array { if (empty($this->wellKnownConfiguration)) { @@ -288,7 +291,6 @@ class Oidc extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } - return $secret; } } diff --git a/src/Appwrite/Auth/OAuth2/Okta.php b/src/Appwrite/Auth/OAuth2/Okta.php index 367c64e764..610d9847f2 100644 --- a/src/Appwrite/Auth/OAuth2/Okta.php +++ b/src/Appwrite/Auth/OAuth2/Okta.php @@ -16,7 +16,7 @@ class Okta extends OAuth2 'openid', 'profile', 'email', - 'offline_access', + 'offline_access' ]; /** @@ -42,17 +42,18 @@ class Okta extends OAuth2 */ public function getLoginURL(): string { - return 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/authorize?'.\http_build_query([ + return 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'state' => \json_encode($this->state), 'scope' => \implode(' ', $this->getScopes()), - 'response_type' => 'code', + 'response_type' => 'code' ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -61,7 +62,7 @@ class Okta extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token', + 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token', $headers, \http_build_query([ 'code' => $code, @@ -69,7 +70,7 @@ class Okta extends OAuth2 'client_secret' => $this->getClientSecret(), 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -77,8 +78,10 @@ class Okta extends OAuth2 return $this->tokens; } + /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -86,13 +89,13 @@ class Okta extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token', + 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token', $headers, \http_build_query([ 'refresh_token' => $refreshToken, 'client_id' => $this->appID, 'client_secret' => $this->getClientSecret(), - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -104,7 +107,8 @@ class Okta extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -115,7 +119,8 @@ class Okta extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -130,7 +135,8 @@ class Okta extends OAuth2 * * @link https://developer.okta.com/docs/reference/api/oidc/#userinfo * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -145,7 +151,8 @@ class Okta extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -156,14 +163,15 @@ class Okta extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; - $user = $this->request('GET', 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/userinfo', $headers); + $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $user = $this->request('GET', 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/userinfo', $headers); $this->user = \json_decode($user, true); } @@ -218,7 +226,6 @@ class Okta extends OAuth2 } catch (\Throwable $th) { throw new \Exception('Invalid secret'); } - return $secret; } } diff --git a/src/Appwrite/Auth/OAuth2/Paypal.php b/src/Appwrite/Auth/OAuth2/Paypal.php index e55ed05ac4..5d5bd0a06f 100644 --- a/src/Appwrite/Auth/OAuth2/Paypal.php +++ b/src/Appwrite/Auth/OAuth2/Paypal.php @@ -46,7 +46,7 @@ class Paypal extends OAuth2 protected array $scopes = [ 'openid', 'profile', - 'email', + 'email' ]; /** @@ -62,14 +62,14 @@ class Paypal extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint[$this->environment].'connect/?'. + $url = $this->endpoint[$this->environment] . 'connect/?' . \http_build_query([ 'flowEntry' => 'static', 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), // paypal is not accepting localhost string into return uri - 'redirect_uri' => \str_replace('localhost', '127.0.0.1', $this->callback), + 'redirect_uri' => \str_replace("localhost", "127.0.0.1", $this->callback), 'state' => \json_encode($this->state), ]); @@ -77,7 +77,8 @@ class Paypal extends OAuth2 } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -85,8 +86,8 @@ class Paypal extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->resourceEndpoint[$this->environment].'oauth2/token', - ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)], + $this->resourceEndpoint[$this->environment] . 'oauth2/token', + ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)], \http_build_query([ 'code' => $code, 'grant_type' => 'authorization_code', @@ -98,15 +99,16 @@ class Paypal extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->resourceEndpoint[$this->environment].'oauth2/token', - ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)], + $this->resourceEndpoint[$this->environment] . 'oauth2/token', + ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)], \http_build_query([ 'refresh_token' => $refreshToken, 'grant_type' => 'refresh_token', @@ -121,7 +123,8 @@ class Paypal extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -132,7 +135,8 @@ class Paypal extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -144,7 +148,7 @@ class Paypal extends OAuth2 return $email['primary'] === true; }); - if (! empty($email)) { + if (!empty($email)) { return $email[0]['value']; } } @@ -157,7 +161,8 @@ class Paypal extends OAuth2 * * @link https://developer.paypal.com/docs/api/identity/v1/#userinfo_get * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -172,7 +177,8 @@ class Paypal extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -183,19 +189,20 @@ class Paypal extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { $header = [ 'Content-Type: application/json', - 'Authorization: Bearer '.\urlencode($accessToken), + 'Authorization: Bearer ' . \urlencode($accessToken), ]; if (empty($this->user)) { $user = $this->request( 'GET', - $this->resourceEndpoint[$this->environment].'identity/oauth2/userinfo?schema=paypalv1.1', + $this->resourceEndpoint[$this->environment] . 'identity/oauth2/userinfo?schema=paypalv1.1', $header ); $this->user = \json_decode($user, true); diff --git a/src/Appwrite/Auth/OAuth2/PaypalSandbox.php b/src/Appwrite/Auth/OAuth2/PaypalSandbox.php index e5ab612c0d..0f56a09c21 100644 --- a/src/Appwrite/Auth/OAuth2/PaypalSandbox.php +++ b/src/Appwrite/Auth/OAuth2/PaypalSandbox.php @@ -2,6 +2,8 @@ namespace Appwrite\Auth\OAuth2; +use Appwrite\Auth\OAuth2\Paypal; + class PaypalSandbox extends Paypal { protected string $environment = 'sandbox'; diff --git a/src/Appwrite/Auth/OAuth2/Podio.php b/src/Appwrite/Auth/OAuth2/Podio.php index f3ba81968e..e4194238d1 100644 --- a/src/Appwrite/Auth/OAuth2/Podio.php +++ b/src/Appwrite/Auth/OAuth2/Podio.php @@ -51,18 +51,19 @@ class Podio extends OAuth2 */ public function getLoginURL(): string { - $url = $this->endpoint.'/authorize?'. + $url = $this->endpoint . '/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'state' => \json_encode($this->state), - 'redirect_uri' => $this->callback, + 'redirect_uri' => $this->callback ]); return $url; } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -70,14 +71,14 @@ class Podio extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->apiEndpoint.'/oauth/token', + $this->apiEndpoint . '/oauth/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'authorization_code', 'code' => $code, 'redirect_uri' => $this->callback, 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, + 'client_secret' => $this->appSecret ]) ), true); } @@ -86,14 +87,15 @@ class Podio extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->apiEndpoint.'/oauth/token', + $this->apiEndpoint . '/oauth/token', ['Content-Type: application/x-www-form-urlencoded'], \http_build_query([ 'grant_type' => 'refresh_token', @@ -111,7 +113,8 @@ class Podio extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -122,7 +125,8 @@ class Podio extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -135,7 +139,8 @@ class Podio extends OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -143,7 +148,7 @@ class Podio extends OAuth2 $user = $this->getUser($accessToken); $mails = $user['mails']; - $mainMailIndex = \array_search($user['mail'], \array_map(fn ($m) => $m['mail'], $mails)); + $mainMailIndex = \array_search($user['mail'], \array_map(fn($m) => $m['mail'], $mails)); $mainMain = $mails[$mainMailIndex]; if ($mainMain['verified'] ?? false) { @@ -154,7 +159,8 @@ class Podio extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -165,7 +171,8 @@ class Podio extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array @@ -173,14 +180,14 @@ class Podio extends OAuth2 if (empty($this->user)) { $user = \json_decode($this->request( 'GET', - $this->apiEndpoint.'/user', - ['Authorization: Bearer '.\urlencode($accessToken)] + $this->apiEndpoint . '/user', + ['Authorization: Bearer ' . \urlencode($accessToken)] ), true); $profile = \json_decode($this->request( 'GET', - $this->apiEndpoint.'/user/profile', - ['Authorization: Bearer '.\urlencode($accessToken)] + $this->apiEndpoint . '/user/profile', + ['Authorization: Bearer ' . \urlencode($accessToken)] ), true); $this->user = $user; diff --git a/src/Appwrite/Auth/OAuth2/Salesforce.php b/src/Appwrite/Auth/OAuth2/Salesforce.php index 5fede655df..564fc51139 100644 --- a/src/Appwrite/Auth/OAuth2/Salesforce.php +++ b/src/Appwrite/Auth/OAuth2/Salesforce.php @@ -25,7 +25,7 @@ class Salesforce extends OAuth2 * @var array */ protected array $scopes = [ - 'openid', + "openid" ]; /** @@ -37,7 +37,8 @@ class Salesforce extends OAuth2 } /** - * @param string $state + * @param string $state + * * @return array */ public function parseState(string $state) @@ -45,29 +46,31 @@ class Salesforce extends OAuth2 return \json_decode(\html_entity_decode($state), true); } + /** * @return string */ public function getLoginURL(): string { - return 'https://login.salesforce.com/services/oauth2/authorize?'.\http_build_query([ + return 'https://login.salesforce.com/services/oauth2/authorize?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { $headers = [ - 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), + 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( @@ -77,7 +80,7 @@ class Salesforce extends OAuth2 \http_build_query([ 'code' => $code, 'redirect_uri' => $this->callback, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -86,13 +89,14 @@ class Salesforce extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $headers = [ - 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), + 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( @@ -101,7 +105,7 @@ class Salesforce extends OAuth2 $headers, \http_build_query([ 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -113,7 +117,8 @@ class Salesforce extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -124,7 +129,8 @@ class Salesforce extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -139,7 +145,8 @@ class Salesforce extends OAuth2 * * @link https://help.salesforce.com/s/articleView?id=sf.remoteaccess_using_userinfo_endpoint.htm&type=5 * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -154,7 +161,8 @@ class Salesforce extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -165,16 +173,16 @@ class Salesforce extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token='.\urlencode($accessToken)); + $user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token=' . \urlencode($accessToken)); $this->user = \json_decode($user, true); } - return $this->user; } } diff --git a/src/Appwrite/Auth/OAuth2/Slack.php b/src/Appwrite/Auth/OAuth2/Slack.php index ee6d43c0cc..8898f4d1f7 100644 --- a/src/Appwrite/Auth/OAuth2/Slack.php +++ b/src/Appwrite/Auth/OAuth2/Slack.php @@ -23,7 +23,7 @@ class Slack extends OAuth2 'identity.avatar', 'identity.basic', 'identity.email', - 'identity.team', + 'identity.team' ]; /** @@ -40,16 +40,17 @@ class Slack extends OAuth2 public function getLoginURL(): string { // https://api.slack.com/docs/oauth#step_1_-_sending_users_to_authorize_and_or_install - return 'https://slack.com/oauth/authorize?'.\http_build_query([ + return 'https://slack.com/oauth/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -58,11 +59,11 @@ class Slack extends OAuth2 // https://api.slack.com/docs/oauth#step_3_-_exchanging_a_verification_code_for_an_access_token $this->tokens = \json_decode($this->request( 'GET', - 'https://slack.com/api/oauth.access?'.\http_build_query([ + 'https://slack.com/api/oauth.access?' . \http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'code' => $code, - 'redirect_uri' => $this->callback, + 'redirect_uri' => $this->callback ]) ), true); } @@ -71,18 +72,19 @@ class Slack extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'GET', - 'https://slack.com/api/oauth.access?'.\http_build_query([ + 'https://slack.com/api/oauth.access?' . \http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -94,7 +96,8 @@ class Slack extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -105,7 +108,8 @@ class Slack extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -122,18 +126,20 @@ class Slack extends OAuth2 * * @link https://slack.com/help/articles/207262907-Change-your-email-address * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -146,7 +152,8 @@ class Slack extends OAuth2 /** * @link https://api.slack.com/methods/users.identity * - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array @@ -154,7 +161,7 @@ class Slack extends OAuth2 if (empty($this->user)) { $user = $this->request( 'GET', - 'https://slack.com/api/users.identity?token='.\urlencode($accessToken) + 'https://slack.com/api/users.identity?token=' . \urlencode($accessToken) ); $this->user = \json_decode($user, true); diff --git a/src/Appwrite/Auth/OAuth2/Spotify.php b/src/Appwrite/Auth/OAuth2/Spotify.php index a8d5c531ab..d8e23cf0f0 100644 --- a/src/Appwrite/Auth/OAuth2/Spotify.php +++ b/src/Appwrite/Auth/OAuth2/Spotify.php @@ -49,32 +49,33 @@ class Spotify extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint.'authorize?'. + return $this->endpoint . 'authorize?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { - $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)]; + $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'api/token', + $this->endpoint . 'api/token', $headers, \http_build_query([ - 'code' => $code, - 'grant_type' => 'authorization_code', - 'redirect_uri' => $this->callback, + "code" => $code, + "grant_type" => "authorization_code", + "redirect_uri" => $this->callback ]) ), true); } @@ -83,19 +84,20 @@ class Spotify extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { - $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)]; + $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'api/token', + $this->endpoint . 'api/token', $headers, \http_build_query([ - 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + "refresh_token" => $refreshToken, + "grant_type" => "refresh_token", ]) ), true); @@ -107,7 +109,8 @@ class Spotify extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -118,7 +121,8 @@ class Spotify extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -135,7 +139,8 @@ class Spotify extends OAuth2 * * @link https://developer.spotify.com/documentation/web-api/reference/#/operations/get-current-users-profile * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -144,7 +149,8 @@ class Spotify extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -155,7 +161,8 @@ class Spotify extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) @@ -163,8 +170,8 @@ class Spotify extends OAuth2 if (empty($this->user)) { $this->user = \json_decode($this->request( 'GET', - $this->resourceEndpoint.'me', - ['Authorization: Bearer '.\urlencode($accessToken)] + $this->resourceEndpoint . 'me', + ['Authorization: Bearer ' . \urlencode($accessToken)] ), true); } diff --git a/src/Appwrite/Auth/OAuth2/Stripe.php b/src/Appwrite/Auth/OAuth2/Stripe.php index 42260cad1e..5a959dbfcb 100644 --- a/src/Appwrite/Auth/OAuth2/Stripe.php +++ b/src/Appwrite/Auth/OAuth2/Stripe.php @@ -3,6 +3,7 @@ namespace Appwrite\Auth\OAuth2; use Appwrite\Auth\OAuth2; +use Utopia\Exception; class Stripe extends OAuth2 { @@ -49,17 +50,18 @@ class Stripe extends OAuth2 */ public function getLoginURL(): string { - return 'https://connect.stripe.com/oauth/authorize?'.\http_build_query([ + return 'https://connect.stripe.com/oauth/authorize?' . \http_build_query([ 'response_type' => 'code', // The only option at the moment is "code." 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -71,7 +73,7 @@ class Stripe extends OAuth2 [], \http_build_query([ 'grant_type' => $this->grantType['authorize'], - 'code' => $code, + 'code' => $code ]) ), true); @@ -82,7 +84,8 @@ class Stripe extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -102,12 +105,12 @@ class Stripe extends OAuth2 } $this->stripeAccountId = $this->tokens['stripe_user_id']; - return $this->tokens; } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -118,7 +121,8 @@ class Stripe extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -137,18 +141,20 @@ class Stripe extends OAuth2 * * If present, the email is verified. This was verfied through a manual Stripe sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -159,17 +165,18 @@ class Stripe extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) { - if (empty($this->user) && ! empty($this->stripeAccountId)) { + if (empty($this->user) && !empty($this->stripeAccountId)) { $this->user = \json_decode( $this->request( 'GET', - 'https://api.stripe.com/v1/accounts/'.$this->stripeAccountId, - ['Authorization: Bearer '.\urlencode($accessToken)] + 'https://api.stripe.com/v1/accounts/' . $this->stripeAccountId, + ['Authorization: Bearer ' . \urlencode($accessToken)] ), true ); diff --git a/src/Appwrite/Auth/OAuth2/Tradeshift.php b/src/Appwrite/Auth/OAuth2/Tradeshift.php index 350c152e4c..8d0bfa8784 100644 --- a/src/Appwrite/Auth/OAuth2/Tradeshift.php +++ b/src/Appwrite/Auth/OAuth2/Tradeshift.php @@ -10,7 +10,6 @@ use Appwrite\Auth\OAuth2; class Tradeshift extends OAuth2 { public const TRADESHIFT_SANDBOX_API_DOMAIN = 'api-sandbox.tradeshift.com'; - public const TRADESHIFT_API_DOMAIN = 'api.tradeshift.com'; private array $apiDomain = [ @@ -19,13 +18,13 @@ class Tradeshift extends OAuth2 ]; private array $endpoint = [ - 'sandbox' => 'https://'.self::TRADESHIFT_SANDBOX_API_DOMAIN.'/tradeshift/', - 'live' => 'https://'.self::TRADESHIFT_API_DOMAIN.'/tradeshift/', + 'sandbox' => 'https://' . self::TRADESHIFT_SANDBOX_API_DOMAIN . '/tradeshift/', + 'live' => 'https://' . self::TRADESHIFT_API_DOMAIN . '/tradeshift/', ]; private array $resourceEndpoint = [ - 'sandbox' => 'https://'.self::TRADESHIFT_SANDBOX_API_DOMAIN.'/tradeshift/rest/external/', - 'live' => 'https://'.self::TRADESHIFT_API_DOMAIN.'/tradeshift/rest/external/', + 'sandbox' => 'https://' . self::TRADESHIFT_SANDBOX_API_DOMAIN . '/tradeshift/rest/external/', + 'live' => 'https://' . self::TRADESHIFT_API_DOMAIN . '/tradeshift/rest/external/', ]; protected string $environment = 'live'; @@ -65,17 +64,18 @@ class Tradeshift extends OAuth2 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), - 'redirect_uri' => \str_replace('localhost', '127.0.0.1', $this->callback), + 'redirect_uri' => \str_replace("localhost", "127.0.0.1", $this->callback), 'state' => \json_encode($this->state), ]); - $url = $this->endpoint[$this->environment].'auth/login?'.$httpQuery; + $url = $this->endpoint[$this->environment] . 'auth/login?' . $httpQuery; return $url; } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -83,8 +83,8 @@ class Tradeshift extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint[$this->environment].'auth/token', - ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)], + $this->endpoint[$this->environment] . 'auth/token', + ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)], \http_build_query([ 'grant_type' => 'authorization_code', 'code' => $code, @@ -96,15 +96,16 @@ class Tradeshift extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint[$this->environment].'auth/token', - ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)], + $this->endpoint[$this->environment] . 'auth/token', + ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)], \http_build_query([ 'grant_type' => 'refresh_token', 'refresh_token' => $refreshToken, @@ -119,7 +120,8 @@ class Tradeshift extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -130,7 +132,8 @@ class Tradeshift extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -145,18 +148,20 @@ class Tradeshift extends OAuth2 * * If present, the email is verified. This was verfied through a manual Tradeshift sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUser($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -166,11 +171,12 @@ class Tradeshift extends OAuth2 $firstName = $user['FirstName'] ?? ''; $lastName = $user['LastName'] ?? ''; - return $firstName.' '.$lastName; + return $firstName . ' ' . $lastName; } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array @@ -178,14 +184,14 @@ class Tradeshift extends OAuth2 $header = [ 'Content-Type: application/json', 'Accept: application/json', - 'Host: '.urlencode($this->apiDomain[$this->environment]), - 'Authorization: Bearer '.$accessToken, + 'Host: ' . urlencode($this->apiDomain[$this->environment]), + 'Authorization: Bearer ' . $accessToken, ]; if (empty($this->user)) { $response = $this->request( 'GET', - $this->resourceEndpoint[$this->environment].'account/info/user', + $this->resourceEndpoint[$this->environment] . 'account/info/user', $header ); $this->user = \json_decode($response, true); diff --git a/src/Appwrite/Auth/OAuth2/TradeshiftBox.php b/src/Appwrite/Auth/OAuth2/TradeshiftBox.php index d960acf2d3..27a4c0a456 100644 --- a/src/Appwrite/Auth/OAuth2/TradeshiftBox.php +++ b/src/Appwrite/Auth/OAuth2/TradeshiftBox.php @@ -2,6 +2,8 @@ namespace Appwrite\Auth\OAuth2; +use Appwrite\Auth\OAuth2\Tradeshift; + class TradeshiftBox extends Tradeshift { protected string $environment = 'sandbox'; diff --git a/src/Appwrite/Auth/OAuth2/Twitch.php b/src/Appwrite/Auth/OAuth2/Twitch.php index dad2efe800..ed73054c31 100644 --- a/src/Appwrite/Auth/OAuth2/Twitch.php +++ b/src/Appwrite/Auth/OAuth2/Twitch.php @@ -49,19 +49,20 @@ class Twitch extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint.'authorize?'. + return $this->endpoint . 'authorize?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'redirect_uri' => $this->callback, 'force_verify' => true, - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -69,12 +70,12 @@ class Twitch extends OAuth2 if (empty($this->tokens)) { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'token?'.\http_build_query([ - 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, - 'code' => $code, - 'grant_type' => 'authorization_code', - 'redirect_uri' => $this->callback, + $this->endpoint . 'token?' . \http_build_query([ + "client_id" => $this->appID, + "client_secret" => $this->appSecret, + "code" => $code, + "grant_type" => "authorization_code", + "redirect_uri" => $this->callback ]) ), true); } @@ -83,18 +84,19 @@ class Twitch extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'token?'.\http_build_query([ - 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, - 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + $this->endpoint . 'token?' . \http_build_query([ + "client_id" => $this->appID, + "client_secret" => $this->appSecret, + "refresh_token" => $refreshToken, + "grant_type" => "refresh_token", ]) ), true); @@ -106,7 +108,8 @@ class Twitch extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -117,7 +120,8 @@ class Twitch extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -134,18 +138,20 @@ class Twitch extends OAuth2 * * @link https://dev.twitch.tv/docs/api/reference#get-users * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -156,7 +162,8 @@ class Twitch extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) @@ -166,8 +173,8 @@ class Twitch extends OAuth2 'GET', $this->resourceEndpoint, [ - 'Authorization: Bearer '.\urlencode($accessToken), - 'Client-Id: '.\urlencode($this->appID), + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Client-Id: ' . \urlencode($this->appID) ] ), true); diff --git a/src/Appwrite/Auth/OAuth2/WordPress.php b/src/Appwrite/Auth/OAuth2/WordPress.php index 084b890a5d..1bd55916fc 100644 --- a/src/Appwrite/Auth/OAuth2/WordPress.php +++ b/src/Appwrite/Auth/OAuth2/WordPress.php @@ -39,17 +39,18 @@ class WordPress extends OAuth2 */ public function getLoginURL(): string { - return 'https://public-api.wordpress.com/oauth2/authorize?'.\http_build_query([ + return 'https://public-api.wordpress.com/oauth2/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'response_type' => 'code', 'scope' => $this->getScopes(), - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -64,7 +65,7 @@ class WordPress extends OAuth2 'redirect_uri' => $this->callback, 'client_secret' => $this->appSecret, 'grant_type' => 'authorization_code', - 'code' => $code, + 'code' => $code ]) ), true); } @@ -73,7 +74,8 @@ class WordPress extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -86,7 +88,7 @@ class WordPress extends OAuth2 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken, + 'refresh_token' => $refreshToken ]) ), true); @@ -98,7 +100,8 @@ class WordPress extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -109,7 +112,8 @@ class WordPress extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -128,7 +132,8 @@ class WordPress extends OAuth2 * * @link https://developer.wordpress.com/docs/api/1.1/get/me/ * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -143,7 +148,8 @@ class WordPress extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -154,13 +160,14 @@ class WordPress extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) { if (empty($this->user)) { - $this->user = \json_decode($this->request('GET', 'https://public-api.wordpress.com/rest/v1/me', ['Authorization: Bearer '.$accessToken]), true); + $this->user = \json_decode($this->request('GET', 'https://public-api.wordpress.com/rest/v1/me', ['Authorization: Bearer ' . $accessToken]), true); } return $this->user; diff --git a/src/Appwrite/Auth/OAuth2/Yahoo.php b/src/Appwrite/Auth/OAuth2/Yahoo.php index 82496d666c..c70a2fb6c9 100644 --- a/src/Appwrite/Auth/OAuth2/Yahoo.php +++ b/src/Appwrite/Auth/OAuth2/Yahoo.php @@ -45,8 +45,10 @@ class Yahoo extends OAuth2 return 'yahoo'; } + /** * @param $state + * * @return array */ public function parseState(string $state) @@ -59,36 +61,37 @@ class Yahoo extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint.'request_auth?'. + return $this->endpoint . 'request_auth?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { $headers = [ - 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), + 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'get_token', + $this->endpoint . 'get_token', $headers, \http_build_query([ - 'code' => $code, - 'grant_type' => 'authorization_code', - 'redirect_uri' => $this->callback, + "code" => $code, + "grant_type" => "authorization_code", + "redirect_uri" => $this->callback ]) ), true); } @@ -97,23 +100,24 @@ class Yahoo extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $headers = [ - 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), + 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'get_token', + $this->endpoint . 'get_token', $headers, \http_build_query([ - 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + "refresh_token" => $refreshToken, + "grant_type" => "refresh_token", ]) ), true); @@ -125,7 +129,8 @@ class Yahoo extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -136,7 +141,8 @@ class Yahoo extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -151,18 +157,20 @@ class Yahoo extends OAuth2 * * If present, the email is verified. This was verfied through a manual Yahoo sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -173,7 +181,8 @@ class Yahoo extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) @@ -182,7 +191,7 @@ class Yahoo extends OAuth2 $this->user = \json_decode($this->request( 'GET', $this->resourceEndpoint, - ['Authorization: Bearer '.\urlencode($accessToken)] + ['Authorization: Bearer ' . \urlencode($accessToken)] ), true); } diff --git a/src/Appwrite/Auth/OAuth2/Yammer.php b/src/Appwrite/Auth/OAuth2/Yammer.php index c6d1ba2837..9e1827bc58 100644 --- a/src/Appwrite/Auth/OAuth2/Yammer.php +++ b/src/Appwrite/Auth/OAuth2/Yammer.php @@ -37,17 +37,18 @@ class Yammer extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint.'oauth2/authorize?'. + return $this->endpoint . 'oauth2/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'response_type' => 'code', 'redirect_uri' => $this->callback, - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array @@ -56,13 +57,13 @@ class Yammer extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'access_token?', + $this->endpoint . 'access_token?', $headers, \http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'code' => $code, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -71,7 +72,8 @@ class Yammer extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array @@ -79,13 +81,13 @@ class Yammer extends OAuth2 $headers = ['Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'access_token?', + $this->endpoint . 'access_token?', $headers, \http_build_query([ 'client_id' => $this->appID, 'client_secret' => $this->appSecret, 'refresh_token' => $refreshToken, - 'grant_type' => 'refresh_token', + 'grant_type' => 'refresh_token' ]) ), true); @@ -97,7 +99,8 @@ class Yammer extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -108,7 +111,8 @@ class Yammer extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -123,18 +127,20 @@ class Yammer extends OAuth2 * * If present, the email is verified. This was verfied through a manual Yammer sign up process * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool { $email = $this->getUserEmail($accessToken); - return ! empty($email); + return !empty($email); } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -145,13 +151,14 @@ class Yammer extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer '.\urlencode($accessToken)]; + $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; $user = $this->request('GET', 'https://www.yammer.com/api/v1/users/current.json', $headers); $this->user = \json_decode($user, true); } diff --git a/src/Appwrite/Auth/OAuth2/Yandex.php b/src/Appwrite/Auth/OAuth2/Yandex.php index 13e1fb4dfc..a6a2e2e550 100644 --- a/src/Appwrite/Auth/OAuth2/Yandex.php +++ b/src/Appwrite/Auth/OAuth2/Yandex.php @@ -8,6 +8,7 @@ use Appwrite\Auth\OAuth2; // https://tech.yandex.com/passport/doc/dg/reference/request-docpage/ // https://tech.yandex.com/oauth/doc/dg/reference/web-client-docpage/ + class Yandex extends OAuth2 { /** @@ -34,7 +35,8 @@ class Yandex extends OAuth2 } /** - * @param string $state + * @param string $state + * * @return array */ public function parseState(string $state) @@ -42,28 +44,30 @@ class Yandex extends OAuth2 return \json_decode(\html_entity_decode($state), true); } + /** * @return string */ public function getLoginURL(): string { - return 'https://oauth.yandex.com/authorize?'.\http_build_query([ + return 'https://oauth.yandex.com/authorize?' . \http_build_query([ 'response_type' => 'code', 'client_id' => $this->appID, 'scope' => \implode(' ', $this->getScopes()), - 'state' => \json_encode($this->state), + 'state' => \json_encode($this->state) ]); } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { $headers = [ - 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), + 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( @@ -72,7 +76,7 @@ class Yandex extends OAuth2 $headers, \http_build_query([ 'code' => $code, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); } @@ -81,13 +85,14 @@ class Yandex extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { $headers = [ - 'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), + 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded', ]; $this->tokens = \json_decode($this->request( @@ -96,7 +101,7 @@ class Yandex extends OAuth2 $headers, \http_build_query([ 'refresh_token' => $refreshToken, - 'grant_type' => 'authorization_code', + 'grant_type' => 'authorization_code' ]) ), true); @@ -108,7 +113,8 @@ class Yandex extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -119,7 +125,8 @@ class Yandex extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -132,7 +139,8 @@ class Yandex extends OAuth2 /** * Check if the OAuth email is verified * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -141,7 +149,8 @@ class Yandex extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string @@ -152,19 +161,19 @@ class Yandex extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken): array { if (empty($this->user)) { - $user = $this->request('GET', 'https://login.yandex.ru/info?'.\http_build_query([ + $user = $this->request('GET', 'https://login.yandex.ru/info?' . \http_build_query([ 'format' => 'json', - 'oauth_token' => $accessToken, + 'oauth_token' => $accessToken ])); $this->user = \json_decode($user, true); } - return $this->user; } } diff --git a/src/Appwrite/Auth/OAuth2/Zoom.php b/src/Appwrite/Auth/OAuth2/Zoom.php index 01ade69a48..9dad22212a 100644 --- a/src/Appwrite/Auth/OAuth2/Zoom.php +++ b/src/Appwrite/Auth/OAuth2/Zoom.php @@ -30,7 +30,7 @@ class Zoom extends OAuth2 * @var array */ protected array $scopes = [ - 'user_info:read', + 'user_info:read' ]; /** @@ -46,7 +46,7 @@ class Zoom extends OAuth2 */ public function getLoginURL(): string { - return $this->endpoint.'/oauth/authorize?'.\http_build_query([ + return $this->endpoint . '/oauth/authorize?' . \http_build_query([ 'client_id' => $this->appID, 'redirect_uri' => $this->callback, 'response_type' => 'code', @@ -56,21 +56,22 @@ class Zoom extends OAuth2 } /** - * @param string $code + * @param string $code + * * @return array */ protected function getTokens(string $code): array { if (empty($this->tokens)) { - $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded']; + $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth/token', + $this->endpoint . '/oauth/token', $headers, \http_build_query([ 'grant_type' => 'authorization_code', 'redirect_uri' => $this->callback, - 'code' => $code, + 'code' => $code ]) ), true); } @@ -79,15 +80,16 @@ class Zoom extends OAuth2 } /** - * @param string $refreshToken + * @param string $refreshToken + * * @return array */ public function refreshTokens(string $refreshToken): array { - $headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret), 'Content-Type: application/x-www-form-urlencoded']; + $headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded']; $this->tokens = \json_decode($this->request( 'POST', - $this->endpoint.'/oauth/token', + $this->endpoint . '/oauth/token', $headers, \http_build_query([ 'grant_type' => 'refresh_token', @@ -103,7 +105,8 @@ class Zoom extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserID(string $accessToken): string @@ -114,7 +117,8 @@ class Zoom extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserEmail(string $accessToken): string @@ -129,7 +133,8 @@ class Zoom extends OAuth2 * * @link https://marketplace.zoom.us/docs/api-reference/zoom-api/methods/#operation/user * - * @param string $accessToken + * @param string $accessToken + * * @return bool */ public function isEmailVerified(string $accessToken): bool @@ -144,24 +149,26 @@ class Zoom extends OAuth2 } /** - * @param string $accessToken + * @param string $accessToken + * * @return string */ public function getUserName(string $accessToken): string { $response = $this->getUser($accessToken); - return ($response['first_name'] ?? '').' '.($response['last_name'] ?? ''); + return ($response['first_name'] ?? '') . ' ' . ($response['last_name'] ?? ''); } /** - * @param string $accessToken + * @param string $accessToken + * * @return array */ protected function getUser(string $accessToken) { $headers = [ - 'Authorization: Bearer '.\urlencode($accessToken), + 'Authorization: Bearer ' . \urlencode($accessToken) ]; if (empty($this->user)) { diff --git a/src/Appwrite/Auth/Validator/Password.php b/src/Appwrite/Auth/Validator/Password.php index e997d03f81..93a9f74114 100644 --- a/src/Appwrite/Auth/Validator/Password.php +++ b/src/Appwrite/Auth/Validator/Password.php @@ -26,12 +26,13 @@ class Password extends Validator /** * Is valid. * - * @param mixed $value + * @param mixed $value + * * @return bool */ public function isValid($value): bool { - if (! \is_string($value)) { + if (!\is_string($value)) { return false; } diff --git a/src/Appwrite/Auth/Validator/PasswordDictionary.php b/src/Appwrite/Auth/Validator/PasswordDictionary.php index 27feeeca36..003d68bc73 100644 --- a/src/Appwrite/Auth/Validator/PasswordDictionary.php +++ b/src/Appwrite/Auth/Validator/PasswordDictionary.php @@ -10,7 +10,6 @@ namespace Appwrite\Auth\Validator; class PasswordDictionary extends Password { protected array $dictionary; - protected bool $enabled; public function __construct(array $dictionary, bool $enabled = false) @@ -34,19 +33,19 @@ class PasswordDictionary extends Password /** * Is valid. * - * @param mixed $value + * @param mixed $value + * * @return bool */ public function isValid($value): bool { - if (! parent::isValid($value)) { + if (!parent::isValid($value)) { return false; } if ($this->enabled && array_key_exists($value, $this->dictionary)) { return false; } - return true; } diff --git a/src/Appwrite/Auth/Validator/PasswordHistory.php b/src/Appwrite/Auth/Validator/PasswordHistory.php index d78abe6689..8cfabf4666 100644 --- a/src/Appwrite/Auth/Validator/PasswordHistory.php +++ b/src/Appwrite/Auth/Validator/PasswordHistory.php @@ -12,9 +12,7 @@ use Appwrite\Auth\Auth; class PasswordHistory extends Password { protected array $history; - protected string $algo; - protected array $algoOptions; public function __construct(array $history, string $algo, array $algoOptions = []) @@ -39,7 +37,8 @@ class PasswordHistory extends Password /** * Is valid. * - * @param mixed $value + * @param mixed $value + * * @return bool */ public function isValid($value): bool @@ -49,7 +48,6 @@ class PasswordHistory extends Password return false; } } - return true; } diff --git a/src/Appwrite/Auth/Validator/PersonalData.php b/src/Appwrite/Auth/Validator/PersonalData.php index 911d8f5515..6f8ed0a8c9 100644 --- a/src/Appwrite/Auth/Validator/PersonalData.php +++ b/src/Appwrite/Auth/Validator/PersonalData.php @@ -31,16 +31,17 @@ class PersonalData extends Password /** * Is valid. * - * @param mixed $value + * @param mixed $value + * * @return bool */ public function isValid($password): bool { - if (! parent::isValid($password)) { + if (!parent::isValid($password)) { return false; } - if (! $this->strict) { + if (!$this->strict) { $password = strtolower($password); $this->userId = strtolower($this->userId); $this->email = strtolower($this->email); diff --git a/src/Appwrite/Auth/Validator/Phone.php b/src/Appwrite/Auth/Validator/Phone.php index 49d78ac8c6..32c3ca3398 100644 --- a/src/Appwrite/Auth/Validator/Phone.php +++ b/src/Appwrite/Auth/Validator/Phone.php @@ -26,12 +26,13 @@ class Phone extends Validator /** * Is valid. * - * @param mixed $value + * @param mixed $value + * * @return bool */ public function isValid($value): bool { - return is_string($value) && (bool) \preg_match('/^\+[1-9]\d{1,14}$/', $value); + return is_string($value) && !!\preg_match('/^\+[1-9]\d{1,14}$/', $value); } /** diff --git a/src/Appwrite/Detector/Detector.php b/src/Appwrite/Detector/Detector.php index ed1be7325b..62f7a0a04b 100644 --- a/src/Appwrite/Detector/Detector.php +++ b/src/Appwrite/Detector/Detector.php @@ -17,7 +17,7 @@ class Detector protected $detctor; /** - * @param string $userAgent + * @param string $userAgent */ public function __construct(string $userAgent) { @@ -54,7 +54,7 @@ class Detector 'type' => 'desktop', 'short_name' => 'cli', 'name' => 'Appwrite CLI', - 'version' => $version, + 'version' => $version ]; } else { $client = $this->getDetector()->getClient(); @@ -89,7 +89,7 @@ class Detector */ protected function getDetector(): DeviceDetector { - if (! $this->detctor) { + if (!$this->detctor) { $this->detctor = new DeviceDetector($this->userAgent); $this->detctor->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) $this->detctor->parse(); @@ -103,7 +103,7 @@ class Detector * It is needed if we want bots to be processed as a simple clients. So we can detect if it is mobile client, * or desktop, or enything else. By default all this information is not retrieved for the bots. * - * @param bool $skip + * @param bool $skip */ public function skipBotDetection(bool $skip = true): void { diff --git a/src/Appwrite/Docker/Compose.php b/src/Appwrite/Docker/Compose.php index 0b4a8b16b9..64441805de 100644 --- a/src/Appwrite/Docker/Compose.php +++ b/src/Appwrite/Docker/Compose.php @@ -13,7 +13,7 @@ class Compose protected $compose = []; /** - * @var string + * @var string $data */ public function __construct(string $data) { @@ -48,7 +48,7 @@ class Compose */ public function getService(string $name): Service { - if (! isset($this->compose['services'][$name])) { + if (!isset($this->compose['services'][$name])) { throw new Exception('Service not found'); } diff --git a/src/Appwrite/Docker/Compose/Service.php b/src/Appwrite/Docker/Compose/Service.php index 32c12b82b1..a3f9c91253 100644 --- a/src/Appwrite/Docker/Compose/Service.php +++ b/src/Appwrite/Docker/Compose/Service.php @@ -12,7 +12,7 @@ class Service protected $service = []; /** - * @var string + * @var string $path */ public function __construct(array $service) { @@ -54,8 +54,7 @@ class Service public function getImageVersion(): string { $image = $this->getImage(); - - return substr($image, ((int) strpos($image, ':')) + 1); + return substr($image, ((int)strpos($image, ':')) + 1); } /** diff --git a/src/Appwrite/Docker/Env.php b/src/Appwrite/Docker/Env.php index 6351ce4f78..bce12a95e6 100644 --- a/src/Appwrite/Docker/Env.php +++ b/src/Appwrite/Docker/Env.php @@ -2,6 +2,8 @@ namespace Appwrite\Docker; +use Exception; + class Env { /** @@ -10,7 +12,7 @@ class Env protected $vars = []; /** - * @var string + * @var string $data */ public function __construct(string $data) { @@ -28,8 +30,9 @@ class Env } /** - * @param string $key - * @param mixed $value + * @param string $key + * @param mixed $value + * * @return $this */ public function setVar(string $key, $value): self @@ -40,7 +43,8 @@ class Env } /** - * @param string $key + * @param string $key + * * @return string */ public function getVar(string $key): string @@ -66,7 +70,7 @@ class Env $output = ''; foreach ($this->vars as $key => $value) { - $output .= $key.'='.$value."\n"; + $output .= $key . '=' . $value . "\n"; } return $output; diff --git a/src/Appwrite/Event/Audit.php b/src/Appwrite/Event/Audit.php index da396bba17..254f7c294a 100644 --- a/src/Appwrite/Event/Audit.php +++ b/src/Appwrite/Event/Audit.php @@ -7,11 +7,8 @@ use Resque; class Audit extends Event { protected string $resource = ''; - protected string $mode = ''; - protected string $userAgent = ''; - protected string $ip = ''; public function __construct() @@ -22,7 +19,7 @@ class Audit extends Event /** * Set resource for this audit event. * - * @param string $resource + * @param string $resource * @return self */ public function setResource(string $resource): self @@ -45,7 +42,7 @@ class Audit extends Event /** * Set mode for this audit event * - * @param string $mode + * @param string $mode * @return self */ public function setMode(string $mode): self @@ -68,7 +65,7 @@ class Audit extends Event /** * Set user agent for this audit event. * - * @param string $userAgent + * @param string $userAgent * @return self */ public function setUserAgent(string $userAgent): self @@ -91,7 +88,7 @@ class Audit extends Event /** * Set IP for this audit event. * - * @param string $ip + * @param string $ip * @return self */ public function setIP(string $ip): self @@ -115,7 +112,6 @@ class Audit extends Event * Executes the event and sends it to the audit worker. * * @return string|bool - * * @throws \InvalidArgumentException */ public function trigger(): string|bool diff --git a/src/Appwrite/Event/Build.php b/src/Appwrite/Event/Build.php index 92e4659dd7..4d4b338118 100644 --- a/src/Appwrite/Event/Build.php +++ b/src/Appwrite/Event/Build.php @@ -8,9 +8,7 @@ use Utopia\Database\Document; class Build extends Event { protected string $type = ''; - protected ?Document $resource = null; - protected ?Document $deployment = null; public function __construct() @@ -21,7 +19,7 @@ class Build extends Event /** * Sets resource document for the build event. * - * @param Document $resource + * @param Document $resource * @return self */ public function setResource(Document $resource): self @@ -44,7 +42,7 @@ class Build extends Event /** * Sets deployment for the build event. * - * @param Document $deployment + * @param Document $deployment * @return self */ public function setDeployment(Document $deployment): self @@ -67,7 +65,7 @@ class Build extends Event /** * Sets type for the build event. * - * @param string $type Can be `BUILD_TYPE_DEPLOYMENT` or `BUILD_TYPE_RETRY`. + * @param string $type Can be `BUILD_TYPE_DEPLOYMENT` or `BUILD_TYPE_RETRY`. * @return self */ public function setType(string $type): self @@ -91,7 +89,6 @@ class Build extends Event * Executes the function event and sends it to the functions worker. * * @return string|bool - * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -100,7 +97,7 @@ class Build extends Event 'project' => $this->project, 'resource' => $this->resource, 'deployment' => $this->deployment, - 'type' => $this->type, + 'type' => $this->type ]); } } diff --git a/src/Appwrite/Event/Certificate.php b/src/Appwrite/Event/Certificate.php index c39adbed8f..d3d9091804 100644 --- a/src/Appwrite/Event/Certificate.php +++ b/src/Appwrite/Event/Certificate.php @@ -8,7 +8,6 @@ use Utopia\Database\Document; class Certificate extends Event { protected bool $skipRenewCheck = false; - protected ?Document $domain = null; public function __construct() @@ -19,7 +18,7 @@ class Certificate extends Event /** * Set domain for this certificates event. * - * @param Document $domain + * @param Document $domain * @return self */ public function setDomain(Document $domain): self @@ -42,7 +41,7 @@ class Certificate extends Event /** * Set if the certificate needs to be validated. * - * @param bool $skipRenewCheck + * @param bool $skipRenewCheck * @return self */ public function setSkipRenewCheck(bool $skipRenewCheck): self @@ -66,7 +65,6 @@ class Certificate extends Event * Executes the event and sends it to the certificates worker. * * @return string|bool - * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -74,7 +72,7 @@ class Certificate extends Event return Resque::enqueue($this->queue, $this->class, [ 'project' => $this->project, 'domain' => $this->domain, - 'skipRenewCheck' => $this->skipRenewCheck, + 'skipRenewCheck' => $this->skipRenewCheck ]); } } diff --git a/src/Appwrite/Event/Database.php b/src/Appwrite/Event/Database.php index cc83263d71..1822f06c71 100644 --- a/src/Appwrite/Event/Database.php +++ b/src/Appwrite/Event/Database.php @@ -8,11 +8,8 @@ use Utopia\Database\Document; class Database extends Event { protected string $type = ''; - protected ?Document $database = null; - protected ?Document $collection = null; - protected ?Document $document = null; public function __construct() @@ -23,7 +20,7 @@ class Database extends Event /** * Sets the type for this database event (use the constants starting with DATABASE_TYPE_*). * - * @param string $type + * @param string $type * @return self */ public function setType(string $type): self @@ -35,7 +32,6 @@ class Database extends Event /** * Returns the set type for the database event. - * * @return string */ public function getType(): string @@ -46,20 +42,19 @@ class Database extends Event /** * Set the database for this event * - * @param Document $database + * @param Document $database * @return self */ public function setDatabase(Document $database): self { $this->database = $database; - return $this; } /** * Set the collection for this database event. * - * @param Document $collection + * @param Document $collection * @return self */ public function setCollection(Document $collection): self @@ -82,7 +77,7 @@ class Database extends Event /** * Set the document for this database event. * - * @param Document $document + * @param Document $document * @return self */ public function setDocument(Document $document): self @@ -94,7 +89,6 @@ class Database extends Event /** * Returns set document for this database event. - * * @return null|Document */ public function getDocument(): ?Document @@ -106,7 +100,6 @@ class Database extends Event * Executes the event and send it to the database worker. * * @return string|bool - * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -118,7 +111,7 @@ class Database extends Event 'collection' => $this->collection, 'document' => $this->document, 'database' => $this->database, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()), + 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) ]); } } diff --git a/src/Appwrite/Event/Delete.php b/src/Appwrite/Event/Delete.php index dee01ed6bf..d1519121a6 100644 --- a/src/Appwrite/Event/Delete.php +++ b/src/Appwrite/Event/Delete.php @@ -8,15 +8,12 @@ use Utopia\Database\Document; class Delete extends Event { protected string $type = ''; - protected ?Document $document = null; - protected ?string $resource = null; - protected ?string $datetime = null; - protected ?string $hourlyUsageRetentionDatetime = null; + public function __construct() { parent::__construct(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME); @@ -25,7 +22,7 @@ class Delete extends Event /** * Sets the type for the delete event (use the constants starting with DELETE_TYPE_*). * - * @param string $type + * @param string $type * @return self */ public function setType(string $type): self @@ -48,33 +45,31 @@ class Delete extends Event /** * set Datetime. * - * @param string $datetime + * @param string $datetime * @return self */ public function setDatetime(string $datetime): self { $this->datetime = $datetime; - return $this; } /** * Sets datetime for 1h interval. * - * @param string $datetime + * @param string $datetime * @return self */ public function setUsageRetentionHourlyDateTime(string $datetime): self { $this->hourlyUsageRetentionDatetime = $datetime; - return $this; } /** * Sets the document for the delete event. * - * @param Document $document + * @param Document $document * @return self */ public function setDocument(Document $document): self @@ -97,7 +92,7 @@ class Delete extends Event /** * Sets the resource for the delete event. * - * @param string $resource + * @param string $resource * @return self */ public function setResource(string $resource): self @@ -117,11 +112,11 @@ class Delete extends Event return $this->document; } + /** * Executes this event and sends it to the deletes worker. * * @return string|bool - * * @throws \InvalidArgumentException */ public function trigger(): string|bool diff --git a/src/Appwrite/Event/Event.php b/src/Appwrite/Event/Event.php index 0000cc482d..23dde49637 100644 --- a/src/Appwrite/Event/Event.php +++ b/src/Appwrite/Event/Event.php @@ -9,70 +9,51 @@ use Utopia\Database\Document; class Event { public const DATABASE_QUEUE_NAME = 'v1-database'; - public const DATABASE_CLASS_NAME = 'DatabaseV1'; public const DELETE_QUEUE_NAME = 'v1-deletes'; - public const DELETE_CLASS_NAME = 'DeletesV1'; public const AUDITS_QUEUE_NAME = 'v1-audits'; - public const AUDITS_CLASS_NAME = 'AuditsV1'; public const MAILS_QUEUE_NAME = 'v1-mails'; - public const MAILS_CLASS_NAME = 'MailsV1'; public const FUNCTIONS_QUEUE_NAME = 'v1-functions'; - public const FUNCTIONS_CLASS_NAME = 'FunctionsV1'; public const USAGE_QUEUE_NAME = 'v1-usage'; - public const USAGE_CLASS_NAME = 'UsageV1'; public const WEBHOOK_QUEUE_NAME = 'v1-webhooks'; - public const WEBHOOK_CLASS_NAME = 'WebhooksV1'; public const CERTIFICATES_QUEUE_NAME = 'v1-certificates'; - public const CERTIFICATES_CLASS_NAME = 'CertificatesV1'; public const BUILDS_QUEUE_NAME = 'v1-builds'; - public const BUILDS_CLASS_NAME = 'BuildsV1'; public const MESSAGING_QUEUE_NAME = 'v1-messaging'; - public const MESSAGING_CLASS_NAME = 'MessagingV1'; public const MIGRATIONS_QUEUE_NAME = 'v1-migrations'; - public const MIGRATIONS_CLASS_NAME = 'MigrationsV1'; protected string $queue = ''; - protected string $class = ''; - protected string $event = ''; - protected array $params = []; - protected array $payload = []; - protected array $context = []; - protected ?Document $project = null; - protected ?Document $user = null; - protected bool $paused = false; /** - * @param string $queue - * @param string $class + * @param string $queue + * @param string $class * @return void */ public function __construct(string $queue, string $class) @@ -84,7 +65,7 @@ class Event /** * Set queue used for this event. * - * @param string $queue + * @param string $queue * @return Event */ public function setQueue(string $queue): self @@ -106,8 +87,7 @@ class Event /** * Set event name used for this event. - * - * @param string $event + * @param string $event * @return Event */ public function setEvent(string $event): self @@ -130,7 +110,7 @@ class Event /** * Set project for this event. * - * @param Document $project + * @param Document $project * @return self */ public function setProject(Document $project): self @@ -153,7 +133,7 @@ class Event /** * Set user for this event. * - * @param Document $user + * @param Document $user * @return self */ public function setUser(Document $user): self @@ -176,7 +156,7 @@ class Event /** * Set payload for this event. * - * @param array $payload + * @param array $payload * @return self */ public function setPayload(array $payload): self @@ -199,8 +179,8 @@ class Event /** * Set context for this event. * - * @param string $key - * @param Document $context + * @param string $key + * @param Document $context * @return self */ public function setContext(string $key, Document $context): self @@ -213,7 +193,8 @@ class Event /** * Get context for this event. * - * @param string $key + * @param string $key + * * @return null|Document */ public function getContext(string $key): ?Document @@ -223,8 +204,7 @@ class Event /** * Set class used for this event. - * - * @param string $class + * @param string $class * @return self */ public function setClass(string $class): self @@ -247,8 +227,8 @@ class Event /** * Set param of event. * - * @param string $key - * @param mixed $value + * @param string $key + * @param mixed $value * @return self */ public function setParam(string $key, mixed $value): self @@ -261,7 +241,7 @@ class Event /** * Get param of event. * - * @param string $key + * @param string $key * @return mixed */ public function getParam(string $key): mixed @@ -283,7 +263,6 @@ class Event * Execute Event. * * @return string|bool - * * @throws InvalidArgumentException */ public function trigger(): string|bool @@ -297,7 +276,7 @@ class Event 'user' => $this->user, 'payload' => $this->payload, 'context' => $this->context, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()), + 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) ]); } @@ -316,7 +295,7 @@ class Event /** * Parses event pattern and returns the parts in their respective section. * - * @param string $pattern + * @param string $pattern * @return array */ public static function parseEventPattern(string $pattern): array @@ -345,13 +324,13 @@ class Event } } - if ($hasSubResource && ! $hasSubSubResource) { + if ($hasSubResource && !$hasSubSubResource) { if ($count === 6) { $attribute = $parts[5]; } } - if (! $hasSubResource) { + if (!$hasSubResource) { if ($count === 4) { $attribute = $parts[3]; } @@ -363,7 +342,7 @@ class Event $subSubResource ??= false; $attribute ??= false; $action = match (true) { - ! $hasSubResource && $count > 2 => $parts[2], + !$hasSubResource && $count > 2 => $parts[2], $hasSubSubResource => $parts[6] ?? false, $hasSubResource && $count > 4 => $parts[4], default => false @@ -384,10 +363,9 @@ class Event /** * Generates all possible events from a pattern. * - * @param string $pattern - * @param array $params + * @param string $pattern + * @param array $params * @return array - * * @throws \InvalidArgumentException */ public static function generateEvents(string $pattern, array $params = []): array @@ -408,15 +386,15 @@ class Event $action = $parsed['action']; $attribute = $parsed['attribute']; - if ($resource && ! \in_array(\trim($resource, "\[\]"), $paramKeys)) { + if ($resource && !\in_array(\trim($resource, "\[\]"), $paramKeys)) { throw new InvalidArgumentException("{$resource} is missing from the params."); } - if ($subResource && ! \in_array(\trim($subResource, "\[\]"), $paramKeys)) { + if ($subResource && !\in_array(\trim($subResource, "\[\]"), $paramKeys)) { throw new InvalidArgumentException("{$subResource} is missing from the params."); } - if ($subSubResource && ! \in_array(\trim($subSubResource, "\[\]"), $paramKeys)) { + if ($subSubResource && !\in_array(\trim($subSubResource, "\[\]"), $paramKeys)) { throw new InvalidArgumentException("{$subSubResource} is missing from the params."); } @@ -470,9 +448,9 @@ class Event if ($subCurrent === $current || $subCurrent === $key) { continue; } - $filtered1 = \array_filter($paramKeys, fn (string $k) => $k === $subCurrent); + $filtered1 = \array_filter($paramKeys, fn(string $k) => $k === $subCurrent); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered1, '*', $eventPattern)); - $filtered2 = \array_filter($paramKeys, fn (string $k) => $k === $current); + $filtered2 = \array_filter($paramKeys, fn(string $k) => $k === $current); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered2, '*', \str_replace($filtered1, '*', $eventPattern))); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered2, '*', $eventPattern)); } @@ -480,7 +458,7 @@ class Event if ($current === $key) { continue; } - $filtered = \array_filter($paramKeys, fn (string $k) => $k === $current); + $filtered = \array_filter($paramKeys, fn(string $k) => $k === $current); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered, '*', $eventPattern)); } } diff --git a/src/Appwrite/Event/Func.php b/src/Appwrite/Event/Func.php index dea2381cda..d121b47a4a 100644 --- a/src/Appwrite/Event/Func.php +++ b/src/Appwrite/Event/Func.php @@ -9,13 +9,9 @@ use Utopia\Queue\Connection; class Func extends Event { protected string $jwt = ''; - protected string $type = ''; - protected string $data = ''; - protected ?Document $function = null; - protected ?Document $execution = null; public function __construct(protected Connection $connection) @@ -26,7 +22,7 @@ class Func extends Event /** * Sets function document for the function event. * - * @param Document $function + * @param Document $function * @return self */ public function setFunction(Document $function): self @@ -49,7 +45,7 @@ class Func extends Event /** * Sets execution for the function event. * - * @param Document $execution + * @param Document $execution * @return self */ public function setExecution(Document $execution): self @@ -72,7 +68,7 @@ class Func extends Event /** * Sets type for the function event. * - * @param string $type Can be `schedule`, `event` or `http`. + * @param string $type Can be `schedule`, `event` or `http`. * @return self */ public function setType(string $type): self @@ -95,7 +91,7 @@ class Func extends Event /** * Sets custom data for the function event. * - * @param string $data + * @param string $data * @return self */ public function setData(string $data): self @@ -118,7 +114,7 @@ class Func extends Event /** * Sets JWT for the function event. * - * @param string $jwt + * @param string $jwt * @return self */ public function setJWT(string $jwt): self @@ -142,7 +138,6 @@ class Func extends Event * Executes the function event and sends it to the functions worker. * * @return string|bool - * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -171,8 +166,10 @@ class Func extends Event /** * Generate a function event from a base event * - * @param Event $event + * @param Event $event + * * @return self + * */ public function from(Event $event): self { @@ -181,7 +178,6 @@ class Func extends Event $this->payload = $event->getPayload(); $this->event = $event->getEvent(); $this->params = $event->getParams(); - return $this; } } diff --git a/src/Appwrite/Event/Mail.php b/src/Appwrite/Event/Mail.php index 68a6cfe2a3..37b42704c5 100644 --- a/src/Appwrite/Event/Mail.php +++ b/src/Appwrite/Event/Mail.php @@ -3,19 +3,15 @@ namespace Appwrite\Event; use Resque; +use Utopia\Database\Document; class Mail extends Event { protected string $recipient = ''; - protected string $from = ''; - protected string $name = ''; - protected string $subject = ''; - protected string $body = ''; - protected array $smtp = []; public function __construct() @@ -26,7 +22,7 @@ class Mail extends Event /** * Sets subject for the mail event. * - * @param string $subject + * @param string $subject * @return self */ public function setSubject(string $subject): self @@ -49,7 +45,7 @@ class Mail extends Event /** * Sets recipient for the mail event. * - * @param string $recipient + * @param string $recipient * @return self */ public function setRecipient(string $recipient): self @@ -72,7 +68,7 @@ class Mail extends Event /** * Sets from for the mail event. * - * @param string $from + * @param string $from * @return self */ public function setFrom(string $from): self @@ -95,7 +91,7 @@ class Mail extends Event /** * Sets body for the mail event. * - * @param string $body + * @param string $body * @return self */ public function setBody(string $body): self @@ -118,7 +114,7 @@ class Mail extends Event /** * Sets name for the mail event. * - * @param string $name + * @param string $name * @return self */ public function setName(string $name): self @@ -141,13 +137,12 @@ class Mail extends Event /** * Set SMTP Host * - * @param string $host + * @param string $host * @return self */ public function setSmtpHost(string $host): self { $this->smtp['host'] = $host; - return $this; } @@ -160,59 +155,54 @@ class Mail extends Event public function setSmtpPort(int $port): self { $this->smtp['port'] = $port; - return $this; } /** * Set SMTP username * - * @param string $username + * @param string $username * @return self */ public function setSmtpUsername(string $username): self { $this->smtp['username']; - return $this; } /** * Set SMTP password * - * @param string $password + * @param string $password * @return self */ public function setSmtpPassword(string $password): self { $this->smtp['password']; - return $this; } /** * Set SMTP sender email * - * @param string $senderEmail + * @param string $senderEmail * @return self */ public function setSmtpSenderEmail(string $senderEmail): self { $this->smtp['senderEmail'] = $senderEmail; - return $this; } /** * Set SMTP reply to * - * @param string $replyTo + * @param string $replyTo * @return self */ public function setSmtpReplyTo(string $replyTo): self { $this->smtp['replyTo'] = $replyTo; - return $this; } @@ -229,7 +219,7 @@ class Mail extends Event /** * Get SMTP port * - * @return int + * @return integer */ public function getSmtpPort(): int { @@ -280,7 +270,6 @@ class Mail extends Event * Executes the event and sends it to the mails worker. * * @return string|bool - * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -292,7 +281,7 @@ class Mail extends Event 'subject' => $this->subject, 'body' => $this->body, 'smtp' => $this->smtp, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()), + 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) ]); } } diff --git a/src/Appwrite/Event/Migration.php b/src/Appwrite/Event/Migration.php index ebe15483d0..4d53f16796 100644 --- a/src/Appwrite/Event/Migration.php +++ b/src/Appwrite/Event/Migration.php @@ -10,7 +10,6 @@ use Utopia\Database\Document; class Migration extends Event { protected string $type = ''; - protected ?Document $migration = null; public function __construct() @@ -21,7 +20,7 @@ class Migration extends Event /** * Sets migration document for the migration event. * - * @param Document $migration + * @param Document $migration * @return self */ public function setMigration(Document $migration): self @@ -44,7 +43,8 @@ class Migration extends Event /** * Sets migration type for the migration event. * - * @param string $type + * @param string $type + * * @return self */ public function setType(string $type): self @@ -68,7 +68,6 @@ class Migration extends Event * Executes the migration event and sends it to the migrations worker. * * @return string|bool - * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -76,16 +75,15 @@ class Migration extends Event return Resque::enqueue($this->queue, $this->class, [ 'project' => $this->project, 'user' => $this->user, - 'migration' => $this->migration, + 'migration' => $this->migration ]); } /** * Schedules the migration event and schedules it in the migrations worker queue. * - * @param \DateTime|int $at + * @param \DateTime|int $at * @return void - * * @throws \Resque_Exception * @throws \ResqueScheduler_InvalidTimestampException */ @@ -94,7 +92,7 @@ class Migration extends Event ResqueScheduler::enqueueAt($at, $this->queue, $this->class, [ 'project' => $this->project, 'user' => $this->user, - 'migration' => $this->migration, + 'migration' => $this->migration ]); } } diff --git a/src/Appwrite/Event/Phone.php b/src/Appwrite/Event/Phone.php index 87bee4bc37..8baa5120c9 100644 --- a/src/Appwrite/Event/Phone.php +++ b/src/Appwrite/Event/Phone.php @@ -7,7 +7,6 @@ use Resque; class Phone extends Event { protected string $recipient = ''; - protected string $message = ''; public function __construct() @@ -18,7 +17,7 @@ class Phone extends Event /** * Sets recipient for the messaging event. * - * @param string $recipient + * @param string $recipient * @return self */ public function setRecipient(string $recipient): self @@ -41,7 +40,7 @@ class Phone extends Event /** * Sets url for the messaging event. * - * @param string $message + * @param string $message * @return self */ public function setMessage(string $message): self @@ -65,7 +64,6 @@ class Phone extends Event * Executes the event and sends it to the messaging worker. * * @return string|bool - * * @throws \InvalidArgumentException */ public function trigger(): string|bool @@ -76,7 +74,7 @@ class Phone extends Event 'payload' => $this->payload, 'recipient' => $this->recipient, 'message' => $this->message, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()), + 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) ]); } } diff --git a/src/Appwrite/Event/Usage.php b/src/Appwrite/Event/Usage.php index 01f576896b..b302b88808 100644 --- a/src/Appwrite/Event/Usage.php +++ b/src/Appwrite/Event/Usage.php @@ -2,15 +2,14 @@ namespace Appwrite\Event; -use Utopia\Database\Document; use Utopia\Queue\Client; use Utopia\Queue\Connection; +use Utopia\Database\Document; class Usage extends Event { protected array $metrics = []; - - protected array $reduce = []; + protected array $reduce = []; public function __construct(protected Connection $connection) { @@ -20,7 +19,7 @@ class Usage extends Event /** * Add reduce. * - * @param Document $document + * @param Document $document * @return self */ public function addReduce(Document $document): self @@ -33,8 +32,8 @@ class Usage extends Event /** * Add metric. * - * @param string $key - * @param int $value + * @param string $key + * @param int $value * @return self */ public function addMetric(string $key, int $value): self @@ -58,7 +57,7 @@ class Usage extends Event return $client->enqueue([ 'project' => $this->getProject(), - 'reduce' => $this->reduce, + 'reduce' => $this->reduce, 'metrics' => $this->metrics, ]); } diff --git a/src/Appwrite/Event/Validator/Event.php b/src/Appwrite/Event/Validator/Event.php index 7e8ef316cc..3f22900486 100644 --- a/src/Appwrite/Event/Validator/Event.php +++ b/src/Appwrite/Event/Validator/Event.php @@ -27,7 +27,8 @@ class Event extends Validator /** * Is valid. * - * @param mixed $value + * @param mixed $value + * * @return bool */ public function isValid($value): bool @@ -47,7 +48,6 @@ class Event extends Validator if ($type == 'functions') { $this->message = 'Triggering a function on a function event is not allowed.'; - return false; } @@ -55,7 +55,7 @@ class Event extends Validator $hasSubResource = $count > 3 && ($events[$type]['$resource'] ?? false) && ($events[$type][$parts[2]]['$resource'] ?? false); $hasSubSubResource = $count > 5 && $hasSubResource && ($events[$type][$parts[2]][$parts[4]]['$resource'] ?? false); - if (! $type || ! $resource) { + if (!$type || !$resource) { return false; } @@ -72,13 +72,13 @@ class Event extends Validator } } - if ($hasSubResource && ! $hasSubSubResource) { + if ($hasSubResource && !$hasSubSubResource) { if ($count === 6) { $attribute = $parts[5]; } } - if (! $hasSubResource) { + if (!$hasSubResource) { if ($count === 4) { $attribute = $parts[3]; } @@ -91,36 +91,36 @@ class Event extends Validator $attribute ??= false; $action = match (true) { - ! $hasSubResource && $count > 2 => $parts[2], + !$hasSubResource && $count > 2 => $parts[2], $hasSubSubResource => $parts[6] ?? false, $hasSubResource && $count > 4 => $parts[4], default => false }; - if (! \array_key_exists($type, $events)) { + if (!\array_key_exists($type, $events)) { return false; } if ($subType) { - if ($action && ! \array_key_exists($action, $events[$type][$subType])) { + if ($action && !\array_key_exists($action, $events[$type][$subType])) { return false; } - if (! ($subResource) || ! \array_key_exists($subType, $events[$type])) { + if (!($subResource) || !\array_key_exists($subType, $events[$type])) { return false; } } else { - if ($action && ! \array_key_exists($action, $events[$type])) { + if ($action && !\array_key_exists($action, $events[$type])) { return false; } } if ($attribute) { if (($subType)) { - if (! \array_key_exists($attribute, $events[$type][$subType][$action])) { + if (!\array_key_exists($attribute, $events[$type][$subType][$action])) { return false; } } else { - if (! \array_key_exists($attribute, $events[$type][$action])) { + if (!\array_key_exists($attribute, $events[$type][$action])) { return false; } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 4b1be708c3..d5803f5fbf 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -36,295 +36,187 @@ class Exception extends \Exception */ /** General */ - public const GENERAL_UNKNOWN = 'general_unknown'; - - public const GENERAL_MOCK = 'general_mock'; - - public const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; - - public const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; - - public const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; - - public const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; - - public const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; - - public const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; - - public const GENERAL_PHONE_DISABLED = 'general_phone_disabled'; - - public const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; - - public const GENERAL_QUERY_LIMIT_EXCEEDED = 'general_query_limit_exceeded'; - - public const GENERAL_QUERY_INVALID = 'general_query_invalid'; - - public const GENERAL_ROUTE_NOT_FOUND = 'general_route_not_found'; - - public const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found'; - - public const GENERAL_SERVER_ERROR = 'general_server_error'; - - public const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported'; - - public const GENERAL_CODES_DISABLED = 'general_codes_disabled'; - - public const GENERAL_USAGE_DISABLED = 'general_usage_disabled'; + public const GENERAL_UNKNOWN = 'general_unknown'; + public const GENERAL_MOCK = 'general_mock'; + public const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; + public const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; + public const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; + public const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; + public const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; + public const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; + public const GENERAL_PHONE_DISABLED = 'general_phone_disabled'; + public const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; + public const GENERAL_QUERY_LIMIT_EXCEEDED = 'general_query_limit_exceeded'; + public const GENERAL_QUERY_INVALID = 'general_query_invalid'; + public const GENERAL_ROUTE_NOT_FOUND = 'general_route_not_found'; + public const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found'; + public const GENERAL_SERVER_ERROR = 'general_server_error'; + public const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported'; + public const GENERAL_CODES_DISABLED = 'general_codes_disabled'; + public const GENERAL_USAGE_DISABLED = 'general_usage_disabled'; /** Users */ - public const USER_COUNT_EXCEEDED = 'user_count_exceeded'; - - public const USER_JWT_INVALID = 'user_jwt_invalid'; - - public const USER_ALREADY_EXISTS = 'user_already_exists'; - - public const USER_BLOCKED = 'user_blocked'; - - public const USER_INVALID_TOKEN = 'user_invalid_token'; - - public const USER_PASSWORD_RESET_REQUIRED = 'user_password_reset_required'; - - public const USER_EMAIL_NOT_WHITELISTED = 'user_email_not_whitelisted'; - - public const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; - - public const USER_INVALID_CODE = 'user_invalid_code'; - - public const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; - + public const USER_COUNT_EXCEEDED = 'user_count_exceeded'; + public const USER_JWT_INVALID = 'user_jwt_invalid'; + public const USER_ALREADY_EXISTS = 'user_already_exists'; + public const USER_BLOCKED = 'user_blocked'; + public const USER_INVALID_TOKEN = 'user_invalid_token'; + public const USER_PASSWORD_RESET_REQUIRED = 'user_password_reset_required'; + public const USER_EMAIL_NOT_WHITELISTED = 'user_email_not_whitelisted'; + public const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; + public const USER_INVALID_CODE = 'user_invalid_code'; + public const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; public const USER_ANONYMOUS_CONSOLE_PROHIBITED = 'user_anonymous_console_prohibited'; - - public const USER_SESSION_ALREADY_EXISTS = 'user_session_already_exists'; - - public const USER_NOT_FOUND = 'user_not_found'; - - public const USER_PASSWORD_RECENTLY_USED = 'password_recently_used'; - - public const USER_PASSWORD_PERSONAL_DATA = 'password_personal_data'; - - public const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; - - public const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; - - public const USER_SESSION_NOT_FOUND = 'user_session_not_found'; - - public const USER_IDENTITY_NOT_FOUND = 'user_identity_not_found'; - - public const USER_UNAUTHORIZED = 'user_unauthorized'; - - public const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; - - public const USER_PHONE_ALREADY_EXISTS = 'user_phone_already_exists'; - - public const USER_PHONE_NOT_FOUND = 'user_phone_not_found'; - - public const USER_MISSING_ID = 'user_missing_id'; - - public const USER_OAUTH2_BAD_REQUEST = 'user_oauth2_bad_request'; - - public const USER_OAUTH2_UNAUTHORIZED = 'user_oauth2_unauthorized'; - - public const USER_OAUTH2_PROVIDER_ERROR = 'user_oauth2_provider_error'; - - public const USER_TARGET_NOT_FOUND = 'user_target_not_found'; - - public const USER_TARGET_ALREADY_EXISTS = 'user_target_already_exists'; - + public const USER_SESSION_ALREADY_EXISTS = 'user_session_already_exists'; + public const USER_NOT_FOUND = 'user_not_found'; + public const USER_PASSWORD_RECENTLY_USED = 'password_recently_used'; + public const USER_PASSWORD_PERSONAL_DATA = 'password_personal_data'; + public const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; + public const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; + public const USER_SESSION_NOT_FOUND = 'user_session_not_found'; + public const USER_IDENTITY_NOT_FOUND = 'user_identity_not_found'; + public const USER_UNAUTHORIZED = 'user_unauthorized'; + public const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; + public const USER_PHONE_ALREADY_EXISTS = 'user_phone_already_exists'; + public const USER_PHONE_NOT_FOUND = 'user_phone_not_found'; + public const USER_MISSING_ID = 'user_missing_id'; + public const USER_OAUTH2_BAD_REQUEST = 'user_oauth2_bad_request'; + public const USER_OAUTH2_UNAUTHORIZED = 'user_oauth2_unauthorized'; + public const USER_OAUTH2_PROVIDER_ERROR = 'user_oauth2_provider_error'; + public const USER_TARGET_NOT_FOUND = 'user_target_not_found'; + public const USER_TARGET_ALREADY_EXISTS = 'user_target_already_exists'; /** Teams */ - public const TEAM_NOT_FOUND = 'team_not_found'; - - public const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; - - public const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; - - public const TEAM_INVALID_SECRET = 'team_invalid_secret'; - - public const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; - - public const TEAM_INVITE_MISMATCH = 'team_invite_mismatch'; - - public const TEAM_ALREADY_EXISTS = 'team_already_exists'; + public const TEAM_NOT_FOUND = 'team_not_found'; + public const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; + public const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; + public const TEAM_INVALID_SECRET = 'team_invalid_secret'; + public const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; + public const TEAM_INVITE_MISMATCH = 'team_invite_mismatch'; + public const TEAM_ALREADY_EXISTS = 'team_already_exists'; /** Membership */ - public const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; - - public const MEMBERSHIP_ALREADY_CONFIRMED = 'membership_already_confirmed'; + public const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; + public const MEMBERSHIP_ALREADY_CONFIRMED = 'membership_already_confirmed'; /** Avatars */ - public const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; - - public const AVATAR_NOT_FOUND = 'avatar_not_found'; - - public const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; - - public const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; - - public const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; + public const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; + public const AVATAR_NOT_FOUND = 'avatar_not_found'; + public const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; + public const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; + public const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; /** Storage */ - public const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; - - public const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; - - public const STORAGE_FILE_EMPTY = 'storage_file_empty'; - - public const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; - - public const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; - - public const STORAGE_INVALID_FILE = 'storage_invalid_file'; - - public const STORAGE_BUCKET_ALREADY_EXISTS = 'storage_bucket_already_exists'; - - public const STORAGE_BUCKET_NOT_FOUND = 'storage_bucket_not_found'; - - public const STORAGE_INVALID_CONTENT_RANGE = 'storage_invalid_content_range'; - - public const STORAGE_INVALID_RANGE = 'storage_invalid_range'; - - public const STORAGE_INVALID_APPWRITE_ID = 'storage_invalid_appwrite_id'; + public const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; + public const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; + public const STORAGE_FILE_EMPTY = 'storage_file_empty'; + public const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; + public const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; + public const STORAGE_INVALID_FILE = 'storage_invalid_file'; + public const STORAGE_BUCKET_ALREADY_EXISTS = 'storage_bucket_already_exists'; + public const STORAGE_BUCKET_NOT_FOUND = 'storage_bucket_not_found'; + public const STORAGE_INVALID_CONTENT_RANGE = 'storage_invalid_content_range'; + public const STORAGE_INVALID_RANGE = 'storage_invalid_range'; + public const STORAGE_INVALID_APPWRITE_ID = 'storage_invalid_appwrite_id'; /** Functions */ - public const FUNCTION_NOT_FOUND = 'function_not_found'; - - public const FUNCTION_RUNTIME_UNSUPPORTED = 'function_runtime_unsupported'; + public const FUNCTION_NOT_FOUND = 'function_not_found'; + public const FUNCTION_RUNTIME_UNSUPPORTED = 'function_runtime_unsupported'; /** Deployments */ - public const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; + public const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; /** Builds */ - public const BUILD_NOT_FOUND = 'build_not_found'; - - public const BUILD_NOT_READY = 'build_not_ready'; - - public const BUILD_IN_PROGRESS = 'build_in_progress'; + public const BUILD_NOT_FOUND = 'build_not_found'; + public const BUILD_NOT_READY = 'build_not_ready'; + public const BUILD_IN_PROGRESS = 'build_in_progress'; /** Execution */ - public const EXECUTION_NOT_FOUND = 'execution_not_found'; + public const EXECUTION_NOT_FOUND = 'execution_not_found'; /** Databases */ - public const DATABASE_NOT_FOUND = 'database_not_found'; - - public const DATABASE_ALREADY_EXISTS = 'database_already_exists'; + public const DATABASE_NOT_FOUND = 'database_not_found'; + public const DATABASE_ALREADY_EXISTS = 'database_already_exists'; /** Collections */ - public const COLLECTION_NOT_FOUND = 'collection_not_found'; - - public const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; - - public const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; + public const COLLECTION_NOT_FOUND = 'collection_not_found'; + public const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; + public const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; /** Documents */ - public const DOCUMENT_NOT_FOUND = 'document_not_found'; - - public const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; - - public const DOCUMENT_MISSING_DATA = 'document_missing_data'; - - public const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; - - public const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; - - public const DOCUMENT_UPDATE_CONFLICT = 'document_update_conflict'; - - public const DOCUMENT_DELETE_RESTRICTED = 'document_delete_restricted'; + public const DOCUMENT_NOT_FOUND = 'document_not_found'; + public const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; + public const DOCUMENT_MISSING_DATA = 'document_missing_data'; + public const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; + public const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; + public const DOCUMENT_UPDATE_CONFLICT = 'document_update_conflict'; + public const DOCUMENT_DELETE_RESTRICTED = 'document_delete_restricted'; /** Attribute */ - public const ATTRIBUTE_NOT_FOUND = 'attribute_not_found'; - - public const ATTRIBUTE_UNKNOWN = 'attribute_unknown'; - - public const ATTRIBUTE_NOT_AVAILABLE = 'attribute_not_available'; - - public const ATTRIBUTE_FORMAT_UNSUPPORTED = 'attribute_format_unsupported'; - - public const ATTRIBUTE_DEFAULT_UNSUPPORTED = 'attribute_default_unsupported'; - - public const ATTRIBUTE_ALREADY_EXISTS = 'attribute_already_exists'; - - public const ATTRIBUTE_LIMIT_EXCEEDED = 'attribute_limit_exceeded'; - - public const ATTRIBUTE_VALUE_INVALID = 'attribute_value_invalid'; - - public const ATTRIBUTE_TYPE_INVALID = 'attribute_type_invalid'; + public const ATTRIBUTE_NOT_FOUND = 'attribute_not_found'; + public const ATTRIBUTE_UNKNOWN = 'attribute_unknown'; + public const ATTRIBUTE_NOT_AVAILABLE = 'attribute_not_available'; + public const ATTRIBUTE_FORMAT_UNSUPPORTED = 'attribute_format_unsupported'; + public const ATTRIBUTE_DEFAULT_UNSUPPORTED = 'attribute_default_unsupported'; + public const ATTRIBUTE_ALREADY_EXISTS = 'attribute_already_exists'; + public const ATTRIBUTE_LIMIT_EXCEEDED = 'attribute_limit_exceeded'; + public const ATTRIBUTE_VALUE_INVALID = 'attribute_value_invalid'; + public const ATTRIBUTE_TYPE_INVALID = 'attribute_type_invalid'; /** Indexes */ - public const INDEX_NOT_FOUND = 'index_not_found'; - - public const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; - - public const INDEX_ALREADY_EXISTS = 'index_already_exists'; - - public const INDEX_INVALID = 'index_invalid'; + public const INDEX_NOT_FOUND = 'index_not_found'; + public const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; + public const INDEX_ALREADY_EXISTS = 'index_already_exists'; + public const INDEX_INVALID = 'index_invalid'; /** Projects */ - public const PROJECT_NOT_FOUND = 'project_not_found'; + public const PROJECT_NOT_FOUND = 'project_not_found'; + public const PROJECT_UNKNOWN = 'project_unknown'; + public const PROJECT_PROVIDER_DISABLED = 'project_provider_disabled'; + public const PROJECT_PROVIDER_UNSUPPORTED = 'project_provider_unsupported'; + public const PROJECT_ALREADY_EXISTS = 'project_already_exists'; + public const PROJECT_INVALID_SUCCESS_URL = 'project_invalid_success_url'; + public const PROJECT_INVALID_FAILURE_URL = 'project_invalid_failure_url'; + public const PROJECT_RESERVED_PROJECT = 'project_reserved_project'; + public const PROJECT_KEY_EXPIRED = 'project_key_expired'; - public const PROJECT_UNKNOWN = 'project_unknown'; - - public const PROJECT_PROVIDER_DISABLED = 'project_provider_disabled'; - - public const PROJECT_PROVIDER_UNSUPPORTED = 'project_provider_unsupported'; - - public const PROJECT_ALREADY_EXISTS = 'project_already_exists'; - - public const PROJECT_INVALID_SUCCESS_URL = 'project_invalid_success_url'; - - public const PROJECT_INVALID_FAILURE_URL = 'project_invalid_failure_url'; - - public const PROJECT_RESERVED_PROJECT = 'project_reserved_project'; - - public const PROJECT_KEY_EXPIRED = 'project_key_expired'; - - public const PROJECT_SMTP_CONFIG_INVALID = 'project_smtp_config_invalid'; + public const PROJECT_SMTP_CONFIG_INVALID = 'project_smtp_config_invalid'; public const PROJECT_TEMPLATE_DEFAULT_DELETION = 'project_template_default_deletion'; /** Webhooks */ - public const WEBHOOK_NOT_FOUND = 'webhook_not_found'; + public const WEBHOOK_NOT_FOUND = 'webhook_not_found'; /** Keys */ - public const KEY_NOT_FOUND = 'key_not_found'; + public const KEY_NOT_FOUND = 'key_not_found'; /** Variables */ - public const VARIABLE_NOT_FOUND = 'variable_not_found'; - - public const VARIABLE_ALREADY_EXISTS = 'variable_already_exists'; + public const VARIABLE_NOT_FOUND = 'variable_not_found'; + public const VARIABLE_ALREADY_EXISTS = 'variable_already_exists'; /** Platform */ - public const PLATFORM_NOT_FOUND = 'platform_not_found'; + public const PLATFORM_NOT_FOUND = 'platform_not_found'; /** Domain */ - public const DOMAIN_NOT_FOUND = 'domain_not_found'; - - public const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; - - public const DOMAIN_FORBIDDEN = 'domain_forbidden'; - - public const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; - - public const DOMAIN_TARGET_INVALID = 'domain_target_invalid'; + public const DOMAIN_NOT_FOUND = 'domain_not_found'; + public const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; + public const DOMAIN_FORBIDDEN = 'domain_forbidden'; + public const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; + public const DOMAIN_TARGET_INVALID = 'domain_target_invalid'; /** GraphqQL */ - public const GRAPHQL_NO_QUERY = 'graphql_no_query'; - - public const GRAPHQL_TOO_MANY_QUERIES = 'graphql_too_many_queries'; + public const GRAPHQL_NO_QUERY = 'graphql_no_query'; + public const GRAPHQL_TOO_MANY_QUERIES = 'graphql_too_many_queries'; /** Migrations */ - public const MIGRATION_NOT_FOUND = 'migration_not_found'; - - public const MIGRATION_ALREADY_EXISTS = 'migration_already_exists'; - - public const MIGRATION_IN_PROGRESS = 'migration_in_progress'; + public const MIGRATION_NOT_FOUND = 'migration_not_found'; + public const MIGRATION_ALREADY_EXISTS = 'migration_already_exists'; + public const MIGRATION_IN_PROGRESS = 'migration_in_progress'; /** Provider */ - public const PROVIDER_NOT_FOUND = 'provider_not_found'; - - public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; + public const PROVIDER_NOT_FOUND = 'provider_not_found'; + public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; protected $type = ''; - protected $errors = []; public function __construct(string $type = Exception::GENERAL_UNKNOWN, string $message = null, int $code = null, \Throwable $previous = null) @@ -356,7 +248,8 @@ class Exception extends \Exception /** * Set the type of the exception. * - * @param string $type + * @param string $type + * * @return void */ public function setType(string $type): void diff --git a/src/Appwrite/GraphQL/Promises/Adapter.php b/src/Appwrite/GraphQL/Promises/Adapter.php index 0051dbe612..86270f2a8b 100644 --- a/src/Appwrite/GraphQL/Promises/Adapter.php +++ b/src/Appwrite/GraphQL/Promises/Adapter.php @@ -22,15 +22,14 @@ abstract class Adapter implements PromiseAdapter /** * Converts a {@see Promise} into a {@see GQLPromise} * - * @param mixed $thenable + * @param mixed $thenable * @return GQLPromise - * * @throws \Exception */ public function convertThenable(mixed $thenable): GQLPromise { - if (! $thenable instanceof Promise) { - throw new \Exception('Expected instance of Promise got: '.\gettype($thenable)); + if (!$thenable instanceof Promise) { + throw new \Exception('Expected instance of Promise got: ' . \gettype($thenable)); } return new GQLPromise($thenable, $this); @@ -39,9 +38,9 @@ abstract class Adapter implements PromiseAdapter /** * Returns a promise that resolves when the passed in promise resolves. * - * @param GQLPromise $promise - * @param callable|null $onFulfilled - * @param callable|null $onRejected + * @param GQLPromise $promise + * @param callable|null $onFulfilled + * @param callable|null $onRejected * @return GQLPromise */ public function then( @@ -58,7 +57,7 @@ abstract class Adapter implements PromiseAdapter /** * Create a new promise with the given resolver function. * - * @param callable $resolver + * @param callable $resolver * @return GQLPromise */ abstract public function create(callable $resolver): GQLPromise; @@ -66,7 +65,7 @@ abstract class Adapter implements PromiseAdapter /** * Create a new promise that is fulfilled with the given value. * - * @param mixed $value + * @param mixed $value * @return GQLPromise */ abstract public function createFulfilled(mixed $value = null): GQLPromise; @@ -74,7 +73,7 @@ abstract class Adapter implements PromiseAdapter /** * Create a new promise that is rejected with the given reason. * - * @param mixed $reason + * @param mixed $reason * @return GQLPromise */ abstract public function createRejected(mixed $reason): GQLPromise; @@ -82,7 +81,7 @@ abstract class Adapter implements PromiseAdapter /** * Create a new promise that resolves when all passed in promises resolve. * - * @param array $promisesOrValues + * @param array $promisesOrValues * @return GQLPromise */ abstract public function all(array $promisesOrValues): GQLPromise; diff --git a/src/Appwrite/GraphQL/Resolvers.php b/src/Appwrite/GraphQL/Resolvers.php index 3c5ba4b310..c143a93554 100644 --- a/src/Appwrite/GraphQL/Resolvers.php +++ b/src/Appwrite/GraphQL/Resolvers.php @@ -15,28 +15,28 @@ class Resolvers /** * Create a resolver for a given API {@see Route}. * - * @param App $utopia - * @param ?Route $route + * @param App $utopia + * @param ?Route $route * @return callable */ public static function api( App $utopia, ?Route $route, - ): callable - { - return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $route, $args) { + ): callable { + return static fn($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $route, $args, $context, $info) { /** @var App $utopia */ /** @var Response $response */ /** @var Request $request */ + $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); $path = $route->getPath(); foreach ($args as $key => $value) { - if (\str_contains($path, '/:'.$key)) { - $path = \str_replace(':'.$key, $value, $path); + if (\str_contains($path, '/:' . $key)) { + $path = \str_replace(':' . $key, $value, $path); } } @@ -60,10 +60,10 @@ class Resolvers /** * Create a resolver for a document in a specified database and collection with a specific method type. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param string $methodType + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param string $methodType * @return callable */ public static function document( @@ -71,9 +71,8 @@ class Resolvers string $databaseId, string $collectionId, string $methodType, - ): callable - { - return [self::class, 'document'.\ucfirst($methodType)]( + ): callable { + return [self::class, 'document' . \ucfirst($methodType)]( $utopia, $databaseId, $collectionId @@ -83,10 +82,10 @@ class Resolvers /** * Create a resolver for getting a document in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url * @return callable */ public static function documentGet( @@ -94,10 +93,9 @@ class Resolvers string $databaseId, string $collectionId, callable $url, - ): callable - { - return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $args) { + ): callable { + return static fn($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -113,11 +111,11 @@ class Resolvers /** * Create a resolver for listing documents in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url - * @param callable $params + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url + * @param callable $params * @return callable */ public static function documentList( @@ -126,10 +124,9 @@ class Resolvers string $collectionId, callable $url, callable $params, - ): callable - { - return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { + ): callable { + return static fn($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -150,11 +147,11 @@ class Resolvers /** * Create a resolver for creating a document in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url - * @param callable $params + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url + * @param callable $params * @return callable */ public static function documentCreate( @@ -163,10 +160,9 @@ class Resolvers string $collectionId, callable $url, callable $params, - ): callable - { - return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { + ): callable { + return static fn($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -183,11 +179,11 @@ class Resolvers /** * Create a resolver for updating a document in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url - * @param callable $params + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url + * @param callable $params * @return callable */ public static function documentUpdate( @@ -196,10 +192,9 @@ class Resolvers string $collectionId, callable $url, callable $params, - ): callable - { - return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { + ): callable { + return static fn($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -216,10 +211,10 @@ class Resolvers /** * Create a resolver for deleting a document in a specified database and collection. * - * @param App $utopia - * @param string $databaseId - * @param string $collectionId - * @param callable $url + * @param App $utopia + * @param string $databaseId + * @param string $collectionId + * @param callable $url * @return callable */ public static function documentDelete( @@ -227,10 +222,9 @@ class Resolvers string $databaseId, string $collectionId, callable $url, - ): callable - { - return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $args) { + ): callable { + return static fn($type, $args, $context, $info) => new Swoole( + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -244,15 +238,14 @@ class Resolvers } /** - * @param App $utopia - * @param Request $request - * @param Response $response - * @param callable $resolve - * @param callable $reject - * @param callable|null $beforeResolve - * @param callable|null $beforeReject + * @param App $utopia + * @param Request $request + * @param Response $response + * @param callable $resolve + * @param callable $reject + * @param callable|null $beforeResolve + * @param callable|null $beforeReject * @return void - * * @throws Exception */ private static function resolve( @@ -270,7 +263,7 @@ class Resolvers } $request = clone $request; - $utopia->setResource('request', static fn () => $request); + $utopia->setResource('request', static fn() => $request); $response->setContentType(Response::CONTENT_TYPE_NULL); try { @@ -282,7 +275,6 @@ class Resolvers $e = $beforeReject($e); } $reject($e); - return; } @@ -296,7 +288,6 @@ class Resolvers message: $payload['message'], code: $response->getStatusCode() )); - return; } diff --git a/src/Appwrite/GraphQL/Schema.php b/src/Appwrite/GraphQL/Schema.php index 608369ef80..11f728e571 100644 --- a/src/Appwrite/GraphQL/Schema.php +++ b/src/Appwrite/GraphQL/Schema.php @@ -13,17 +13,16 @@ use Utopia\Route; class Schema { protected static ?GQLSchema $schema = null; - protected static array $dirty = []; /** - * @param App $utopia - * @param callable $complexity Function to calculate complexity - * @param callable $attributes Function to get attributes - * @param array $urls Array of functions to get urls for specific method types - * @param array $params Array of functions to build parameters for specific method types - * @return GQLSchema * + * @param App $utopia + * @param callable $complexity Function to calculate complexity + * @param callable $attributes Function to get attributes + * @param array $urls Array of functions to get urls for specific method types + * @param array $params Array of functions to build parameters for specific method types + * @return GQLSchema * @throws Exception */ public static function build( @@ -37,7 +36,7 @@ class Schema return $utopia; }); - if (! empty(self::$schema)) { + if (!empty(self::$schema)) { return self::$schema; } @@ -68,12 +67,12 @@ class Schema return static::$schema = new GQLSchema([ 'query' => new ObjectType([ 'name' => 'Query', - 'fields' => $queries, + 'fields' => $queries ]), 'mutation' => new ObjectType([ 'name' => 'Mutation', - 'fields' => $mutations, - ]), + 'fields' => $mutations + ]) ]); } @@ -81,10 +80,9 @@ class Schema * This function iterates all API routes and builds a GraphQL * schema defining types and resolvers for all response models. * - * @param App $utopia - * @param callable $complexity + * @param App $utopia + * @param callable $complexity * @return array - * * @throws Exception */ protected static function api(App $utopia, callable $complexity): array @@ -99,9 +97,10 @@ class Schema foreach ($utopia->getRoutes() as $routes) { foreach ($routes as $route) { /** @var Route $route */ + $namespace = $route->getLabel('sdk.namespace', ''); $method = $route->getLabel('sdk.method', ''); - $name = $namespace.\ucfirst($method); + $name = $namespace . \ucfirst($method); if (empty($name)) { continue; @@ -127,7 +126,7 @@ class Schema return [ 'query' => $queries, - 'mutation' => $mutations, + 'mutation' => $mutations ]; } @@ -135,13 +134,12 @@ class Schema * Iterates all of a projects attributes and builds GraphQL * queries and mutations for the collections they make up. * - * @param App $utopia - * @param callable $complexity - * @param callable $attributes - * @param array $urls - * @param array $params + * @param App $utopia + * @param callable $complexity + * @param callable $attributes + * @param array $urls + * @param array $params * @return array - * * @throws \Exception */ protected static function collections( @@ -157,7 +155,7 @@ class Schema $limit = 1000; $offset = 0; - while (! empty($attrs = $attributes($limit, $offset))) { + while (!empty($attrs = $attributes($limit, $offset))) { foreach ($attrs as $attr) { if ($attr['status'] !== 'available') { continue; @@ -184,7 +182,7 @@ class Schema $objectType = new ObjectType([ 'name' => $collectionId, 'fields' => \array_merge( - ['_id' => ['type' => Type::string()]], + ["_id" => ['type' => Type::string()]], $attributes ), ]); @@ -193,7 +191,7 @@ class Schema Mapper::args('mutate') ); - $queryFields[$collectionId.'Get'] = [ + $queryFields[$collectionId . 'Get'] = [ 'type' => $objectType, 'args' => Mapper::args('id'), 'resolve' => Resolvers::documentGet( @@ -201,9 +199,9 @@ class Schema $databaseId, $collectionId, $urls['get'], - ), + ) ]; - $queryFields[$collectionId.'List'] = [ + $queryFields[$collectionId . 'List'] = [ 'type' => Type::listOf($objectType), 'args' => Mapper::args('list'), 'resolve' => Resolvers::documentList( @@ -216,7 +214,7 @@ class Schema 'complexity' => $complexity, ]; - $mutationFields[$collectionId.'Create'] = [ + $mutationFields[$collectionId . 'Create'] = [ 'type' => $objectType, 'args' => $attributes, 'resolve' => Resolvers::documentCreate( @@ -225,14 +223,14 @@ class Schema $collectionId, $urls['create'], $params['create'], - ), + ) ]; - $mutationFields[$collectionId.'Update'] = [ + $mutationFields[$collectionId . 'Update'] = [ 'type' => $objectType, 'args' => \array_merge( Mapper::args('id'), \array_map( - fn ($attr) => $attr['type'] = Type::getNullableType($attr['type']), + fn($attr) => $attr['type'] = Type::getNullableType($attr['type']), $attributes ) ), @@ -242,9 +240,9 @@ class Schema $collectionId, $urls['update'], $params['update'], - ), + ) ]; - $mutationFields[$collectionId.'Delete'] = [ + $mutationFields[$collectionId . 'Delete'] = [ 'type' => Mapper::model('none'), 'args' => Mapper::args('id'), 'resolve' => Resolvers::documentDelete( @@ -252,7 +250,7 @@ class Schema $databaseId, $collectionId, $urls['delete'], - ), + ) ]; } $offset += $limit; @@ -260,7 +258,7 @@ class Schema return [ 'query' => $queryFields, - 'mutation' => $mutationFields, + 'mutation' => $mutationFields ]; } diff --git a/src/Appwrite/GraphQL/Types.php b/src/Appwrite/GraphQL/Types.php index b20c4cb32e..279cac2068 100644 --- a/src/Appwrite/GraphQL/Types.php +++ b/src/Appwrite/GraphQL/Types.php @@ -22,7 +22,6 @@ class Types } $type = new Json(); Registry::set(Json::class, $type); - return $type; } @@ -38,7 +37,6 @@ class Types } $type = new Assoc(); Registry::set(Assoc::class, $type); - return $type; } @@ -54,7 +52,6 @@ class Types } $type = new InputFile(); Registry::set(InputFile::class, $type); - return $type; } } diff --git a/src/Appwrite/GraphQL/Types/Assoc.php b/src/Appwrite/GraphQL/Types/Assoc.php index 58584ff60f..a2099f9b22 100644 --- a/src/Appwrite/GraphQL/Types/Assoc.php +++ b/src/Appwrite/GraphQL/Types/Assoc.php @@ -2,13 +2,19 @@ namespace Appwrite\GraphQL\Types; +use GraphQL\Language\AST\BooleanValueNode; +use GraphQL\Language\AST\FloatValueNode; +use GraphQL\Language\AST\IntValueNode; +use GraphQL\Language\AST\ListValueNode; use GraphQL\Language\AST\Node; +use GraphQL\Language\AST\ObjectValueNode; +use GraphQL\Language\AST\StringValueNode; +use GraphQL\Type\Definition\ScalarType; // https://github.com/webonyx/graphql-php/issues/129#issuecomment-309366803 class Assoc extends Json { public $name = 'Assoc'; - public $description = 'The `Assoc` scalar type represents associative array values.'; public function serialize($value) diff --git a/src/Appwrite/GraphQL/Types/InputFile.php b/src/Appwrite/GraphQL/Types/InputFile.php index 6d55ab5359..39fd4e23b3 100644 --- a/src/Appwrite/GraphQL/Types/InputFile.php +++ b/src/Appwrite/GraphQL/Types/InputFile.php @@ -9,7 +9,6 @@ use GraphQL\Type\Definition\ScalarType; class InputFile extends ScalarType { public $name = 'InputFile'; - public $description = 'The `InputFile` special type represents a file to be uploaded in the same HTTP request as specified by [graphql-multipart-request-spec](https://github.com/jaydenseric/graphql-multipart-request-spec).'; @@ -25,6 +24,6 @@ class InputFile extends ScalarType public function parseLiteral(Node $valueNode, ?array $variables = null) { - throw new Error('`InputFile` cannot be hardcoded in query, be sure to conform to GraphQL multipart request specification. Instead got: '.$valueNode->kind, $valueNode); + throw new Error('`InputFile` cannot be hardcoded in query, be sure to conform to GraphQL multipart request specification. Instead got: ' . $valueNode->kind, $valueNode); } } diff --git a/src/Appwrite/GraphQL/Types/Json.php b/src/Appwrite/GraphQL/Types/Json.php index 305432cb90..18d27322a1 100644 --- a/src/Appwrite/GraphQL/Types/Json.php +++ b/src/Appwrite/GraphQL/Types/Json.php @@ -15,7 +15,6 @@ use GraphQL\Type\Definition\ScalarType; class Json extends ScalarType { public $name = 'Json'; - public $description = 'The `JSON` scalar type represents JSON values as specified by [ECMA-404](https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).'; @@ -44,9 +43,8 @@ class Json extends ScalarType $value[$field->name->value] = $this->parseLiteral($field->value); } - return $value; - case $valueNode instanceof ListValueNode: + case ($valueNode instanceof ListValueNode): return array_map([$this, 'parseLiteral'], $valueNode->values); default: return null; diff --git a/src/Appwrite/GraphQL/Types/Mapper.php b/src/Appwrite/GraphQL/Types/Mapper.php index 1c03074f23..0be60d93dc 100644 --- a/src/Appwrite/GraphQL/Types/Mapper.php +++ b/src/Appwrite/GraphQL/Types/Mapper.php @@ -16,9 +16,7 @@ use Utopia\Validator\Nullable; class Mapper { private static array $models = []; - private static array $args = []; - private static array $blacklist = [ '/v1/mock', '/v1/graphql', @@ -45,7 +43,7 @@ class Mapper 'permissions' => [ 'type' => Type::listOf(Type::nonNull(Type::string())), 'defaultValue' => [], - ], + ] ], ]; @@ -68,7 +66,7 @@ class Mapper /** * Get the registered default arguments for a given key. * - * @param string $key + * @param string $key * @return array */ public static function args(string $key): array @@ -89,7 +87,7 @@ class Mapper $names = $route->getLabel('sdk.response.model', 'none'); $models = \is_array($names) - ? \array_map(static fn ($m) => static::$models[$m], $names) + ? \array_map(static fn($m) => static::$models[$m], $names) : [static::$models[$names]]; foreach ($models as $model) { @@ -105,7 +103,7 @@ class Mapper $parameterType = Mapper::param( $utopia, $parameter['validator'], - ! $parameter['optional'], + !$parameter['optional'], $parameter['injections'] ); $params[$name] = [ @@ -118,7 +116,7 @@ class Mapper 'type' => $type, 'description' => $description, 'args' => $params, - 'resolve' => Resolvers::api($utopia, $route), + 'resolve' => Resolvers::api($utopia, $route) ]; if ($list) { @@ -132,7 +130,7 @@ class Mapper /** * Get a type from the registry, creating it if it does not already exist. * - * @param string $name + * @param string $name * @return Type */ public static function model(string $name): Type @@ -151,23 +149,23 @@ class Mapper 'description' => 'Additional data', 'resolve' => static function ($object, $args, $context, $info) { $data = \array_filter( - (array) $object, - fn ($key) => ! \str_starts_with($key, '_'), + (array)$object, + fn($key) => !\str_starts_with($key, '_'), ARRAY_FILTER_USE_KEY ); return \json_encode($data, JSON_FORCE_OBJECT); - }, + } ]; } // If model has no properties, explicitly add a 'status' field // because GraphQL requires at least 1 field per type. - if (! $model->isAny() && empty($model->getRules())) { + if (!$model->isAny() && empty($model->getRules())) { $fields['status'] = [ 'type' => Type::string(), 'description' => 'Status', - 'resolve' => static fn ($object, $args, $context, $info) => 'OK', + 'resolve' => static fn($object, $args, $context, $info) => 'OK', ]; } @@ -189,7 +187,7 @@ class Mapper 'description' => $rule['description'], ]; - if (! $rule['required']) { + if (!$rule['required']) { $fields[$escapedKey]['defaultValue'] = $rule['default']; } } @@ -207,12 +205,11 @@ class Mapper /** * Map a {@see Route} parameter to a GraphQL Type * - * @param App $utopia - * @param Validator|callable $validator - * @param bool $required - * @param array $injections + * @param App $utopia + * @param Validator|callable $validator + * @param bool $required + * @param array $injections * @return Type - * * @throws Exception */ public static function param( @@ -231,7 +228,7 @@ class Mapper $validator = $validator->getValidator(); } - switch ((! empty($validator)) ? $validator::class : '') { + switch ((!empty($validator)) ? $validator::class : '') { case 'Appwrite\Network\Validator\CNAME': case 'Appwrite\Task\Validator\Cron': case 'Appwrite\Utopia\Database\Validator\CustomId': @@ -303,7 +300,7 @@ class Mapper break; } - if ($required && ! $isNullable) { + if ($required && !$isNullable) { $type = Type::nonNull($type); } @@ -313,11 +310,10 @@ class Mapper /** * Map an {@see Attribute} to a GraphQL Type * - * @param string $type - * @param bool $array - * @param bool $required + * @param string $type + * @param bool $array + * @param bool $required * @return Type - * * @throws Exception */ public static function attribute(string $type, bool $array, bool $required): Type @@ -353,7 +349,6 @@ class Mapper } $complexModel = self::$models[$type]; - return self::model(\ucfirst($complexModel->getType())); } @@ -394,7 +389,7 @@ class Mapper return static::getHashOptionsImplementation($object); } - throw new Exception('Unknown union type: '.$name); + throw new Exception('Unknown union type: ' . $name); } private static function getAttributeImplementation(array $object): Type diff --git a/src/Appwrite/GraphQL/Types/Registry.php b/src/Appwrite/GraphQL/Types/Registry.php index 325766bb67..cd40d5c3e4 100644 --- a/src/Appwrite/GraphQL/Types/Registry.php +++ b/src/Appwrite/GraphQL/Types/Registry.php @@ -11,7 +11,7 @@ class Registry /** * Check if a type exists in the registry. * - * @param string $type + * @param string $type * @return bool */ public static function has(string $type): bool @@ -22,7 +22,7 @@ class Registry /** * Get a type from the registry. * - * @param string $type + * @param string $type * @return Type */ public static function get(string $type): Type @@ -33,8 +33,8 @@ class Registry /** * Set a type in the registry. * - * @param string $type - * @param Type $typeObject + * @param string $type + * @param Type $typeObject */ public static function set(string $type, Type $typeObject): void { diff --git a/src/Appwrite/Messaging/Adapter.php b/src/Appwrite/Messaging/Adapter.php index 794fd9b3ed..27dd7f68eb 100644 --- a/src/Appwrite/Messaging/Adapter.php +++ b/src/Appwrite/Messaging/Adapter.php @@ -5,8 +5,6 @@ namespace Appwrite\Messaging; abstract class Adapter { abstract public function subscribe(string $projectId, mixed $identifier, array $roles, array $channels): void; - abstract public function unsubscribe(mixed $identifier): void; - abstract public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options): void; } diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php index 2824f948d7..33fe484c13 100644 --- a/src/Appwrite/Messaging/Adapter/Realtime.php +++ b/src/Appwrite/Messaging/Adapter/Realtime.php @@ -2,10 +2,10 @@ namespace Appwrite\Messaging\Adapter; -use Appwrite\Messaging\Adapter; -use Utopia\App; use Utopia\Database\DateTime; use Utopia\Database\Document; +use Appwrite\Messaging\Adapter; +use Utopia\App; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; @@ -39,20 +39,20 @@ class Realtime extends Adapter /** * Adds a subscription. * - * @param string $projectId - * @param mixed $identifier - * @param array $roles - * @param array $channels + * @param string $projectId + * @param mixed $identifier + * @param array $roles + * @param array $channels * @return void */ public function subscribe(string $projectId, mixed $identifier, array $roles, array $channels): void { - if (! isset($this->subscriptions[$projectId])) { // Init Project + if (!isset($this->subscriptions[$projectId])) { // Init Project $this->subscriptions[$projectId] = []; } foreach ($roles as $role) { - if (! isset($this->subscriptions[$projectId][$role])) { // Add user first connection + if (!isset($this->subscriptions[$projectId][$role])) { // Add user first connection $this->subscriptions[$projectId][$role] = []; } @@ -64,14 +64,14 @@ class Realtime extends Adapter $this->connections[$identifier] = [ 'projectId' => $projectId, 'roles' => $roles, - 'channels' => $channels, + 'channels' => $channels ]; } /** * Removes Subscription. * - * @param mixed $connection + * @param mixed $connection * @return void */ public function unsubscribe(mixed $connection): void @@ -102,10 +102,9 @@ class Realtime extends Adapter /** * Checks if Channel has a subscriber. - * - * @param string $projectId - * @param string $role - * @param string $channel + * @param string $projectId + * @param string $role + * @param string $channel * @return bool */ public function hasSubscriber(string $projectId, string $role, string $channel = ''): bool @@ -123,13 +122,12 @@ class Realtime extends Adapter /** * Sends an event to the Realtime Server - * - * @param string $projectId - * @param array $payload - * @param string $event - * @param array $channels - * @param array $roles - * @param array $options + * @param string $projectId + * @param array $payload + * @param string $event + * @param array $channels + * @param array $roles + * @param array $options * @return void */ public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options = []): void @@ -152,8 +150,8 @@ class Realtime extends Adapter 'events' => $events, 'channels' => $channels, 'timestamp' => DateTime::formatTz(DateTime::now()), - 'payload' => $payload, - ], + 'payload' => $payload + ] ])); } @@ -168,10 +166,11 @@ class Realtime extends Adapter * - 110.201 ms (±2.32%) | 100,000 Connections / 1,000,000 Subscriptions * - 1,121.328 ms (±0.84%) | 1,000,000 Connections / 10,000,000 Subscriptions * - * @param array $event + * @param array $event */ public function getSubscribers(array $event) { + $receivers = []; /** * Check if project has subscriber. @@ -213,9 +212,8 @@ class Realtime extends Adapter /** * Converts the channels from the Query Params into an array. * Also renames the account channel to account.USER_ID and removes all illegal account channel variations. - * - * @param array $channels - * @param string $userId + * @param array $channels + * @param string $userId * @return array */ public static function convertChannels(array $channels, string $userId): array @@ -229,8 +227,8 @@ class Realtime extends Adapter break; case $key === 'account': - if (! empty($userId)) { - $channels['account.'.$userId] = $value; + if (!empty($userId)) { + $channels['account.' . $userId] = $value; } break; } @@ -242,9 +240,9 @@ class Realtime extends Adapter /** * Create channels array based on the event name and payload. * - * @param string $event - * @param Document $payload - * @param Document|null $project + * @param string $event + * @param Document $payload + * @param Document|null $project * @return array */ public static function fromPayload(string $event, Document $payload, Document $project = null, Document $database = null, Document $collection = null, Document $bucket = null): array @@ -259,18 +257,18 @@ class Realtime extends Adapter switch ($parts[0]) { case 'users': $channels[] = 'account'; - $channels[] = 'account.'.$parts[1]; + $channels[] = 'account.' . $parts[1]; $roles = [Role::user(ID::custom($parts[1]))->toString()]; break; case 'teams': if ($parts[2] === 'memberships') { $permissionsChanged = $parts[4] ?? false; $channels[] = 'memberships'; - $channels[] = 'memberships.'.$parts[3]; + $channels[] = 'memberships.' . $parts[3]; } else { $permissionsChanged = $parts[2] === 'create'; $channels[] = 'teams'; - $channels[] = 'teams.'.$parts[1]; + $channels[] = 'teams.' . $parts[1]; } $roles = [Role::team(ID::custom($parts[1]))->toString()]; break; @@ -288,8 +286,8 @@ class Realtime extends Adapter } $channels[] = 'documents'; - $channels[] = 'databases.'.$database->getId().'.collections.'.$payload->getAttribute('$collectionId').'.documents'; - $channels[] = 'databases.'.$database->getId().'.collections.'.$payload->getAttribute('$collectionId').'.documents.'.$payload->getId(); + $channels[] = 'databases.' . $database->getId() . '.collections.' . $payload->getAttribute('$collectionId') . '.documents'; + $channels[] = 'databases.' . $database->getId() . '.collections.' . $payload->getAttribute('$collectionId') . '.documents.' . $payload->getId(); $roles = $collection->getAttribute('documentSecurity', false) ? \array_merge($collection->getRead(), $payload->getRead()) @@ -302,8 +300,8 @@ class Realtime extends Adapter throw new \Exception('Bucket needs to be passed to Realtime for File events in the Storage.'); } $channels[] = 'files'; - $channels[] = 'buckets.'.$payload->getAttribute('bucketId').'.files'; - $channels[] = 'buckets.'.$payload->getAttribute('bucketId').'.files.'.$payload->getId(); + $channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files'; + $channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files.' . $payload->getId(); $roles = $bucket->getAttribute('fileSecurity', false) ? \array_merge($bucket->getRead(), $payload->getRead()) @@ -314,11 +312,11 @@ class Realtime extends Adapter case 'functions': if ($parts[2] === 'executions') { - if (! empty($payload->getRead())) { + if (!empty($payload->getRead())) { $channels[] = 'console'; $channels[] = 'executions'; - $channels[] = 'executions.'.$payload->getId(); - $channels[] = 'functions.'.$payload->getAttribute('functionId'); + $channels[] = 'executions.' . $payload->getId(); + $channels[] = 'functions.' . $payload->getAttribute('functionId'); $roles = $payload->getRead(); } } elseif ($parts[2] === 'deployments') { @@ -334,7 +332,7 @@ class Realtime extends Adapter 'channels' => $channels, 'roles' => $roles, 'permissionsChanged' => $permissionsChanged, - 'projectId' => $projectId, + 'projectId' => $projectId ]; } } diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 2685d81829..9ea3443091 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -2,15 +2,15 @@ namespace Appwrite\Migration; -use Exception; use Swoole\Runtime; -use Utopia\App; +use Utopia\Database\Document; +use Utopia\Database\Database; +use Utopia\Database\Query; use Utopia\CLI\Console; use Utopia\Config\Config; -use Utopia\Database\Database; -use Utopia\Database\Document; +use Exception; +use Utopia\App; use Utopia\Database\Helpers\ID; -use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; Runtime::enableCoroutine(SWOOLE_HOOK_ALL); @@ -80,25 +80,26 @@ abstract class Migration $this->collections = array_merge([ '_metadata' => [ '$id' => ID::custom('_metadata'), - '$collection' => Database::METADATA, + '$collection' => Database::METADATA ], 'audit' => [ '$id' => ID::custom('audit'), - '$collection' => Database::METADATA, + '$collection' => Database::METADATA ], 'abuse' => [ '$id' => ID::custom('abuse'), - '$collection' => Database::METADATA, - ], + '$collection' => Database::METADATA + ] ], Config::getParam('collections', [])); } /** * Set project for migration. * - * @param Document $project - * @param Database $projectDB - * @param Database $oldConsoleDB + * @param Document $project + * @param Database $projectDB + * @param Database $oldConsoleDB + * * @return self */ public function setProject(Document $project, Database $projectDB, Database $consoleDB): self @@ -113,7 +114,7 @@ abstract class Migration /** * Set PDO for Migration. * - * @param \PDO $pdo + * @param \PDO $pdo * @return \Appwrite\Migration\Migration */ public function setPDO(\PDO $pdo): self @@ -126,7 +127,7 @@ abstract class Migration /** * Iterates through every document. * - * @param callable $callback + * @param callable $callback */ public function forEachDocument(callable $callback): void { @@ -135,7 +136,7 @@ abstract class Migration continue; } - Console::log('Migrating Collection '.$collection['$id'].':'); + Console::log('Migrating Collection ' . $collection['$id'] . ':'); \Co\run(function (array $collection, callable $callback) { foreach ($this->documentsIterator($collection['$id']) as $document) { @@ -147,15 +148,14 @@ abstract class Migration $old = $document->getArrayCopy(); $new = call_user_func($callback, $document); - if (is_null($new) || ! self::hasDifference($new->getArrayCopy(), $old)) { + if (is_null($new) || !self::hasDifference($new->getArrayCopy(), $old)) { return; } try { $new = $this->projectDB->updateDocument($document->getCollection(), $document->getId(), $document); } catch (\Throwable $th) { - Console::error('Failed to update document: '.$th->getMessage()); - + Console::error('Failed to update document: ' . $th->getMessage()); return; } }, $document, $callback); @@ -167,9 +167,8 @@ abstract class Migration /** * Provides an iterator for all documents on a collection. * - * @param string $collectionId + * @param string $collectionId * @return iterable - * * @throws \Exception */ public function documentsIterator(string $collectionId): iterable @@ -187,7 +186,7 @@ abstract class Migration $count = count($documents); $sum += $count; - Console::log($sum.' / '.$collectionCount); + Console::log($sum . ' / ' . $collectionCount); foreach ($documents as $document) { yield $document; } @@ -197,28 +196,28 @@ abstract class Migration } else { $nextDocument = end($documents); } - } while (! is_null($nextDocument)); + } while (!is_null($nextDocument)); } /** * Checks 2 arrays for differences. * - * @param array $array1 - * @param array $array2 + * @param array $array1 + * @param array $array2 * @return bool */ public static function hasDifference(array $array1, array $array2): bool { foreach ($array1 as $key => $value) { if (is_array($value)) { - if (! isset($array2[$key]) || ! is_array($array2[$key])) { + if (!isset($array2[$key]) || !is_array($array2[$key])) { return true; } else { if (self::hasDifference($value, $array2[$key])) { return true; } } - } elseif (! array_key_exists($key, $array2) || $array2[$key] !== $value) { + } elseif (!array_key_exists($key, $array2) || $array2[$key] !== $value) { return true; } } @@ -229,17 +228,16 @@ abstract class Migration /** * Creates colletion from the config collection. * - * @param string $id - * @param string|null $name + * @param string $id + * @param string|null $name * @return void - * * @throws \Throwable */ protected function createCollection(string $id, string $name = null): void { $name ??= $id; - if (! $this->projectDB->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), $name)) { + if (!$this->projectDB->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), $name)) { $attributes = []; $indexes = []; $collection = $this->collections[$id]; @@ -277,11 +275,10 @@ abstract class Migration /** * Creates attribute from collections.php * - * @param \Utopia\Database\Database $database - * @param string $collectionId - * @param string $attributeId + * @param \Utopia\Database\Database $database + * @param string $collectionId + * @param string $attributeId * @return void - * * @throws \Exception * @throws \Utopia\Database\Exception\Duplicate * @throws \Utopia\Database\Exception\Limit @@ -323,12 +320,11 @@ abstract class Migration /** * Creates index from collections.php * - * @param \Utopia\Database\Database $database - * @param string $collectionId - * @param string $indexId - * @param string|null $from + * @param \Utopia\Database\Database $database + * @param string $collectionId + * @param string $indexId + * @param string|null $from * @return void - * * @throws \Exception * @throws \Utopia\Database\Exception\Duplicate * @throws \Utopia\Database\Exception\Limit @@ -364,9 +360,9 @@ abstract class Migration /** * Change a collection attribute's internal type * - * @param string $collection - * @param string $attribute - * @param string $type + * @param string $collection + * @param string $attribute + * @param string $type * @return void */ protected function changeAttributeInternalType(string $collection, string $attribute, string $type): void diff --git a/src/Appwrite/Migration/Version/V15.php b/src/Appwrite/Migration/Version/V15.php index dadf971675..b6deb780da 100644 --- a/src/Appwrite/Migration/Version/V15.php +++ b/src/Appwrite/Migration/Version/V15.php @@ -4,6 +4,8 @@ namespace Appwrite\Migration\Version; use Appwrite\Migration\Migration; use Appwrite\OpenSSL\OpenSSL; +use Exception; +use PDO; use Utopia\App; use Utopia\CLI\Console; use Utopia\Config\Config; @@ -31,7 +33,7 @@ class V15 extends Migration $this->providers = \array_merge( ['email', 'anonymous'], \array_map( - fn ($value) => 'oauth-'.$value, + fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('authProviders', [])) ) ); @@ -47,7 +49,7 @@ class V15 extends Migration ); } - Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); + Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); Console::info('Migrating Stats'); $this->migrateStatsMetric('requests', 'project.$all.network.requests'); $this->migrateStatsMetric('network', 'project.$all.network.bandwidth'); @@ -74,7 +76,6 @@ class V15 extends Migration * Migrating all Bucket tables. * * @return void - * * @throws \Exception * @throws \PDOException */ @@ -107,7 +108,7 @@ class V15 extends Migration addCreatePermission: true ); - if (! is_null($bucket->getAttribute('permission'))) { + if (!is_null($bucket->getAttribute('permission'))) { $bucket->setAttribute('fileSecurity', $bucket->getAttribute('permissions') === 'document'); } @@ -151,7 +152,6 @@ class V15 extends Migration * Migrating all Database and Collection tables. * * @return void - * * @throws \Exception * @throws \PDOException */ @@ -229,7 +229,7 @@ class V15 extends Migration addCreatePermission: true ); - if (! is_null($collection->getAttribute('permission'))) { + if (!is_null($collection->getAttribute('permission'))) { $collection->setAttribute('documentSecurity', $collection->getAttribute('permissions') === 'document'); } @@ -249,10 +249,9 @@ class V15 extends Migration $requiredAttributes = array_reduce($collection->getAttribute('attributes', []), function (array $carry, Document $item) { if ($item->getAttribute('required', false)) { $carry = array_merge($carry, [ - $item->getAttribute('key') => $item->getAttribute('default'), + $item->getAttribute('key') => $item->getAttribute('default') ]); } - return $carry; }, []); @@ -290,7 +289,7 @@ class V15 extends Migration /** * Removes all 'write' permissions from a table. * - * @param string $table + * @param string $table * @return void */ protected function removeWritePermissions(string $table): void @@ -305,9 +304,8 @@ class V15 extends Migration /** * Returns all columns from the Table. * - * @param string $table + * @param string $table * @return array - * * @throws \Exception * @throws \PDOException */ @@ -327,7 +325,6 @@ class V15 extends Migration * Migrates all Integer colums for timestamps to DateTime. * * @return void - * * @throws \Exception */ protected function migrateDateTimeAttribute(string $table, string $attribute): void @@ -355,7 +352,7 @@ class V15 extends Migration /** * Skip adding filter on internal attributes. */ - if (! str_starts_with($attribute, '_')) { + if (!str_starts_with($attribute, '_')) { try { /** * Add datetime filter. @@ -381,9 +378,8 @@ class V15 extends Migration /** * Create the '_permissions' column to a table. * - * @param string $table + * @param string $table * @return void - * * @throws \Exception * @throws \PDOException */ @@ -391,7 +387,7 @@ class V15 extends Migration { $columns = $this->getSQLColumnTypes($table); - if (! array_key_exists('_permissions', $columns)) { + if (!array_key_exists('_permissions', $columns)) { try { $this->pdo->prepare("ALTER TABLE IF EXISTS `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_{$table}` ADD `_permissions` MEDIUMTEXT DEFAULT NULL")->execute(); } catch (\Throwable $th) { @@ -403,11 +399,10 @@ class V15 extends Migration /** * Populate '$permissions' from '$read' and '$write'. * - * @param \Utopia\Database\Document $document - * @param null|string $table - * @param bool $addCreatePermission + * @param \Utopia\Database\Document $document + * @param null|string $table + * @param bool $addCreatePermission * @return void - * * @throws \Exception * @throws \PDOException */ @@ -448,7 +443,7 @@ class V15 extends Migration /** * Migrates a permission string * - * @param string $permission + * @param string $permission * @return string */ protected function migratePermission(string $permission): string @@ -735,7 +730,7 @@ class V15 extends Migration foreach ($this->documentsIterator($id) as $function) { $vars = $function->getAttribute('vars', []); - if (! is_array($vars)) { + if (!is_array($vars)) { continue; } @@ -756,7 +751,7 @@ class V15 extends Migration 'functionInternalId' => $function->getInternalId(), 'key' => (string) $key, 'value' => (string) $value, - 'search' => implode(' ', [$variableId, $key, $function->getId()]), + 'search' => implode(' ', [$variableId, $key, $function->getId()]) ]); $this->projectDB->createDocument('variables', $variable); } @@ -1228,7 +1223,7 @@ class V15 extends Migration /** * Fix run on each document * - * @param \Utopia\Database\Document $document + * @param \Utopia\Database\Document $document * @return \Utopia\Database\Document */ protected function fixDocument(Document $document) @@ -1479,14 +1474,14 @@ class V15 extends Migration $this->pdo->prepare("UPDATE `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_stats` SET metric = {$to} WHERE metric = {$from}")->execute(); } catch (\Throwable $th) { - Console::warning("Migrating steps from {$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_stats:".$th->getMessage()); + Console::warning("Migrating steps from {$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_stats:" . $th->getMessage()); } } /** * Filter from the 'encrypt' filter. * - * @param string $value + * @param string $value * @return string|false */ protected function encryptFilter(string $value): string diff --git a/src/Appwrite/Migration/Version/V16.php b/src/Appwrite/Migration/Version/V16.php index 761a274e0f..bee2236dfb 100644 --- a/src/Appwrite/Migration/Version/V16.php +++ b/src/Appwrite/Migration/Version/V16.php @@ -24,7 +24,7 @@ class V16 extends Migration ); } - Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); + Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); Console::info('Migrating Collections'); $this->migrateCollections(); @@ -102,7 +102,7 @@ class V16 extends Migration /** * Fix run on each document * - * @param \Utopia\Database\Document $document + * @param \Utopia\Database\Document $document * @return \Utopia\Database\Document */ protected function fixDocument(Document $document) @@ -118,7 +118,7 @@ class V16 extends Migration * Set default authDuration */ $document->setAttribute('auths', array_merge($document->getAttribute('auths', []), [ - 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, + 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG ])); /** @@ -127,16 +127,16 @@ class V16 extends Migration $authProviders = $document->getAttribute('authProviders', []); foreach (Config::getParam('authProviders') as $provider => $value) { - if (! $value['enabled']) { + if (!$value['enabled']) { continue; } - if (($authProviders[$provider.'Appid'] ?? false) && ($authProviders[$provider.'Secret'] ?? false)) { - if (array_key_exists($provider.'Enabled', $authProviders)) { + if (($authProviders[$provider . 'Appid'] ?? false) && ($authProviders[$provider . 'Secret'] ?? false)) { + if (array_key_exists($provider . 'Enabled', $authProviders)) { continue; } - $authProviders[$provider.'Enabled'] = true; + $authProviders[$provider . 'Enabled'] = true; } } diff --git a/src/Appwrite/Migration/Version/V17.php b/src/Appwrite/Migration/Version/V17.php index 421c86bcc8..3f744d8069 100644 --- a/src/Appwrite/Migration/Version/V17.php +++ b/src/Appwrite/Migration/Version/V17.php @@ -23,7 +23,7 @@ class V17 extends Migration ); } - Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); + Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); Console::info('Migrating Collections'); $this->migrateCollections(); @@ -33,11 +33,11 @@ class V17 extends Migration $this->forEachDocument([$this, 'fixDocument']); } + /** * Migrating all Bucket tables. * * @return void - * * @throws \Exception * @throws \PDOException */ @@ -234,7 +234,7 @@ class V17 extends Migration /** * Fix run on each document * - * @param \Utopia\Database\Document $document + * @param \Utopia\Database\Document $document * @return \Utopia\Database\Document */ protected function fixDocument(Document $document) @@ -250,15 +250,15 @@ class V17 extends Migration * Set default maxSessions */ $document->setAttribute('auths', array_merge($document->getAttribute('auths', []), [ - 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, + 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT ])); break; case 'users': - /** + /** * Set hashOptions type */ $document->setAttribute('hashOptions', array_merge($document->getAttribute('hashOptions', []), [ - 'type' => $document->getAttribute('hash', Auth::DEFAULT_ALGO), + 'type' => $document->getAttribute('hash', Auth::DEFAULT_ALGO) ])); break; } diff --git a/src/Appwrite/Migration/Version/V18.php b/src/Appwrite/Migration/Version/V18.php index 2b3b98088d..839269f940 100644 --- a/src/Appwrite/Migration/Version/V18.php +++ b/src/Appwrite/Migration/Version/V18.php @@ -13,6 +13,7 @@ class V18 extends Migration { public function execute(): void { + /** * Disable SubQueries for Performance. */ @@ -24,7 +25,7 @@ class V18 extends Migration ); } - Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); + Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); $this->addDocumentSecurityToProject(); @@ -42,7 +43,6 @@ class V18 extends Migration * Migrate all Databases. * * @return void - * * @throws \Exception */ private function migrateDatabases(): void @@ -154,7 +154,7 @@ class V18 extends Migration /** * Fix run on each document * - * @param Document $document + * @param Document $document * @return Document */ protected function fixDocument(Document $document): Document diff --git a/src/Appwrite/Migration/Version/V19.php b/src/Appwrite/Migration/Version/V19.php index fe9bde6d29..39522aff0b 100644 --- a/src/Appwrite/Migration/Version/V19.php +++ b/src/Appwrite/Migration/Version/V19.php @@ -2,6 +2,8 @@ namespace Appwrite\Migration\Version; +use Appwrite\Auth\Auth; +use Utopia\Config\Config; use Appwrite\Migration\Migration; use Utopia\CLI\Console; use Utopia\Database\Database; @@ -11,6 +13,7 @@ class V19 extends Migration { public function execute(): void { + /** * Disable SubQueries for Performance. */ @@ -22,7 +25,7 @@ class V19 extends Migration ); } - Console::log('Migrating Project: '.$this->project->getAttribute('name').' ('.$this->project->getId().')'); + Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); $this->alterPermissionIndex('_metadata'); @@ -45,7 +48,6 @@ class V19 extends Migration * Migrate all Databases. * * @return void - * * @throws \Exception */ private function migrateDatabases(): void @@ -97,7 +99,7 @@ class V19 extends Migration default: break; } - if (! in_array($id, ['files', 'collections'])) { + if (!in_array($id, ['files', 'collections'])) { $this->alterPermissionIndex($id); $this->alterUidType($id); } @@ -109,7 +111,7 @@ class V19 extends Migration /** * Fix run on each document * - * @param Document $document + * @param Document $document * @return Document */ protected function fixDocument(Document $document): Document @@ -161,7 +163,6 @@ class V19 extends Migration * Migrating all Bucket tables. * * @return void - * * @throws \Exception * @throws \PDOException */ diff --git a/src/Appwrite/Network/Validator/CNAME.php b/src/Appwrite/Network/Validator/CNAME.php index 3840322137..678a57cecd 100644 --- a/src/Appwrite/Network/Validator/CNAME.php +++ b/src/Appwrite/Network/Validator/CNAME.php @@ -12,7 +12,7 @@ class CNAME extends Validator protected $target; /** - * @param string $target + * @param string $target */ public function __construct($target) { @@ -30,12 +30,13 @@ class CNAME extends Validator /** * Check if CNAME record target value matches selected target * - * @param mixed $domain + * @param mixed $domain + * * @return bool */ public function isValid($domain): bool { - if (! is_string($domain)) { + if (!is_string($domain)) { return false; } @@ -45,7 +46,7 @@ class CNAME extends Validator return false; } - if (! $records) { + if (!$records) { return false; } diff --git a/src/Appwrite/Network/Validator/Email.php b/src/Appwrite/Network/Validator/Email.php index 232437aab7..efc1a5d5b3 100644 --- a/src/Appwrite/Network/Validator/Email.php +++ b/src/Appwrite/Network/Validator/Email.php @@ -8,6 +8,8 @@ use Utopia\Validator; * Email * * Validate that an variable is a valid email address + * + * @package Utopia\Validator */ class Email extends Validator { @@ -28,12 +30,12 @@ class Email extends Validator * * Validation will pass when $value is valid email address. * - * @param mixed $value + * @param mixed $value * @return bool */ public function isValid($value): bool { - if (! \filter_var($value, FILTER_VALIDATE_EMAIL)) { + if (!\filter_var($value, FILTER_VALIDATE_EMAIL)) { return false; } diff --git a/src/Appwrite/Network/Validator/Origin.php b/src/Appwrite/Network/Validator/Origin.php index 78065c0e48..508961ab9e 100644 --- a/src/Appwrite/Network/Validator/Origin.php +++ b/src/Appwrite/Network/Validator/Origin.php @@ -2,55 +2,35 @@ namespace Appwrite\Network\Validator; -use Utopia\Validator; use Utopia\Validator\Hostname; +use Utopia\Validator; class Origin extends Validator { public const CLIENT_TYPE_UNKNOWN = 'unknown'; - public const CLIENT_TYPE_WEB = 'web'; - public const CLIENT_TYPE_FLUTTER_IOS = 'flutter-ios'; - public const CLIENT_TYPE_FLUTTER_ANDROID = 'flutter-android'; - public const CLIENT_TYPE_FLUTTER_MACOS = 'flutter-macos'; - public const CLIENT_TYPE_FLUTTER_WINDOWS = 'flutter-windows'; - public const CLIENT_TYPE_FLUTTER_LINUX = 'flutter-linux'; - public const CLIENT_TYPE_FLUTTER_WEB = 'flutter-web'; - public const CLIENT_TYPE_APPLE_IOS = 'apple-ios'; - public const CLIENT_TYPE_APPLE_MACOS = 'apple-macos'; - public const CLIENT_TYPE_APPLE_WATCHOS = 'apple-watchos'; - public const CLIENT_TYPE_APPLE_TVOS = 'apple-tvos'; - public const CLIENT_TYPE_ANDROID = 'android'; - public const CLIENT_TYPE_UNITY = 'unity'; + public const SCHEME_TYPE_HTTP = 'http'; - public const SCHEME_TYPE_HTTPS = 'https'; - public const SCHEME_TYPE_IOS = 'appwrite-ios'; - public const SCHEME_TYPE_MACOS = 'appwrite-macos'; - public const SCHEME_TYPE_WATCHOS = 'appwrite-watchos'; - public const SCHEME_TYPE_TVOS = 'appwrite-tvos'; - public const SCHEME_TYPE_ANDROID = 'appwrite-android'; - public const SCHEME_TYPE_WINDOWS = 'appwrite-windows'; - public const SCHEME_TYPE_LINUX = 'appwrite-linux'; /** @@ -85,7 +65,7 @@ class Origin extends Validator protected $host = ''; /** - * @param string $target + * @param string $target */ public function __construct($platforms) { @@ -112,7 +92,7 @@ class Origin extends Validator break; default: - // code... + # code... break; } } @@ -120,24 +100,25 @@ class Origin extends Validator public function getDescription(): string { - if (! \array_key_exists($this->client, $this->platforms)) { + if (!\array_key_exists($this->client, $this->platforms)) { return 'Unsupported platform'; } - return 'Invalid Origin. Register your new client ('.$this->host.') as a new ' - .$this->platforms[$this->client].' platform on your project console dashboard'; + return 'Invalid Origin. Register your new client (' . $this->host . ') as a new ' + . $this->platforms[$this->client] . ' platform on your project console dashboard'; } /** * Check if Origin has been allowed * for access to the API * - * @param mixed $origin + * @param mixed $origin + * * @return bool */ public function isValid($origin): bool { - if (! is_string($origin)) { + if (!is_string($origin)) { return false; } diff --git a/src/Appwrite/OpenSSL/OpenSSL.php b/src/Appwrite/OpenSSL/OpenSSL.php index 2eed67dd3e..1965a3c858 100644 --- a/src/Appwrite/OpenSSL/OpenSSL.php +++ b/src/Appwrite/OpenSSL/OpenSSL.php @@ -10,11 +10,12 @@ class OpenSSL * @param $data * @param $method * @param $key - * @param int $options - * @param string $iv - * @param null $tag - * @param string $aad - * @param int $tag_length + * @param int $options + * @param string $iv + * @param null $tag + * @param string $aad + * @param int $tag_length + * * @return string */ public static function encrypt($data, $method, $key, $options = 0, $iv = '', &$tag = null, $aad = '', $tag_length = 16) @@ -26,10 +27,11 @@ class OpenSSL * @param $data * @param $method * @param $password - * @param int $options - * @param string $iv - * @param string $tag - * @param string $aad + * @param int $options + * @param string $iv + * @param string $tag + * @param string $aad + * * @return string */ public static function decrypt($data, $method, $password, $options = 1, $iv = '', $tag = '', $aad = '') @@ -38,7 +40,8 @@ class OpenSSL } /** - * @param string $method + * @param string $method + * * @return int */ public static function cipherIVLength($method) @@ -48,7 +51,8 @@ class OpenSSL /** * @param $length - * @param null $crypto_strong + * @param null $crypto_strong + * * @return false|string */ public static function randomPseudoBytes($length, &$crypto_strong = null) diff --git a/src/Appwrite/Platform/Services/Tasks.php b/src/Appwrite/Platform/Services/Tasks.php index a24d72be2f..9e919127bf 100644 --- a/src/Appwrite/Platform/Services/Tasks.php +++ b/src/Appwrite/Platform/Services/Tasks.php @@ -2,25 +2,26 @@ namespace Appwrite\Platform\Services; -use Appwrite\Platform\Tasks\CalcTierStats; -use Appwrite\Platform\Tasks\CalcUsersStats; -use Appwrite\Platform\Tasks\ClearCardCache; +use Utopia\Platform\Service; use Appwrite\Platform\Tasks\Doctor; -use Appwrite\Platform\Tasks\Hamster; use Appwrite\Platform\Tasks\Install; use Appwrite\Platform\Tasks\Maintenance; use Appwrite\Platform\Tasks\Migrate; -use Appwrite\Platform\Tasks\PatchCreateMissingSchedules; -use Appwrite\Platform\Tasks\PatchDeleteProjectCollections; -use Appwrite\Platform\Tasks\PatchDeleteScheduleUpdatedAtAttribute; use Appwrite\Platform\Tasks\Schedule; +use Appwrite\Platform\Tasks\PatchCreateMissingSchedules; use Appwrite\Platform\Tasks\SDKs; use Appwrite\Platform\Tasks\Specs; use Appwrite\Platform\Tasks\SSL; +use Appwrite\Platform\Tasks\Hamster; +use Appwrite\Platform\Tasks\PatchDeleteScheduleUpdatedAtAttribute; +use Appwrite\Platform\Tasks\ClearCardCache; +use Appwrite\Platform\Tasks\Usage; use Appwrite\Platform\Tasks\Vars; use Appwrite\Platform\Tasks\Version; use Appwrite\Platform\Tasks\VolumeSync; -use Utopia\Platform\Service; +use Appwrite\Platform\Tasks\CalcUsersStats; +use Appwrite\Platform\Tasks\CalcTierStats; +use Appwrite\Platform\Tasks\PatchDeleteProjectCollections; class Tasks extends Service { @@ -45,6 +46,7 @@ class Tasks extends Service ->addAction(Specs::getName(), new Specs()) ->addAction(CalcUsersStats::getName(), new CalcUsersStats()) ->addAction(CalcTierStats::getName(), new CalcTierStats()) - ->addAction(PatchDeleteProjectCollections::getName(), new PatchDeleteProjectCollections()); + ->addAction(PatchDeleteProjectCollections::getName(), new PatchDeleteProjectCollections()) + ; } } diff --git a/src/Appwrite/Platform/Tasks/CalcTierStats.php b/src/Appwrite/Platform/Tasks/CalcTierStats.php index 0dc795cbcd..d660709940 100644 --- a/src/Appwrite/Platform/Tasks/CalcTierStats.php +++ b/src/Appwrite/Platform/Tasks/CalcTierStats.php @@ -4,15 +4,15 @@ namespace Appwrite\Platform\Tasks; use Exception; use League\Csv\CannotInsertRecord; -use League\Csv\Writer; -use PHPMailer\PHPMailer\PHPMailer; use Utopia\App; +use Utopia\Database\Validator\Authorization; +use Utopia\Platform\Action; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; -use Utopia\Platform\Action; +use League\Csv\Writer; +use PHPMailer\PHPMailer\PHPMailer; use Utopia\Pools\Group; use Utopia\Registry\Registry; @@ -44,13 +44,11 @@ class CalcTierStats extends Action ]; protected string $directory = '/usr/local'; - protected string $path; - protected string $date; private array $usageStats = [ - 'project.$all.network.requests' => 'Requests', + 'project.$all.network.requests' => 'Requests', 'project.$all.network.bandwidth' => 'Bandwidth', ]; @@ -62,6 +60,7 @@ class CalcTierStats extends Action public function __construct() { + $this ->desc('Get stats for projects') ->inject('pools') @@ -82,7 +81,7 @@ class CalcTierStats extends Action //docker compose exec -t appwrite calc-tier-stats Console::title('Cloud free tier stats calculation V1'); - Console::success(APP_NAME.' cloud free tier stats calculation has started'); + Console::success(APP_NAME . ' cloud free tier stats calculation has started'); /* Initialise new Utopia app */ $app = new App('UTC'); @@ -103,8 +102,9 @@ class CalcTierStats extends Action $limit = 30; $sum = 30; $offset = 0; - while (! empty($projects)) { + while (!empty($projects)) { foreach ($projects as $project) { + /** * Skip user projects with id 'console' */ @@ -123,18 +123,18 @@ class CalcTierStats extends Action $dbForProject = new Database($adapter, $cache); $dbForProject->setDefaultDatabase('appwrite'); - $dbForProject->setNamespace('_'.$project->getInternalId()); + $dbForProject->setNamespace('_' . $project->getInternalId()); /** Get Project ID */ $stats['Project ID'] = $project->getId(); - $stats['Organization ID'] = $project->getAttribute('teamId', null); + $stats['Organization ID'] = $project->getAttribute('teamId', null); /** Get Total Members */ $teamInternalId = $project->getAttribute('teamInternalId', null); if ($teamInternalId) { $stats['Organization Members'] = $dbForConsole->count('memberships', [ - Query::equal('teamInternalId', [$teamInternalId]), + Query::equal('teamInternalId', [$teamInternalId]) ]); } else { $stats['Organization Members'] = 0; @@ -195,7 +195,7 @@ class CalcTierStats extends Action }); foreach ($tmp as $key => $value) { - $stats[$metrics[$key]] = $value; + $stats[$metrics[$key]] = $value; } try { @@ -208,27 +208,27 @@ class CalcTierStats extends Action } try { - /** Get Api keys */ + /** Get Api keys */ $stats['Api keys'] = $dbForConsole->count('keys', [ - Query::equal('projectInternalId', [$project->getInternalId()]), + Query::equal('projectInternalId', [$project->getInternalId()]), ]); } catch (\Throwable) { $stats['Api keys'] = 0; } try { - /** Get Webhooks */ + /** Get Webhooks */ $stats['Webhooks'] = $dbForConsole->count('webhooks', [ - Query::equal('projectInternalId', [$project->getInternalId()]), + Query::equal('projectInternalId', [$project->getInternalId()]), ]); } catch (\Throwable) { $stats['Webhooks'] = 0; } try { - /** Get Platforms */ + /** Get Platforms */ $stats['Platforms'] = $dbForConsole->count('platforms', [ - Query::equal('projectInternalId', [$project->getInternalId()]), + Query::equal('projectInternalId', [$project->getInternalId()]), ]); } catch (\Throwable) { $stats['Platforms'] = 0; @@ -242,26 +242,28 @@ class CalcTierStats extends Action try { $buckets = $dbForProject->find('buckets', []); foreach ($buckets as $bucket) { - $file = $dbForProject->findOne('bucket_'.$bucket->getInternalId(), [Query::orderDesc('sizeOriginal')]); + $file = $dbForProject->findOne('bucket_' . $bucket->getInternalId(), [Query::orderDesc('sizeOriginal'),]); if (empty($file)) { continue; } - $filesSum += $dbForProject->sum('bucket_'.$bucket->getInternalId(), 'sizeOriginal', [], 0); - $filesCount += $dbForProject->count('bucket_'.$bucket->getInternalId(), []); + $filesSum += $dbForProject->sum('bucket_' . $bucket->getInternalId(), 'sizeOriginal', [], 0); + $filesCount += $dbForProject->count('bucket_' . $bucket->getInternalId(), []); if ($file->getAttribute('sizeOriginal') > $maxFileSize) { $maxFileSize = $file->getAttribute('sizeOriginal'); } $counter++; } } catch (\Throwable) { + ; } $stats['Buckets'] = $counter; $stats['Files'] = $filesCount; $stats['Storage (bytes)'] = $filesSum; $stats['Max File Size (bytes)'] = $maxFileSize; + try { - /** Get Total Functions */ + /** Get Total Functions */ $stats['Databases'] = $dbForProject->count('databases', []); } catch (\Throwable) { $stats['Databases'] = 0; @@ -290,7 +292,7 @@ class CalcTierStats extends Action $csv->insertOne(array_values($stats)); } catch (\Throwable $th) { - Console::error('Failed on project ("'.$project->getId().'") version with error on File: '.$th->getFile().' line no: '.$th->getline().' with message: '.$th->getMessage()); + Console::error('Failed on project ("' . $project->getId() . '") version with error on File: ' . $th->getFile() . ' line no: ' . $th->getline() . ' with message: ' . $th->getMessage()); } finally { $pools ->get($db) @@ -309,7 +311,7 @@ class CalcTierStats extends Action $count = $count + $sum; } - Console::log('Iterated through '.$count - 1 .'/'.$totalProjects.' projects...'); + Console::log('Iterated through ' . $count - 1 . '/' . $totalProjects . ' projects...'); $pools ->get('console') @@ -339,7 +341,7 @@ class CalcTierStats extends Action /** Content */ $mail->Subject = "Cloud Report for {$this->date}"; - $mail->Body = 'Please find the daily cloud report atttached'; + $mail->Body = "Please find the daily cloud report atttached"; $mail->send(); Console::success('Email has been sent!'); } catch (Exception $e) { diff --git a/src/Appwrite/Platform/Tasks/CalcUsersStats.php b/src/Appwrite/Platform/Tasks/CalcUsersStats.php index 67fcc1a5c5..6310fe17b4 100644 --- a/src/Appwrite/Platform/Tasks/CalcUsersStats.php +++ b/src/Appwrite/Platform/Tasks/CalcUsersStats.php @@ -3,14 +3,14 @@ namespace Appwrite\Platform\Tasks; use Exception; -use League\Csv\Writer; -use PHPMailer\PHPMailer\PHPMailer; use Utopia\App; +use Utopia\Platform\Action; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Query; -use Utopia\Platform\Action; +use League\Csv\Writer; +use PHPMailer\PHPMailer\PHPMailer; use Utopia\Pools\Group; use Utopia\Registry\Registry; @@ -21,13 +21,11 @@ class CalcUsersStats extends Action 'Project Name', 'Team ID', 'Team name', - 'Users', + 'Users' ]; protected string $directory = '/usr/local'; - protected string $path; - protected string $date; public static function getName(): string @@ -37,6 +35,7 @@ class CalcUsersStats extends Action public function __construct() { + $this ->desc('Get stats for projects') ->inject('pools') @@ -53,7 +52,7 @@ class CalcUsersStats extends Action //docker compose exec -t appwrite calc-users-stats Console::title('Cloud Users calculation V1'); - Console::success(APP_NAME.' cloud Users calculation has started'); + Console::success(APP_NAME . ' cloud Users calculation has started'); /* Initialise new Utopia app */ $app = new App('UTC'); @@ -74,8 +73,9 @@ class CalcUsersStats extends Action $limit = 30; $sum = 30; $offset = 0; - while (! empty($projects)) { + while (!empty($projects)) { foreach ($projects as $project) { + /** * Skip user projects with id 'console' */ @@ -94,7 +94,7 @@ class CalcUsersStats extends Action $dbForProject = new Database($adapter, $cache); $dbForProject->setDefaultDatabase('appwrite'); - $dbForProject->setNamespace('_'.$project->getInternalId()); + $dbForProject->setNamespace('_' . $project->getInternalId()); /** Get Project ID */ $stats['Project ID'] = $project->getId(); @@ -102,6 +102,7 @@ class CalcUsersStats extends Action /** Get Project Name */ $stats['Project Name'] = $project->getAttribute('name'); + /** Get Team Name and Id */ $teamId = $project->getAttribute('teamId', null); $teamName = null; @@ -110,7 +111,7 @@ class CalcUsersStats extends Action $teamName = $team->getAttribute('name'); } - $stats['Team ID'] = $teamId; + $stats['Team ID'] = $teamId; $stats['Team name'] = $teamName; /** Get Total Users */ @@ -118,7 +119,7 @@ class CalcUsersStats extends Action $csv->insertOne(array_values($stats)); } catch (\Throwable $th) { - Console::error('Failed to update project ("'.$project->getId().'") version with error: '.$th->getMessage()); + Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage()); } finally { $pools ->get($db) @@ -136,7 +137,7 @@ class CalcUsersStats extends Action $offset = $offset + $limit; $count = $count + $sum; } - Console::log('Iterated through '.$count - 1 .'/'.$totalProjects.' projects...'); + Console::log('Iterated through ' . $count - 1 . '/' . $totalProjects . ' projects...'); $pools ->get('console') ->reclaim(); @@ -165,7 +166,7 @@ class CalcUsersStats extends Action /** Content */ $mail->Subject = "Cloud Report for {$this->date}"; - $mail->Body = 'Please find the daily cloud report atttached'; + $mail->Body = "Please find the daily cloud report atttached"; $mail->send(); Console::success('Email has been sent!'); } catch (Exception $e) { diff --git a/src/Appwrite/Platform/Tasks/ClearCardCache.php b/src/Appwrite/Platform/Tasks/ClearCardCache.php index 59499b6888..d3153b995c 100644 --- a/src/Appwrite/Platform/Tasks/ClearCardCache.php +++ b/src/Appwrite/Platform/Tasks/ClearCardCache.php @@ -4,12 +4,12 @@ namespace Appwrite\Platform\Tasks; use Utopia\Cache\Adapter\Filesystem; use Utopia\Cache\Cache; +use Utopia\Platform\Action; use Utopia\CLI\Console; -use Utopia\Database\Database; use Utopia\Database\Query; +use Utopia\Database\Database; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; -use Utopia\Platform\Action; class ClearCardCache extends Action { @@ -33,12 +33,12 @@ class ClearCardCache extends Action Authorization::setDefaultStatus(false); Console::title('ClearCardCache V1'); - Console::success(APP_NAME.' ClearCardCache v1 has started'); - $resources = ['card/'.$userId, 'card-back/'.$userId, 'card-og/'.$userId]; + Console::success(APP_NAME . ' ClearCardCache v1 has started'); + $resources = ['card/' . $userId, 'card-back/' . $userId, 'card-og/' . $userId]; $caches = Authorization::skip(fn () => $dbForConsole->find('cache', [ Query::equal('resource', $resources), - Query::limit(100), + Query::limit(100) ])); $count = \count($caches); @@ -49,7 +49,7 @@ class ClearCardCache extends Action $key = $cache->getId(); $cacheFolder = new Cache( - new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-console') + new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-console') ); $cacheFolder->purge($key); @@ -57,6 +57,6 @@ class ClearCardCache extends Action Authorization::skip(fn () => $dbForConsole->deleteDocument('cache', $cache->getId())); } - Console::success(APP_NAME.' ClearCardCache v1 has finished'); + Console::success(APP_NAME . ' ClearCardCache v1 has finished'); } } diff --git a/src/Appwrite/Platform/Tasks/Doctor.php b/src/Appwrite/Platform/Tasks/Doctor.php index 8b37e578f4..9a6d6a2847 100644 --- a/src/Appwrite/Platform/Tasks/Doctor.php +++ b/src/Appwrite/Platform/Tasks/Doctor.php @@ -2,16 +2,16 @@ namespace Appwrite\Platform\Tasks; -use Appwrite\ClamAV\Network; use Utopia\App; use Utopia\CLI\Console; -use Utopia\Config\Config; -use Utopia\Domains\Domain; +use Appwrite\ClamAV\Network; use Utopia\Logger\Logger; -use Utopia\Platform\Action; -use Utopia\Registry\Registry; use Utopia\Storage\Device\Local; use Utopia\Storage\Storage; +use Utopia\Config\Config; +use Utopia\Domains\Domain; +use Utopia\Platform\Action; +use Utopia\Registry\Registry; class Doctor extends Action { @@ -35,24 +35,24 @@ class Doctor extends Action / \ ) __/ ) __/\ /\ / ) / )( )( ) _) _ )(( O ) \_/\_/(__) (__) (_/\_)(__\_)(__) (__) (____)(_)(__)\__/ "); - Console::log("\n".'👩‍⚕️ Running '.APP_NAME.' Doctor for version '.App::getEnv('_APP_VERSION', 'UNKNOWN').' ...'."\n"); + Console::log("\n" . '👩‍⚕️ Running ' . APP_NAME . ' Doctor for version ' . App::getEnv('_APP_VERSION', 'UNKNOWN') . ' ...' . "\n"); Console::log('[Settings]'); $domain = new Domain(App::getEnv('_APP_DOMAIN')); - if (! $domain->isKnown() || $domain->isTest()) { - Console::log('🔴 Hostname has no public suffix ('.$domain->get().')'); + if (!$domain->isKnown() || $domain->isTest()) { + Console::log('🔴 Hostname has no public suffix (' . $domain->get() . ')'); } else { - Console::log('🟢 Hostname has a public suffix ('.$domain->get().')'); + Console::log('🟢 Hostname has a public suffix (' . $domain->get() . ')'); } $domain = new Domain(App::getEnv('_APP_DOMAIN_TARGET')); - if (! $domain->isKnown() || $domain->isTest()) { - Console::log('🔴 CNAME target has no public suffix ('.$domain->get().')'); + if (!$domain->isKnown() || $domain->isTest()) { + Console::log('🔴 CNAME target has no public suffix (' . $domain->get() . ')'); } else { - Console::log('🟢 CNAME target has a public suffix ('.$domain->get().')'); + Console::log('🟢 CNAME target has a public suffix (' . $domain->get() . ')'); } if (App::getEnv('_APP_OPENSSL_KEY_V1') === 'your-secret-key' || empty(App::getEnv('_APP_OPENSSL_KEY_V1'))) { @@ -96,21 +96,22 @@ class Doctor extends Action $providerName = App::getEnv('_APP_LOGGING_PROVIDER', ''); $providerConfig = App::getEnv('_APP_LOGGING_CONFIG', ''); - if (empty($providerName) || empty($providerConfig) || ! Logger::hasProvider($providerName)) { + if (empty($providerName) || empty($providerConfig) || !Logger::hasProvider($providerName)) { Console::log('🔴 Logging adapter is disabled'); } else { - Console::log('🟢 Logging adapter is enabled ('.$providerName.')'); + Console::log('🟢 Logging adapter is enabled (' . $providerName . ')'); } \sleep(0.2); try { - Console::log("\n".'[Connectivity]'); + Console::log("\n" . '[Connectivity]'); } catch (\Throwable $th) { //throw $th; } $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + $configs = [ 'Console.DB' => Config::getParam('pools-console'), 'Projects.DB' => Config::getParam('pools-database'), @@ -122,12 +123,12 @@ class Doctor extends Action $adapter = $pools->get($database)->pop()->getResource(); if ($adapter->ping()) { - Console::success('🟢 '.str_pad("{$key}({$database})", 50, '.').'connected'); + Console::success('🟢 ' . str_pad("{$key}({$database})", 50, '.') . 'connected'); } else { - Console::error('🔴 '.str_pad("{$key}({$database})", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("{$key}({$database})", 47, '.') . 'disconnected'); } } catch (\Throwable $th) { - Console::error('🔴 '.str_pad("{$key}.({$database})", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("{$key}.({$database})", 47, '.') . 'disconnected'); } } } @@ -145,12 +146,12 @@ class Doctor extends Action $adapter = $pools->get($pool)->pop()->getResource(); if ($adapter->ping()) { - Console::success('🟢 '.str_pad("{$key}({$pool})", 50, '.').'connected'); + Console::success('🟢 ' . str_pad("{$key}({$pool})", 50, '.') . 'connected'); } else { - Console::error('🔴 '.str_pad("{$key}({$pool})", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("{$key}({$pool})", 47, '.') . 'disconnected'); } } catch (\Throwable $th) { - Console::error('🔴 '.str_pad("{$key}({$pool})", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("{$key}({$pool})", 47, '.') . 'disconnected'); } } } @@ -163,12 +164,12 @@ class Doctor extends Action ); if ((@$antivirus->ping())) { - Console::success('🟢 '.str_pad('Antivirus', 50, '.').'connected'); + Console::success('🟢 ' . str_pad("Antivirus", 50, '.') . 'connected'); } else { - Console::error('🔴 '.str_pad('Antivirus', 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("Antivirus", 47, '.') . 'disconnected'); } } catch (\Throwable $th) { - Console::error('🔴 '.str_pad('Antivirus', 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("Antivirus", 47, '.') . 'disconnected'); } } @@ -181,9 +182,9 @@ class Doctor extends Action $mail->AltBody = 'Hello World'; $mail->send(); - Console::success('🟢 '.str_pad('SMTP', 50, '.').'connected'); + Console::success('🟢 ' . str_pad("SMTP", 50, '.') . 'connected'); } catch (\Throwable $th) { - Console::error('🔴 '.str_pad('SMTP', 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("SMTP", 47, '.') . 'disconnected'); } \sleep(0.2); @@ -193,24 +194,24 @@ class Doctor extends Action foreach ( [ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES, + 'Uploads' => APP_STORAGE_UPLOADS, + 'Cache' => APP_STORAGE_CACHE, + 'Config' => APP_STORAGE_CONFIG, + 'Certs' => APP_STORAGE_CERTIFICATES ] as $key => $volume ) { $device = new Local($volume); if (\is_readable($device->getRoot())) { - Console::success('🟢 '.$key.' Volume is readable'); + Console::success('🟢 ' . $key . ' Volume is readable'); } else { - Console::error('🔴 '.$key.' Volume is unreadable'); + Console::error('🔴 ' . $key . ' Volume is unreadable'); } if (\is_writable($device->getRoot())) { - Console::success('🟢 '.$key.' Volume is writeable'); + Console::success('🟢 ' . $key . ' Volume is writeable'); } else { - Console::error('🔴 '.$key.' Volume is unwriteable'); + Console::error('🔴 ' . $key . ' Volume is unwriteable'); } } @@ -221,10 +222,10 @@ class Doctor extends Action foreach ( [ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES, + 'Uploads' => APP_STORAGE_UPLOADS, + 'Cache' => APP_STORAGE_CACHE, + 'Config' => APP_STORAGE_CONFIG, + 'Certs' => APP_STORAGE_CERTIFICATES ] as $key => $volume ) { $device = new Local($volume); @@ -232,32 +233,32 @@ class Doctor extends Action $percentage = (($device->getPartitionTotalSpace() - $device->getPartitionFreeSpace()) / $device->getPartitionTotalSpace()) * 100; - $message = $key.' Volume has '.Storage::human($device->getPartitionFreeSpace()).' free space ('.\round($percentage, 2).'% used)'; + $message = $key . ' Volume has ' . Storage::human($device->getPartitionFreeSpace()) . ' free space (' . \round($percentage, 2) . '% used)'; if ($percentage < 80) { - Console::success('🟢 '.$message); + Console::success('🟢 ' . $message); } else { - Console::error('🔴 '.$message); + Console::error('🔴 ' . $message); } } try { if (App::isProduction()) { Console::log(''); - $version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost').'/v1/health/version'), true); + $version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost') . '/v1/health/version'), true); if ($version && isset($version['version'])) { if (\version_compare($version['version'], App::getEnv('_APP_VERSION', 'UNKNOWN')) === 0) { - Console::info('You are running the latest version of '.APP_NAME.'! 🥳'); + Console::info('You are running the latest version of ' . APP_NAME . '! 🥳'); } else { - Console::info('A new version ('.$version['version'].') is available! 🥳'."\n"); + Console::info('A new version (' . $version['version'] . ') is available! 🥳' . "\n"); } } else { - Console::error('Failed to check for a newer version'."\n"); + Console::error('Failed to check for a newer version' . "\n"); } } } catch (\Throwable $th) { - Console::error('Failed to check for a newer version'."\n"); + Console::error('Failed to check for a newer version' . "\n"); } } } diff --git a/src/Appwrite/Platform/Tasks/Hamster.php b/src/Appwrite/Platform/Tasks/Hamster.php index 85545f1a19..5b04c338eb 100644 --- a/src/Appwrite/Platform/Tasks/Hamster.php +++ b/src/Appwrite/Platform/Tasks/Hamster.php @@ -4,17 +4,17 @@ namespace Appwrite\Platform\Tasks; use Appwrite\Network\Validator\Origin; use Exception; -use Utopia\Analytics\Adapter\Mixpanel; -use Utopia\Analytics\Event; use Utopia\App; +use Utopia\Platform\Action; use Utopia\Cache\Cache; use Utopia\CLI\Console; -use Utopia\Config\Config; use Utopia\Database\Database; -use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; -use Utopia\Platform\Action; +use Utopia\Analytics\Adapter\Mixpanel; +use Utopia\Analytics\Event; +use Utopia\Config\Config; +use Utopia\Database\Document; use Utopia\Pools\Group; class Hamster extends Action @@ -67,8 +67,7 @@ class Hamster extends Action * Skip user projects with id 'console' */ if ($project->getId() === 'console') { - Console::info('Skipping project console'); - + Console::info("Skipping project console"); return; } @@ -83,7 +82,7 @@ class Hamster extends Action $dbForProject = new Database($adapter, $cache); $dbForProject->setDefaultDatabase('appwrite'); - $dbForProject->setNamespace('_'.$project->getInternalId()); + $dbForProject->setNamespace('_' . $project->getInternalId()); $statsPerProject = []; @@ -102,7 +101,7 @@ class Hamster extends Action $statsPerProject['custom_functions'] = $dbForProject->count('functions', [], APP_LIMIT_COUNT); foreach (\array_keys(Config::getParam('runtimes')) as $runtime) { - $statsPerProject['custom_functions_'.$runtime] = $dbForProject->count('functions', [ + $statsPerProject['custom_functions_' . $runtime] = $dbForProject->count('functions', [ Query::equal('runtime', [$runtime]), ], APP_LIMIT_COUNT); } @@ -117,7 +116,7 @@ class Hamster extends Action $teamInternalId = $project->getAttribute('teamInternalId', null); if ($teamInternalId) { $statsPerProject['custom_organization_members'] = $dbForConsole->count('memberships', [ - Query::equal('teamInternalId', [$teamInternalId]), + Query::equal('teamInternalId', [$teamInternalId]) ], APP_LIMIT_COUNT); } else { $statsPerProject['custom_organization_members'] = 0; @@ -129,8 +128,8 @@ class Hamster extends Action Query::equal('teamInternalId', [$teamInternalId]), ]); - if (! $membership || $membership->isEmpty()) { - throw new Exception('Membership not found. Skipping project : '.$project->getId()); + if (!$membership || $membership->isEmpty()) { + throw new Exception('Membership not found. Skipping project : ' . $project->getId()); } $userInternalId = $membership->getAttribute('userInternalId', null); @@ -147,42 +146,42 @@ class Hamster extends Action /** Get Domains */ $statsPerProject['custom_domains'] = $dbForConsole->count('domains', [ Query::equal('projectInternalId', [$project->getInternalId()]), - Query::limit(APP_LIMIT_COUNT), + Query::limit(APP_LIMIT_COUNT) ]); /** Get Platforms */ $platforms = $dbForConsole->find('platforms', [ Query::equal('projectInternalId', [$project->getInternalId()]), - Query::limit(APP_LIMIT_COUNT), + Query::limit(APP_LIMIT_COUNT) ]); - $statsPerProject['custom_platforms_web'] = count(array_filter($platforms, function ($platform) { + $statsPerProject['custom_platforms_web'] = sizeof(array_filter($platforms, function ($platform) { return $platform['type'] === 'web'; })); - $statsPerProject['custom_platforms_android'] = count(array_filter($platforms, function ($platform) { + $statsPerProject['custom_platforms_android'] = sizeof(array_filter($platforms, function ($platform) { return $platform['type'] === 'android'; })); - $statsPerProject['custom_platforms_apple'] = count(array_filter($platforms, function ($platform) { + $statsPerProject['custom_platforms_apple'] = sizeof(array_filter($platforms, function ($platform) { return str_contains($platform['type'], 'apple'); })); - $statsPerProject['custom_platforms_flutter'] = count(array_filter($platforms, function ($platform) { + $statsPerProject['custom_platforms_flutter'] = sizeof(array_filter($platforms, function ($platform) { return str_contains($platform['type'], 'flutter'); })); $flutterPlatforms = [Origin::CLIENT_TYPE_FLUTTER_ANDROID, Origin::CLIENT_TYPE_FLUTTER_IOS, Origin::CLIENT_TYPE_FLUTTER_MACOS, Origin::CLIENT_TYPE_FLUTTER_WINDOWS, Origin::CLIENT_TYPE_FLUTTER_LINUX]; foreach ($flutterPlatforms as $flutterPlatform) { - $statsPerProject['custom_platforms_'.$flutterPlatform] = count(array_filter($platforms, function ($platform) use ($flutterPlatform) { + $statsPerProject['custom_platforms_' . $flutterPlatform] = sizeof(array_filter($platforms, function ($platform) use ($flutterPlatform) { return $platform['type'] === $flutterPlatform; })); } $statsPerProject['custom_platforms_api_keys'] = $dbForConsole->count('keys', [ Query::equal('projectInternalId', [$project->getInternalId()]), - Query::limit(APP_LIMIT_COUNT), + Query::limit(APP_LIMIT_COUNT) ]); /** Get Usage $statsPerProject */ @@ -210,17 +209,17 @@ class Hamster extends Action Query::orderDesc('time'), ]); - $statsPerProject[$key.'_'.$periodKey] = []; + $statsPerProject[$key . '_' . $periodKey] = []; foreach ($requestDocs as $requestDoc) { - $statsPerProject[$key.'_'.$periodKey][] = [ + $statsPerProject[$key . '_' . $periodKey][] = [ 'value' => $requestDoc->getAttribute('value'), 'date' => $requestDoc->getAttribute('time'), ]; } - $statsPerProject[$key.'_'.$periodKey] = array_reverse($statsPerProject[$key.'_'.$periodKey]); + $statsPerProject[$key . '_' . $periodKey] = array_reverse($statsPerProject[$key . '_' . $periodKey]); // Calculate aggregate of each metric - $statsPerProject[$key.'_'.$periodKey] = array_sum(array_column($statsPerProject[$key.'_'.$periodKey], 'value')); + $statsPerProject[$key . '_' . $periodKey] = array_sum(array_column($statsPerProject[$key . '_' . $periodKey], 'value')); } } }); @@ -229,11 +228,11 @@ class Hamster extends Action /** Send data to mixpanel */ $res = $this->mixpanel->createProfile($statsPerProject['email'], '', [ 'name' => $statsPerProject['name'], - 'email' => $statsPerProject['email'], + 'email' => $statsPerProject['email'] ]); - if (! $res) { - Console::error('Failed to create user profile for project: '.$project->getId()); + if (!$res) { + Console::error('Failed to create user profile for project: ' . $project->getId()); } $event = new Event(); @@ -241,12 +240,12 @@ class Hamster extends Action ->setName('Project Daily Usage') ->setProps($statsPerProject); $res = $this->mixpanel->createEvent($event); - if (! $res) { - Console::error('Failed to create event for project: '.$project->getId()); + if (!$res) { + Console::error('Failed to create event for project: ' . $project->getId()); } } } catch (Exception $e) { - Console::error('Failed to send stats for project: '.$project->getId()); + Console::error('Failed to send stats for project: ' . $project->getId()); Console::error($e->getMessage()); } finally { $pools @@ -258,8 +257,9 @@ class Hamster extends Action public function action(Group $pools, Cache $cache, Database $dbForConsole): void { + Console::title('Cloud Hamster V1'); - Console::success(APP_NAME.' cloud hamster process has started'); + Console::success(APP_NAME . ' cloud hamster process has started'); $sleep = (int) App::getEnv('_APP_HAMSTER_INTERVAL', '30'); // 30 seconds (by default) @@ -278,7 +278,7 @@ class Hamster extends Action $delay = $next->getTimestamp() - $now->getTimestamp(); } - Console::log('['.$now->format('Y-m-d H:i:s.v').'] Delaying for '.$delay.' setting loop to ['.$next->format('Y-m-d H:i:s.v').']'); + Console::log('[' . $now->format("Y-m-d H:i:s.v") . '] Delaying for ' . $delay . ' setting loop to [' . $next->format("Y-m-d H:i:s.v") . ']'); Console::loop(function () use ($pools, $cache, $dbForConsole, $sleep) { $now = date('d-m-Y H:i:s', time()); @@ -325,12 +325,12 @@ class Hamster extends Action $results = $dbForConsole->find($collection, \array_merge([ Query::limit($limit), - Query::offset($count), + Query::offset($count) ])); $sum = count($results); - Console::log('Processing chunk #'.$chunk.'. Found '.$sum.' documents'); + Console::log('Processing chunk #' . $chunk . '. Found ' . $sum . ' documents'); foreach ($results as $document) { call_user_func($callback, $dbForConsole, $document); @@ -340,11 +340,12 @@ class Hamster extends Action $executionEnd = \microtime(true); - Console::log("Processed {$count} document by group in ".($executionEnd - $executionStart).' seconds'); + Console::log("Processed {$count} document by group in " . ($executionEnd - $executionStart) . " seconds"); } protected function getStatsPerOrganization(Database $dbForConsole) { + $this->calculateByGroup('teams', $dbForConsole, function (Database $dbForConsole, Document $document) { try { $statsPerOrganization = []; @@ -357,8 +358,8 @@ class Hamster extends Action Query::equal('teamInternalId', [$document->getInternalId()]), ]); - if (! $membership || $membership->isEmpty()) { - throw new Exception('Membership not found. Skipping organization : '.$document->getId()); + if (!$membership || $membership->isEmpty()) { + throw new Exception('Membership not found. Skipping organization : ' . $document->getId()); } $userInternalId = $membership->getAttribute('userInternalId', null); @@ -379,11 +380,11 @@ class Hamster extends Action /** Number of projects in this organization */ $statsPerOrganization['projects'] = $dbForConsole->count('projects', [ Query::equal('teamId', [$document->getId()]), - Query::limit(APP_LIMIT_COUNT), + Query::limit(APP_LIMIT_COUNT) ]); - if (! isset($statsPerOrganization['email'])) { - throw new Exception('Email not found. Skipping organization : '.$document->getId()); + if (!isset($statsPerOrganization['email'])) { + throw new Exception('Email not found. Skipping organization : ' . $document->getId()); } $event = new Event(); @@ -391,8 +392,8 @@ class Hamster extends Action ->setName('Organization Daily Usage') ->setProps($statsPerOrganization); $res = $this->mixpanel->createEvent($event); - if (! $res) { - throw new Exception('Failed to create event for organization : '.$document->getId()); + if (!$res) { + throw new Exception('Failed to create event for organization : ' . $document->getId()); } } catch (Exception $e) { Console::error($e->getMessage()); @@ -418,11 +419,11 @@ class Hamster extends Action /** Number of teams this user is a part of */ $statsPerUser['memberships'] = $dbForConsole->count('memberships', [ Query::equal('userInternalId', [$document->getInternalId()]), - Query::limit(APP_LIMIT_COUNT), + Query::limit(APP_LIMIT_COUNT) ]); - if (! isset($statsPerUser['email'])) { - throw new Exception('User has no email: '.$document->getId()); + if (!isset($statsPerUser['email'])) { + throw new Exception('User has no email: ' . $document->getId()); } /** Send data to mixpanel */ @@ -432,8 +433,8 @@ class Hamster extends Action ->setProps($statsPerUser); $res = $this->mixpanel->createEvent($event); - if (! $res) { - throw new Exception('Failed to create user profile for user: '.$document->getId()); + if (!$res) { + throw new Exception('Failed to create user profile for user: ' . $document->getId()); } } catch (Exception $e) { Console::error($e->getMessage()); diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index 9c25320b6d..be12eadf62 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -9,8 +9,8 @@ use Appwrite\Utopia\View; use Utopia\Analytics\GoogleAnalytics; use Utopia\CLI\Console; use Utopia\Config\Config; -use Utopia\Platform\Action; use Utopia\Validator\Text; +use Utopia\Platform\Action; class Install extends Action { @@ -70,19 +70,19 @@ class Install extends Action Console::success('Starting Appwrite installation...'); // Create directory with write permissions - if (null !== $path && ! \file_exists(\dirname($path))) { - if (! @\mkdir(\dirname($path), 0755, true)) { - Console::error('Can\'t create directory '.\dirname($path)); + if (null !== $path && !\file_exists(\dirname($path))) { + if (!@\mkdir(\dirname($path), 0755, true)) { + Console::error('Can\'t create directory ' . \dirname($path)); Console::exit(1); } } - $data = @file_get_contents($path.'/docker-compose.yml'); + $data = @file_get_contents($path . '/docker-compose.yml'); if ($data !== false) { $time = \time(); - Console::info('Compose file found, creating backup: docker-compose.yml.'.$time.'.backup'); - file_put_contents($path.'/docker-compose.yml.'.$time.'.backup', $data); + Console::info('Compose file found, creating backup: docker-compose.yml.' . $time . '.backup'); + file_put_contents($path . '/docker-compose.yml.' . $time . '.backup', $data); $compose = new Compose($data); $appwrite = $compose->getService('appwrite'); $oldVersion = ($appwrite) ? $appwrite->getImageVersion() : null; @@ -91,14 +91,14 @@ class Install extends Action } catch (\Throwable $th) { $ports = [ $defaultHTTPPort => $defaultHTTPPort, - $defaultHTTPSPort => $defaultHTTPSPort, + $defaultHTTPSPort => $defaultHTTPSPort ]; Console::warning('Traefik not found. Falling back to default ports.'); } if ($oldVersion) { foreach ($compose->getServices() as $service) { // Fetch all env vars from previous compose file - if (! $service) { + if (!$service) { continue; } @@ -116,11 +116,11 @@ class Install extends Action } } - $data = @file_get_contents($path.'/.env'); + $data = @file_get_contents($path . '/.env'); if ($data !== false) { // Fetch all env vars from previous .env file - Console::info('Env file found, creating backup: .env.'.$time.'.backup'); - file_put_contents($path.'/.env.'.$time.'.backup', $data); + Console::info('Env file found, creating backup: .env.' . $time . '.backup'); + file_put_contents($path . '/.env.' . $time . '.backup', $data); $env = new Env($data); foreach ($env->list() as $key => $value) { @@ -148,44 +148,40 @@ class Install extends Action } if (empty($httpPort)) { - $httpPort = Console::confirm('Choose your server HTTP port: (default: '.$defaultHTTPPort.')'); + $httpPort = Console::confirm('Choose your server HTTP port: (default: ' . $defaultHTTPPort . ')'); $httpPort = ($httpPort) ? $httpPort : $defaultHTTPPort; } if (empty($httpsPort)) { - $httpsPort = Console::confirm('Choose your server HTTPS port: (default: '.$defaultHTTPSPort.')'); + $httpsPort = Console::confirm('Choose your server HTTPS port: (default: ' . $defaultHTTPSPort . ')'); $httpsPort = ($httpsPort) ? $httpsPort : $defaultHTTPSPort; } $input = []; foreach ($vars as $var) { - if (! empty($var['filter']) && ($interactive !== 'Y' || ! Console::isInteractive())) { + if (!empty($var['filter']) && ($interactive !== 'Y' || !Console::isInteractive())) { if ($data && $var['default'] !== null) { $input[$var['name']] = $var['default']; - continue; } if ($var['filter'] === 'token') { $input[$var['name']] = Auth::tokenGenerator(); - continue; } if ($var['filter'] === 'password') { $input[$var['name']] = Auth::passwordGenerator(); - continue; } } - if (! $var['required'] || ! Console::isInteractive() || $interactive !== 'Y') { + if (!$var['required'] || !Console::isInteractive() || $interactive !== 'Y') { $input[$var['name']] = $var['default']; - continue; } - $input[$var['name']] = Console::confirm($var['question'].' (default: \''.$var['default'].'\')'); + $input[$var['name']] = Console::confirm($var['question'] . ' (default: \'' . $var['default'] . '\')'); if (empty($input[$var['name']])) { $input[$var['name']] = $var['default']; @@ -195,36 +191,38 @@ class Install extends Action if ($input[$var['name']] !== 'localhost') { Console::warning("\nIf you haven't already done so, set the following record for {$input[$var['name']]} on your DNS provider:\n"); $mask = "%-15.15s %-10.10s %-30.30s\n"; - printf($mask, 'Type', 'Name', 'Value'); - printf($mask, 'A or AAAA', '@', ''); + printf($mask, "Type", "Name", "Value"); + printf($mask, "A or AAAA", "@", ""); Console::warning("\nUse 'AAAA' if you're using an IPv6 address and 'A' if you're using an IPv4 address.\n"); } } } - $templateForCompose = new View(__DIR__.'/../views/install/compose.phtml'); - $templateForEnv = new View(__DIR__.'/../views/install/env.phtml'); + $templateForCompose = new View(__DIR__ . '/../views/install/compose.phtml'); + $templateForEnv = new View(__DIR__ . '/../views/install/env.phtml'); $templateForCompose ->setParam('httpPort', $httpPort) ->setParam('httpsPort', $httpsPort) ->setParam('version', APP_VERSION_STABLE) ->setParam('organization', $organization) - ->setParam('image', $image); + ->setParam('image', $image) + ; $templateForEnv - ->setParam('vars', $input); + ->setParam('vars', $input) + ; - if (! file_put_contents($path.'/docker-compose.yml', $templateForCompose->render(false))) { + if (!file_put_contents($path . '/docker-compose.yml', $templateForCompose->render(false))) { $message = 'Failed to save Docker Compose file'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message); + $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); Console::error($message); Console::exit(1); } - if (! file_put_contents($path.'/.env', $templateForEnv->render(false))) { + if (!file_put_contents($path . '/.env', $templateForEnv->render(false))) { $message = 'Failed to save environment variables file'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message); + $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); Console::error($message); Console::exit(1); } @@ -235,23 +233,23 @@ class Install extends Action foreach ($input as $key => $value) { if ($value) { - $env .= $key.'='.\escapeshellarg($value).' '; + $env .= $key . '=' . \escapeshellarg($value) . ' '; } } - Console::log('Running "docker compose up -d --remove-orphans --renew-anon-volumes"'); + Console::log("Running \"docker compose up -d --remove-orphans --renew-anon-volumes\""); $exit = Console::execute("${env} docker compose --project-directory {$path} up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr); if ($exit !== 0) { $message = 'Failed to install Appwrite dockers'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message); + $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); Console::error($message); Console::error($stderr); Console::exit($exit); } else { $message = 'Appwrite installed successfully'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE.' - '.$message); + $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); Console::success($message); } } diff --git a/src/Appwrite/Platform/Tasks/Maintenance.php b/src/Appwrite/Platform/Tasks/Maintenance.php index df93feb4af..0739923e34 100644 --- a/src/Appwrite/Platform/Tasks/Maintenance.php +++ b/src/Appwrite/Platform/Tasks/Maintenance.php @@ -2,13 +2,14 @@ namespace Appwrite\Platform\Tasks; +use Appwrite\Auth\Auth; use Appwrite\Event\Certificate; use Appwrite\Event\Delete; use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Database; -use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\DateTime; use Utopia\Database\Query; use Utopia\Platform\Action; @@ -30,7 +31,7 @@ class Maintenance extends Action public function action(Database $dbForConsole): void { Console::title('Maintenance V1'); - Console::success(APP_NAME.' maintenance process v1 has started'); + Console::success(APP_NAME . ' maintenance process v1 has started'); function notifyDeleteExecutionLogs(int $interval) { @@ -84,19 +85,20 @@ class Maintenance extends Action $time = DateTime::now(); $certificates = $dbForConsole->find('certificates', [ - Query::lessThan('attempts', 5), // Maximum 5 attempts - Query::lessThanEqual('renewDate', $time), // includes 60 days cooldown (we have 30 days to renew) - Query::limit(200), // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains) + Query::lessThan('attempts', 5), // Maximum 5 attempts + Query::lessThanEqual('renewDate', $time), // includes 60 days cooldown (we have 30 days to renew) + Query::limit(200), // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains) ]); + if (\count($certificates) > 0) { - Console::info("[{$time}] Found ".\count($certificates).' certificates for renewal, scheduling jobs.'); + Console::info("[{$time}] Found " . \count($certificates) . " certificates for renewal, scheduling jobs."); $event = new Certificate(); foreach ($certificates as $certificate) { $event ->setDomain(new Document([ - 'domain' => $certificate->getAttribute('domain'), + 'domain' => $certificate->getAttribute('domain') ])) ->trigger(); } @@ -107,6 +109,7 @@ class Maintenance extends Action function notifyDeleteCache($interval) { + (new Delete()) ->setType(DELETE_TYPE_CACHE_BY_TIMESTAMP) ->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * $interval)) @@ -115,6 +118,7 @@ class Maintenance extends Action function notifyDeleteSchedules($interval) { + (new Delete()) ->setType(DELETE_TYPE_SCHEDULES) ->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * $interval)) diff --git a/src/Appwrite/Platform/Tasks/Migrate.php b/src/Appwrite/Platform/Tasks/Migrate.php index b4112f8d3f..90b4234109 100644 --- a/src/Appwrite/Platform/Tasks/Migrate.php +++ b/src/Appwrite/Platform/Tasks/Migrate.php @@ -2,14 +2,14 @@ namespace Appwrite\Platform\Tasks; +use Utopia\Platform\Action; +use Utopia\CLI\Console; use Appwrite\Migration\Migration; use Utopia\App; -use Utopia\Cache\Adapter\Redis as RedisCache; use Utopia\Cache\Cache; -use Utopia\CLI\Console; +use Utopia\Cache\Adapter\Redis as RedisCache; use Utopia\Database\Document; use Utopia\Database\Validator\Authorization; -use Utopia\Platform\Action; use Utopia\Registry\Registry; use Utopia\Validator\Text; @@ -35,23 +35,22 @@ class Migrate extends Action try { $redis->del($redis->keys("cache-_{$project->getInternalId()}:*")); } catch (\Throwable $th) { - Console::error('Failed to clear project ("'.$project->getId().'") cache with error: '.$th->getMessage()); + Console::error('Failed to clear project ("' . $project->getId() . '") cache with error: ' . $th->getMessage()); } } public function action(string $version, Registry $register) { Authorization::disable(); - if (! array_key_exists($version, Migration::$versions)) { + if (!array_key_exists($version, Migration::$versions)) { Console::error("Version {$version} not found."); Console::exit(1); - return; } $app = new App('UTC'); - Console::success('Starting Data Migration to version '.$version); + Console::success('Starting Data Migration to version ' . $version); $dbPool = $register->get('dbPool', true); $redis = $register->get('cache', true); @@ -79,10 +78,10 @@ class Migrate extends Action $totalProjects = $dbForConsole->count('projects') + 1; } - $class = 'Appwrite\\Migration\\Version\\'.Migration::$versions[$version]; + $class = 'Appwrite\\Migration\\Version\\' . Migration::$versions[$version]; $migration = new $class(); - while (! empty($projects)) { + while (!empty($projects)) { foreach ($projects as $project) { /** * Skip user projects with id 'console' @@ -100,7 +99,7 @@ class Migrate extends Action ->setProject($project, $projectDB, $dbForConsole) ->execute(); } catch (\Throwable $th) { - Console::error('Failed to update project ("'.$project->getId().'") version with error: '.$th->getMessage()); + Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage()); throw $th; } @@ -113,7 +112,7 @@ class Migrate extends Action $offset = $offset + $limit; $count = $count + $sum; - Console::log('Migrated '.$count.'/'.$totalProjects.' projects...'); + Console::log('Migrated ' . $count . '/' . $totalProjects . ' projects...'); } Swoole\Event::wait(); // Wait for Coroutines to finish diff --git a/src/Appwrite/Platform/Tasks/PatchCreateMissingSchedules.php b/src/Appwrite/Platform/Tasks/PatchCreateMissingSchedules.php index 9724818f70..74ef644498 100644 --- a/src/Appwrite/Platform/Tasks/PatchCreateMissingSchedules.php +++ b/src/Appwrite/Platform/Tasks/PatchCreateMissingSchedules.php @@ -2,14 +2,14 @@ namespace Appwrite\Platform\Tasks; +use Utopia\Platform\Action; use Utopia\CLI\Console; -use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; -use Utopia\Database\Helpers\ID; use Utopia\Database\Query; +use Utopia\Database\Database; +use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Authorization; -use Utopia\Platform\Action; class PatchCreateMissingSchedules extends Action { @@ -36,7 +36,7 @@ class PatchCreateMissingSchedules extends Action Authorization::setDefaultStatus(false); Console::title('PatchCreateMissingSchedules V1'); - Console::success(APP_NAME.' PatchCreateMissingSchedules v1 has started'); + Console::success(APP_NAME . ' PatchCreateMissingSchedules v1 has started'); $limit = 100; $projectCursor = null; @@ -52,7 +52,7 @@ class PatchCreateMissingSchedules extends Action } foreach ($projects as $project) { - Console::log('Checking Project '.$project->getAttribute('name').' ('.$project->getId().')'); + Console::log("Checking Project " . $project->getAttribute('name') . " (" . $project->getId() . ")"); $dbForProject = $getProjectDB($project); $functionCursor = null; @@ -79,11 +79,11 @@ class PatchCreateMissingSchedules extends Action 'resourceId' => $functionId, 'resourceUpdatedAt' => DateTime::now(), 'projectId' => $project->getId(), - 'schedule' => $function->getAttribute('schedule'), - 'active' => ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')), + 'schedule' => $function->getAttribute('schedule'), + 'active' => !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')), ])); - Console::success('Recreated schedule for function '.$functionId); + Console::success('Recreated schedule for function ' . $functionId); } } diff --git a/src/Appwrite/Platform/Tasks/PatchDeleteProjectCollections.php b/src/Appwrite/Platform/Tasks/PatchDeleteProjectCollections.php index 3a70e239cb..a909e68595 100644 --- a/src/Appwrite/Platform/Tasks/PatchDeleteProjectCollections.php +++ b/src/Appwrite/Platform/Tasks/PatchDeleteProjectCollections.php @@ -3,11 +3,11 @@ namespace Appwrite\Platform\Tasks; use Utopia\App; +use Utopia\Platform\Action; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Query; -use Utopia\Platform\Action; use Utopia\Pools\Group; use Utopia\Validator\Numeric; @@ -31,6 +31,7 @@ class PatchDeleteProjectCollections extends Action public function __construct() { + $this ->desc('Delete unnecessary project collections') ->param('offset', 0, new Numeric(), 'Resume deletion from param pos', true) @@ -47,7 +48,7 @@ class PatchDeleteProjectCollections extends Action //docker compose exec -t appwrite patch-delete-project-collections Console::title('Delete project collections V1'); - Console::success(APP_NAME.' delete project collections has started'); + Console::success(APP_NAME . ' delete project collections has started'); /* Initialise new Utopia app */ $app = new App('UTC'); @@ -62,8 +63,9 @@ class PatchDeleteProjectCollections extends Action $limit = 50; $sum = 50; $offset = $offset; - while (! empty($projects)) { + while (!empty($projects)) { foreach ($projects as $project) { + /** * Skip user projects with id 'console' */ @@ -82,7 +84,7 @@ class PatchDeleteProjectCollections extends Action $dbForProject = new Database($adapter, $cache); $dbForProject->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - $dbForProject->setNamespace('_'.$project->getInternalId()); + $dbForProject->setNamespace('_' . $project->getInternalId()); foreach ($this->names as $name) { if (empty($name)) { @@ -90,14 +92,14 @@ class PatchDeleteProjectCollections extends Action } if ($dbForProject->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), $name)) { if ($dbForProject->deleteCollection($name)) { - Console::log('Deleted '.$name); + Console::log('Deleted ' . $name); } else { - Console::error('Failed to delete '.$name); + Console::error('Failed to delete ' . $name); } } } } catch (\Throwable $th) { - Console::error('Failed on project ("'.$project->getId().'") version with error: '.$th->getMessage()); + Console::error('Failed on project ("' . $project->getId() . '") version with error: ' . $th->getMessage()); } finally { $pools ->get($db) @@ -112,14 +114,14 @@ class PatchDeleteProjectCollections extends Action Query::offset($offset), ]); - if (! empty($projects)) { - Console::log('Querying..... offset='.$offset.' , limit='.$limit.', count='.$count); + if (!empty($projects)) { + Console::log('Querying..... offset=' . $offset . ' , limit=' . $limit . ', count=' . $count); } $offset = $offset + $limit; $count = $count + $sum; } - Console::log('Iterated through '.$count - 1 .'/'.$totalProjects.' projects...'); + Console::log('Iterated through ' . $count - 1 . '/' . $totalProjects . ' projects...'); $pools ->get('console') ->reclaim(); diff --git a/src/Appwrite/Platform/Tasks/PatchDeleteScheduleUpdatedAtAttribute.php b/src/Appwrite/Platform/Tasks/PatchDeleteScheduleUpdatedAtAttribute.php index b8fd8baaa2..95a7c4ffe1 100644 --- a/src/Appwrite/Platform/Tasks/PatchDeleteScheduleUpdatedAtAttribute.php +++ b/src/Appwrite/Platform/Tasks/PatchDeleteScheduleUpdatedAtAttribute.php @@ -2,11 +2,11 @@ namespace Appwrite\Platform\Tasks; -use Utopia\CLI\Console; -use Utopia\Database\Database; -use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; +use Utopia\CLI\Console; +use Utopia\Database\Query; +use Utopia\Database\Database; +use Utopia\Database\Validator\Authorization; use Utopia\Pools\Group; class PatchDeleteScheduleUpdatedAtAttribute extends Action @@ -35,7 +35,7 @@ class PatchDeleteScheduleUpdatedAtAttribute extends Action Authorization::setDefaultStatus(false); Console::title('PatchDeleteScheduleUpdatedAtAttribute V1'); - Console::success(APP_NAME.' PatchDeleteScheduleUpdatedAtAttribute v1 has started'); + Console::success(APP_NAME . ' PatchDeleteScheduleUpdatedAtAttribute v1 has started'); $limit = 100; $projectCursor = null; @@ -51,7 +51,7 @@ class PatchDeleteScheduleUpdatedAtAttribute extends Action } foreach ($projects as $project) { - Console::log('Checking Project '.$project->getAttribute('name').' ('.$project->getId().')'); + Console::log("Checking Project " . $project->getAttribute('name') . " (" . $project->getId() . ")"); $dbForProject = $getProjectDB($project); try { diff --git a/src/Appwrite/Platform/Tasks/SDKs.php b/src/Appwrite/Platform/Tasks/SDKs.php index 4b2c07e17c..f70ae8bd60 100644 --- a/src/Appwrite/Platform/Tasks/SDKs.php +++ b/src/Appwrite/Platform/Tasks/SDKs.php @@ -2,8 +2,8 @@ namespace Appwrite\Platform\Tasks; +use Utopia\Platform\Action; use Appwrite\SDK\Language\Android; -use Appwrite\SDK\Language\Apple; use Appwrite\SDK\Language\CLI; use Appwrite\SDK\Language\Dart; use Appwrite\SDK\Language\Deno; @@ -18,14 +18,14 @@ use Appwrite\SDK\Language\Python; use Appwrite\SDK\Language\REST; use Appwrite\SDK\Language\Ruby; use Appwrite\SDK\Language\Swift; +use Exception; +use Throwable; +use Appwrite\SDK\Language\Apple; use Appwrite\SDK\Language\Web; use Appwrite\SDK\SDK; use Appwrite\Spec\Swagger2; -use Exception; -use Throwable; use Utopia\CLI\Console; use Utopia\Config\Config; -use Utopia\Platform\Action; class SDKs extends Action { @@ -44,14 +44,14 @@ class SDKs extends Action public function action(): void { $platforms = Config::getParam('platforms'); - $selectedPlatform = Console::confirm('Choose Platform ("'.APP_PLATFORM_CLIENT.'", "'.APP_PLATFORM_SERVER.'", "'.APP_PLATFORM_CONSOLE.'" or "*" for all):'); + $selectedPlatform = Console::confirm('Choose Platform ("' . APP_PLATFORM_CLIENT . '", "' . APP_PLATFORM_SERVER . '", "' . APP_PLATFORM_CONSOLE . '" or "*" for all):'); $selectedSDK = \strtolower(Console::confirm('Choose SDK ("*" for all):')); $version = Console::confirm('Choose an Appwrite version'); $git = (Console::confirm('Should we use git push? (yes/no)') == 'yes'); $production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false; $message = ($git) ? Console::confirm('Please enter your commit message:') : ''; - if (! in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', '1.3.x', 'latest'])) { + if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', '1.3.x', 'latest'])) { throw new Exception('Unknown version given'); } @@ -65,31 +65,30 @@ class SDKs extends Action continue; } - if (! $language['enabled']) { - Console::warning($language['name'].' for '.$platform['name'].' is disabled'); - + if (!$language['enabled']) { + Console::warning($language['name'] . ' for ' . $platform['name'] . ' is disabled'); continue; } - Console::info('Fetching API Spec for '.$language['name'].' for '.$platform['name'].' (version: '.$version.')'); + Console::info('Fetching API Spec for ' . $language['name'] . ' for ' . $platform['name'] . ' (version: ' . $version . ')'); - $spec = file_get_contents(__DIR__.'/../../../../app/config/specs/swagger2-'.$version.'-'.$language['family'].'.json'); + $spec = file_get_contents(__DIR__ . '/../../../../app/config/specs/swagger2-' . $version . '-' . $language['family'] . '.json'); $cover = 'https://appwrite.io/images/github.png'; - $result = \realpath(__DIR__.'/../../../../app').'/sdks/'.$key.'-'.$language['key']; - $resultExamples = \realpath(__DIR__.'/../../../..').'/docs/examples/'.$version.'/'.$key.'-'.$language['key']; - $target = \realpath(__DIR__.'/../../../../app').'/sdks/git/'.$language['key'].'/'; - $readme = \realpath(__DIR__.'/../../../../docs/sdks/'.$language['key'].'/README.md'); + $result = \realpath(__DIR__ . '/../../../../app') . '/sdks/' . $key . '-' . $language['key']; + $resultExamples = \realpath(__DIR__ . '/../../../..') . '/docs/examples/' . $version . '/' . $key . '-' . $language['key']; + $target = \realpath(__DIR__ . '/../../../../app') . '/sdks/git/' . $language['key'] . '/'; + $readme = \realpath(__DIR__ . '/../../../../docs/sdks/' . $language['key'] . '/README.md'); $readme = ($readme) ? \file_get_contents($readme) : ''; - $gettingStarted = \realpath(__DIR__.'/../../../../docs/sdks/'.$language['key'].'/GETTING_STARTED.md'); + $gettingStarted = \realpath(__DIR__ . '/../../../../docs/sdks/' . $language['key'] . '/GETTING_STARTED.md'); $gettingStarted = ($gettingStarted) ? \file_get_contents($gettingStarted) : ''; - $examples = \realpath(__DIR__.'/../../../../docs/sdks/'.$language['key'].'/EXAMPLES.md'); + $examples = \realpath(__DIR__ . '/../../../../docs/sdks/' . $language['key'] . '/EXAMPLES.md'); $examples = ($examples) ? \file_get_contents($examples) : ''; - $changelog = \realpath(__DIR__.'/../../../../docs/sdks/'.$language['key'].'/CHANGELOG.md'); + $changelog = \realpath(__DIR__ . '/../../../../docs/sdks/' . $language['key'] . '/CHANGELOG.md'); $changelog = ($changelog) ? \file_get_contents($changelog) : '# Change Log'; - $warning = '**This SDK is compatible with Appwrite server version '.$version.'. For older versions, please check [previous releases]('.$language['url'].'/releases).**'; + $warning = '**This SDK is compatible with Appwrite server version ' . $version . '. For older versions, please check [previous releases](' . $language['url'] . '/releases).**'; $license = 'BSD-3-Clause'; - $licenseContent = 'Copyright (c) '.date('Y').' Appwrite (https://appwrite.io) and individual contributors. + $licenseContent = 'Copyright (c) ' . date('Y') . ' Appwrite (https://appwrite.io) and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -143,7 +142,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $config = new Node(); $config->setNPMPackage('node-appwrite'); $config->setBowerPackage('appwrite'); - $warning = $warning."\n\n > This is the Node.js SDK for integrating with Appwrite from your Node.js server-side code. + $warning = $warning . "\n\n > This is the Node.js SDK for integrating with Appwrite from your Node.js server-side code. If you're looking to integrate from the browser, you should check [appwrite/sdk-for-web](https://github.com/appwrite/sdk-for-web)"; break; case 'deno': @@ -169,14 +168,14 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND case 'dart': $config = new Dart(); $config->setPackageName('dart_appwrite'); - $warning = $warning."\n\n > This is the Dart SDK for integrating with Appwrite from your Dart server-side code. If you're looking for the Flutter SDK you should check [appwrite/sdk-for-flutter](https://github.com/appwrite/sdk-for-flutter)"; + $warning = $warning . "\n\n > This is the Dart SDK for integrating with Appwrite from your Dart server-side code. If you're looking for the Flutter SDK you should check [appwrite/sdk-for-flutter](https://github.com/appwrite/sdk-for-flutter)"; break; case 'go': $config = new Go(); break; case 'swift': $config = new Swift(); - $warning = $warning."\n\n > This is the Swift SDK for integrating with Appwrite from your Swift server-side code. If you're looking for the Apple SDK you should check [appwrite/sdk-for-apple](https://github.com/appwrite/sdk-for-apple)"; + $warning = $warning . "\n\n > This is the Swift SDK for integrating with Appwrite from your Swift server-side code. If you're looking for the Apple SDK you should check [appwrite/sdk-for-apple](https://github.com/appwrite/sdk-for-apple)"; break; case 'apple': $config = new Apple(); @@ -190,7 +189,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND break; case 'kotlin': $config = new Kotlin(); - $warning = $warning."\n\n > This is the Kotlin SDK for integrating with Appwrite from your Kotlin server-side code. If you're looking for the Android SDK you should check [appwrite/sdk-for-android](https://github.com/appwrite/sdk-for-android)"; + $warning = $warning . "\n\n > This is the Kotlin SDK for integrating with Appwrite from your Kotlin server-side code. If you're looking for the Android SDK you should check [appwrite/sdk-for-android](https://github.com/appwrite/sdk-for-android)"; break; case 'graphql': $config = new GraphQL(); @@ -199,7 +198,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $config = new REST(); break; default: - throw new Exception('Language "'.$language['key'].'" not supported'); + throw new Exception('Language "' . $language['key'] . '" not supported'); } Console::info("Generating {$language['name']} SDK..."); @@ -247,28 +246,29 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $gitUrl = $language['gitUrl']; $gitBranch = $language['gitBranch']; - if (! $production) { - $gitUrl = 'git@github.com:aw-tests/'.$language['gitRepoName'].'.git'; + + if (!$production) { + $gitUrl = 'git@github.com:aw-tests/' . $language['gitRepoName'] . '.git'; } - if ($git && ! empty($gitUrl)) { - \exec('rm -rf '.$target.' && \ - mkdir -p '.$target.' && \ - cd '.$target.' && \ - git init --initial-branch='.$gitBranch.' && \ - git remote add origin '.$gitUrl.' && \ - git fetch origin '.$gitBranch.' && \ - git pull origin '.$gitBranch.' && \ - rm -rf '.$target.'/* && \ - cp -r '.$result.'/* '.$target.'/ && \ + if ($git && !empty($gitUrl)) { + \exec('rm -rf ' . $target . ' && \ + mkdir -p ' . $target . ' && \ + cd ' . $target . ' && \ + git init --initial-branch=' . $gitBranch . ' && \ + git remote add origin ' . $gitUrl . ' && \ + git fetch origin ' . $gitBranch . ' && \ + git pull origin ' . $gitBranch . ' && \ + rm -rf ' . $target . '/* && \ + cp -r ' . $result . '/* ' . $target . '/ && \ git add . && \ - git commit -m "'.$message.'" && \ - git push -u origin '.$gitBranch.' + git commit -m "' . $message . '" && \ + git push -u origin ' . $gitBranch . ' '); Console::success("Pushed {$language['name']} SDK to {$gitUrl}"); - \exec('rm -rf '.$target); + \exec('rm -rf ' . $target); Console::success("Remove temp directory '{$target}' for {$language['name']} SDK"); } @@ -279,10 +279,10 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND } foreach ($docDirectories as $languageTitle => $path) { - $languagePath = strtolower($languageTitle !== 0 ? '/'.$languageTitle : ''); + $languagePath = strtolower($languageTitle !== 0 ? '/' . $languageTitle : ''); \exec( - 'mkdir -p '.$resultExamples.$languagePath.' && \ - cp -r '.$result.'/docs/examples'.$languagePath.' '.$resultExamples + 'mkdir -p ' . $resultExamples . $languagePath . ' && \ + cp -r ' . $result . '/docs/examples' . $languagePath . ' ' . $resultExamples ); Console::success("Copied code examples for {$language['name']} SDK to: {$resultExamples}"); } diff --git a/src/Appwrite/Platform/Tasks/SSL.php b/src/Appwrite/Platform/Tasks/SSL.php index 9697ff91ae..43026b0753 100644 --- a/src/Appwrite/Platform/Tasks/SSL.php +++ b/src/Appwrite/Platform/Tasks/SSL.php @@ -2,11 +2,11 @@ namespace Appwrite\Platform\Tasks; +use Utopia\Platform\Action; use Appwrite\Event\Certificate; use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Document; -use Utopia\Platform\Action; use Utopia\Validator\Hostname; class SSL extends Action @@ -26,11 +26,11 @@ class SSL extends Action public function action(string $domain): void { - Console::success('Scheduling a job to issue a TLS certificate for domain: '.$domain); + Console::success('Scheduling a job to issue a TLS certificate for domain: ' . $domain); (new Certificate()) ->setDomain(new Document([ - 'domain' => $domain, + 'domain' => $domain ])) ->setSkipRenewCheck(true) ->trigger(); diff --git a/src/Appwrite/Platform/Tasks/Schedule.php b/src/Appwrite/Platform/Tasks/Schedule.php index 42e8327e9a..219d1c9886 100644 --- a/src/Appwrite/Platform/Tasks/Schedule.php +++ b/src/Appwrite/Platform/Tasks/Schedule.php @@ -2,23 +2,23 @@ namespace Appwrite\Platform\Tasks; -use Appwrite\Event\Func; use Cron\CronExpression; -use function Swoole\Coroutine\run; use Swoole\Timer; use Utopia\App; +use Utopia\Platform\Action; use Utopia\CLI\Console; -use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Platform\Action; +use Utopia\Database\Database; use Utopia\Pools\Group; +use Appwrite\Event\Func; + +use function Swoole\Coroutine\run; class Schedule extends Action { public const FUNCTION_UPDATE_TIMER = 10; //seconds - public const FUNCTION_ENQUEUE_TIMER = 60; //seconds public static function getName(): string @@ -40,17 +40,16 @@ class Schedule extends Action * 1. Load all documents from 'schedules' collection to create local copy * 2. Create timer that sync all changes from 'schedules' collection to local copy. Only reading changes thanks to 'resourceUpdatedAt' attribute * 3. Create timer that prepares coroutines for soon-to-execute schedules. When it's ready, coroutime sleeps until exact time before sending request to worker. - */ + */ public function action(Group $pools, Database $dbForConsole, callable $getProjectDB): void { Console::title('Scheduler V1'); - Console::success(APP_NAME.' Scheduler v1 has started'); + Console::success(APP_NAME . ' Scheduler v1 has started'); /** * Extract only nessessary attributes to lower memory used. * * @var Document $schedule - * * @return array */ $getSchedule = function (Document $schedule) use ($dbForConsole, $getProjectDB): array { @@ -93,14 +92,14 @@ class Schedule extends Action $schedules[$document['resourceId']] = $getSchedule($document); } - $latestDocument = ! empty(array_key_last($results)) ? $results[array_key_last($results)] : null; + $latestDocument = !empty(array_key_last($results)) ? $results[array_key_last($results)] : null; } $pools->reclaim(); - Console::success("{$total} functions were loaded in ".(microtime(true) - $loadStart).' seconds'); + Console::success("{$total} functions were loaded in " . (microtime(true) - $loadStart) . " seconds"); - Console::success('Starting timers at '.DateTime::now()); + Console::success("Starting timers at " . DateTime::now()); run( function () use ($dbForConsole, &$schedules, &$lastSyncUpdate, $getSchedule, $pools) { @@ -121,7 +120,7 @@ class Schedule extends Action while ($sum === $limit) { $paginationQueries = [Query::limit($limit)]; if ($latestDocument !== null) { - $paginationQueries[] = Query::cursorAfter($latestDocument); + $paginationQueries[] = Query::cursorAfter($latestDocument); } $results = $dbForConsole->find('schedules', \array_merge($paginationQueries, [ Query::equal('region', [App::getEnv('_APP_REGION', 'default')]), @@ -145,7 +144,7 @@ class Schedule extends Action $schedules[$document['resourceId']] = $getSchedule($document); } } - $latestDocument = ! empty(array_key_last($results)) ? $results[array_key_last($results)] : null; + $latestDocument = !empty(array_key_last($results)) ? $results[array_key_last($results)] : null; } $lastSyncUpdate = $time; @@ -153,7 +152,7 @@ class Schedule extends Action $pools->reclaim(); - Console::log("Sync tick: {$total} schedules were updated in ".($timerEnd - $timerStart).' seconds'); + Console::log("Sync tick: {$total} schedules were updated in " . ($timerEnd - $timerStart) . " seconds"); }); /** @@ -180,7 +179,7 @@ class Schedule extends Action $currentTick = $next < $timeFrame; - if (! $currentTick) { + if (!$currentTick) { continue; } @@ -190,7 +189,7 @@ class Schedule extends Action $executionStart = $nextDate->getTimestamp(); // in seconds $delay = $executionStart - $promiseStart; // Time to wait from now until execution needs to be queued - if (! isset($delayedExecutions[$delay])) { + if (!isset($delayedExecutions[$delay])) { $delayedExecutions[$delay] = []; } @@ -206,7 +205,7 @@ class Schedule extends Action foreach ($scheduleKeys as $scheduleKey) { // Ensure schedule was not deleted - if (! isset($schedules[$scheduleKey])) { + if (!isset($schedules[$scheduleKey])) { return; } @@ -227,10 +226,10 @@ class Schedule extends Action $timerEnd = \microtime(true); $lastEnqueueUpdate = $timerStart; - Console::log("Enqueue tick: {$total} executions were enqueued in ".($timerEnd - $timerStart).' seconds'); + Console::log("Enqueue tick: {$total} executions were enqueued in " . ($timerEnd - $timerStart) . " seconds"); }; - Timer::tick(self::FUNCTION_ENQUEUE_TIMER * 1000, fn () => $enqueueFunctions()); + Timer::tick(self::FUNCTION_ENQUEUE_TIMER * 1000, fn() => $enqueueFunctions()); $enqueueFunctions(); } ); diff --git a/src/Appwrite/Platform/Tasks/Specs.php b/src/Appwrite/Platform/Tasks/Specs.php index d596a36925..82caf8ef72 100644 --- a/src/Appwrite/Platform/Tasks/Specs.php +++ b/src/Appwrite/Platform/Tasks/Specs.php @@ -2,6 +2,8 @@ namespace Appwrite\Platform\Tasks; +use Utopia\Platform\Action; +use Utopia\Validator\Text; use Appwrite\Specification\Format\OpenAPI3; use Appwrite\Specification\Format\Swagger2; use Appwrite\Specification\Specification; @@ -15,10 +17,8 @@ use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Adapter\MySQL; use Utopia\Database\Database; -use Utopia\Platform\Action; use Utopia\Registry\Registry; use Utopia\Request; -use Utopia\Validator\Text; use Utopia\Validator\WhiteList; class Specs extends Action @@ -177,15 +177,15 @@ class Specs extends Action $sdkPlaforms[] = APP_PLATFORM_CLIENT; } - if (! $route->getLabel('docs', true)) { + if (!$route->getLabel('docs', true)) { continue; } - if ($route->getLabel('sdk.mock', false) && ! $mocks) { + if ($route->getLabel('sdk.mock', false) && !$mocks) { continue; } - if (! $route->getLabel('sdk.mock', false) && $mocks) { + if (!$route->getLabel('sdk.mock', false) && $mocks) { continue; } @@ -193,7 +193,7 @@ class Specs extends Action continue; } - if ($platform !== APP_PLATFORM_CONSOLE && ! \in_array($platforms[$platform], $sdkPlaforms)) { + if ($platform !== APP_PLATFORM_CONSOLE && !\in_array($platforms[$platform], $sdkPlaforms)) { continue; } @@ -203,10 +203,10 @@ class Specs extends Action foreach (Config::getParam('services', []) as $service) { if ( - ! isset($service['docs']) // Skip service if not part of the public API - || ! isset($service['sdk']) - || ! $service['docs'] - || ! $service['sdk'] + !isset($service['docs']) // Skip service if not part of the public API + || !isset($service['sdk']) + || !$service['docs'] + || !$service['sdk'] ) { continue; } @@ -221,7 +221,7 @@ class Specs extends Action $models = $response->getModels(); foreach ($models as $key => $value) { - if ($platform !== APP_PLATFORM_CONSOLE && ! $value->isPublic()) { + if ($platform !== APP_PLATFORM_CONSOLE && !$value->isPublic()) { unset($models[$key]); } } @@ -231,7 +231,7 @@ class Specs extends Action $formatInstance = match ($format) { 'swagger2' => new Swagger2(...$arguments), 'open-api3' => new OpenAPI3(...$arguments), - default => throw new Exception('Format not found: '.$format) + default => throw new Exception('Format not found: ' . $format) }; $specs = new Specification($formatInstance); @@ -243,36 +243,36 @@ class Specs extends Action ->setParam('description', 'Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)') ->setParam('endpoint', 'https://HOSTNAME/v1') ->setParam('version', APP_VERSION_STABLE) - ->setParam('terms', $endpoint.'/policy/terms') + ->setParam('terms', $endpoint . '/policy/terms') ->setParam('support.email', $email) - ->setParam('support.url', $endpoint.'/support') - ->setParam('contact.name', APP_NAME.' Team') + ->setParam('support.url', $endpoint . '/support') + ->setParam('contact.name', APP_NAME . ' Team') ->setParam('contact.email', $email) - ->setParam('contact.url', $endpoint.'/support') + ->setParam('contact.url', $endpoint . '/support') ->setParam('license.name', 'BSD-3-Clause') ->setParam('license.url', 'https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE') ->setParam('docs.description', 'Full API docs, specs and tutorials') - ->setParam('docs.url', $endpoint.'/docs'); + ->setParam('docs.url', $endpoint . '/docs'); if ($mocks) { - $path = __DIR__.'/../config/specs/'.$format.'-mocks-'.$platform.'.json'; + $path = __DIR__ . '/../config/specs/' . $format . '-mocks-' . $platform . '.json'; - if (! file_put_contents($path, json_encode($specs->parse()))) { - throw new Exception('Failed to save mocks spec file: '.$path); + if (!file_put_contents($path, json_encode($specs->parse()))) { + throw new Exception('Failed to save mocks spec file: ' . $path); } - Console::success('Saved mocks spec file: '.realpath($path)); + Console::success('Saved mocks spec file: ' . realpath($path)); continue; } - $path = __DIR__.'/../../../../app/config/specs/'.$format.'-'.$version.'-'.$platform.'.json'; + $path = __DIR__ . '/../../../../app/config/specs/' . $format . '-' . $version . '-' . $platform . '.json'; - if (! file_put_contents($path, json_encode($specs->parse()))) { - throw new Exception('Failed to save spec file: '.$path); + if (!file_put_contents($path, json_encode($specs->parse()))) { + throw new Exception('Failed to save spec file: ' . $path); } - Console::success('Saved spec file: '.realpath($path)); + Console::success('Saved spec file: ' . realpath($path)); } } } diff --git a/src/Appwrite/Platform/Tasks/Vars.php b/src/Appwrite/Platform/Tasks/Vars.php index 714bb40ab1..c97f77a9da 100644 --- a/src/Appwrite/Platform/Tasks/Vars.php +++ b/src/Appwrite/Platform/Tasks/Vars.php @@ -3,8 +3,8 @@ namespace Appwrite\Platform\Tasks; use Utopia\App; -use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\CLI\Console; use Utopia\Platform\Action; class Vars extends Action @@ -33,7 +33,7 @@ class Vars extends Action } foreach ($vars as $key => $value) { - Console::log('- '.$value['name'].'='.App::getEnv($value['name'], '')); + Console::log('- ' . $value['name'] . '=' . App::getEnv($value['name'], '')); } } } diff --git a/src/Appwrite/Platform/Tasks/VolumeSync.php b/src/Appwrite/Platform/Tasks/VolumeSync.php index 193d07fd17..6197b20fbd 100644 --- a/src/Appwrite/Platform/Tasks/VolumeSync.php +++ b/src/Appwrite/Platform/Tasks/VolumeSync.php @@ -27,10 +27,11 @@ class VolumeSync extends Action public function action(string $source, string $destination, int $interval) { - Console::title('RSync V1'); - Console::success(APP_NAME.' rsync process v1 has started'); - if (! file_exists($source)) { + Console::title('RSync V1'); + Console::success(APP_NAME . ' rsync process v1 has started'); + + if (!file_exists($source)) { Console::error('Source directory does not exist. Exiting ... '); Console::exit(0); } @@ -41,15 +42,14 @@ class VolumeSync extends Action Console::info("[{$time}] Executing rsync every {$interval} seconds"); Console::info("Syncing between $source and $destination"); - if (! file_exists($source)) { + if (!file_exists($source)) { Console::error('Source directory does not exist. Skipping ... '); - return; } - $stdin = ''; - $stdout = ''; - $stderr = ''; + $stdin = ""; + $stdout = ""; + $stderr = ""; Console::execute("rsync -av $source $destination", $stdin, $stdout, $stderr); Console::success($stdout); diff --git a/src/Appwrite/Promises/Promise.php b/src/Appwrite/Promises/Promise.php index 95e4c7bc69..a6b1aa79d5 100644 --- a/src/Appwrite/Promises/Promise.php +++ b/src/Appwrite/Promises/Promise.php @@ -5,9 +5,7 @@ namespace Appwrite\Promises; abstract class Promise { protected const STATE_PENDING = 1; - protected const STATE_FULFILLED = 0; - protected const STATE_REJECTED = -1; protected int $state = self::STATE_PENDING; @@ -39,7 +37,7 @@ abstract class Promise /** * Create a new promise from the given callable. * - * @param callable $promise + * @param callable $promise * @return self */ public static function create(callable $promise): self @@ -50,7 +48,7 @@ abstract class Promise /** * Resolve promise with given value. * - * @param mixed $value + * @param mixed $value * @return self */ public static function resolve(mixed $value): self @@ -63,7 +61,7 @@ abstract class Promise /** * Rejects the promise with the given reason. * - * @param mixed $value + * @param mixed $value * @return self */ public static function reject(mixed $value): self @@ -76,7 +74,7 @@ abstract class Promise /** * Catch any exception thrown by the executor. * - * @param callable $onRejected + * @param callable $onRejected * @return self */ public function catch(callable $onRejected): self @@ -87,8 +85,8 @@ abstract class Promise /** * Execute the promise. * - * @param callable|null $onFulfilled - * @param callable|null $onRejected + * @param callable|null $onFulfilled + * @param callable|null $onRejected * @return self */ public function then( @@ -101,15 +99,13 @@ abstract class Promise if ($this->isFulfilled() && $onFulfilled === null) { return $this; } - return self::create(function (callable $resolve, callable $reject) use ($onFulfilled, $onRejected) { while ($this->isPending()) { usleep(25000); } $callable = $this->isFulfilled() ? $onFulfilled : $onRejected; - if (! \is_callable($callable)) { + if (!\is_callable($callable)) { $resolve($this->result); - return; } try { @@ -123,7 +119,7 @@ abstract class Promise /** * Returns a promise that completes when all passed in promises complete. * - * @param iterable|self[] $promises + * @param iterable|self[] $promises * @return self */ abstract public static function all(iterable $promises): self; @@ -131,14 +127,13 @@ abstract class Promise /** * Set resolved result * - * @param mixed $value + * @param mixed $value * @return void */ protected function setResult(mixed $value): void { - if (! \is_callable([$value, 'then'])) { + if (!\is_callable([$value, 'then'])) { $this->result = $value; - return; } @@ -151,7 +146,7 @@ abstract class Promise $value->then($callable, $callable); - while (! $resolved) { + while (!$resolved) { usleep(25000); } } @@ -159,7 +154,7 @@ abstract class Promise /** * Change promise state * - * @param int $state + * @param integer $state * @return void */ protected function setState(int $state): void @@ -170,7 +165,7 @@ abstract class Promise /** * Promise is pending * - * @return bool + * @return boolean */ protected function isPending(): bool { @@ -180,7 +175,7 @@ abstract class Promise /** * Promise is fulfilled * - * @return bool + * @return boolean */ protected function isFulfilled(): bool { @@ -190,7 +185,7 @@ abstract class Promise /** * Promise is rejected * - * @return bool + * @return boolean */ protected function isRejected(): bool { diff --git a/src/Appwrite/Promises/Swoole.php b/src/Appwrite/Promises/Swoole.php index 4867ed6c96..c258ef6a5e 100644 --- a/src/Appwrite/Promises/Swoole.php +++ b/src/Appwrite/Promises/Swoole.php @@ -28,7 +28,7 @@ class Swoole extends Promise /** * Returns a promise that completes when all passed in promises complete. * - * @param iterable|Swoole[] $promises + * @param iterable|Swoole[] $promises * @return Promise */ public static function all(iterable $promises): Promise @@ -45,7 +45,6 @@ class Swoole extends Promise $promise->then(function ($value) use ($key, &$result, $channel) { $result[$key] = $value; $channel->push(true); - return $value; }, function ($err) use ($channel, &$error) { $channel->push(true); @@ -62,7 +61,6 @@ class Swoole extends Promise if ($error !== null) { $reject($error); - return; } diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index f6ff7c2fb8..146500e743 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -5,14 +5,12 @@ namespace Appwrite\Resque; use Appwrite\Event\Usage; use Exception; use Utopia\App; -use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; -use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Cache\Adapter\Sharding; +use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; -use Utopia\DSN\DSN; use Utopia\Pools\Group; use Utopia\Storage\Device; use Utopia\Storage\Device\Backblaze; @@ -20,6 +18,8 @@ use Utopia\Storage\Device\DOSpaces; use Utopia\Storage\Device\Linode; use Utopia\Storage\Device\Local; use Utopia\Storage\Device\S3; +use Utopia\Database\Validator\Authorization; +use Utopia\DSN\DSN; use Utopia\Storage\Device\Wasabi; use Utopia\Storage\Storage; @@ -43,12 +43,11 @@ abstract class Worker * Function for identifying the worker needs to be set to unique name * * @return string - * * @throws Exception */ public function getName(): string { - throw new Exception('Please implement getName method in worker'); + throw new Exception("Please implement getName method in worker"); } /** @@ -56,12 +55,11 @@ abstract class Worker * Can include any preparations, such as connecting to external services or loading files * * @return void - * * @throws \Exception|\Throwable */ public function init(): void { - throw new Exception('Please implement init method in worker'); + throw new Exception("Please implement init method in worker"); } /** @@ -69,12 +67,11 @@ abstract class Worker * You can access $args here, it will contain event information * * @return void - * * @throws \Exception|\Throwable */ public function run(): void { - throw new Exception('Please implement run method in worker'); + throw new Exception("Please implement run method in worker"); } /** @@ -82,23 +79,20 @@ abstract class Worker * You can do cleanup here, such as disconnecting from services or removing temp files * * @return void - * * @throws \Exception|\Throwable */ public function shutdown(): void { - throw new Exception('Please implement shutdown method in worker'); + throw new Exception("Please implement shutdown method in worker"); } public const DATABASE_PROJECT = 'project'; - public const DATABASE_CONSOLE = 'console'; /** * A wrapper around 'init' function with non-worker-specific code * * @return void - * * @throws \Exception|\Throwable */ public function setUp(): void @@ -107,7 +101,7 @@ abstract class Worker $this->init(); } catch (\Throwable $error) { foreach (self::$errorCallbacks as $errorCallback) { - $errorCallback($error, 'init', $this->getName()); + $errorCallback($error, "init", $this->getName()); } throw $error; @@ -118,7 +112,6 @@ abstract class Worker * A wrapper around 'run' function with non-worker-specific code * * @return void - * * @throws \Exception|\Throwable */ public function perform(): void @@ -132,7 +125,7 @@ abstract class Worker $this->run(); } catch (\Throwable $error) { foreach (self::$errorCallbacks as $errorCallback) { - $errorCallback($error, 'run', $this->getName(), $this->args); + $errorCallback($error, "run", $this->getName(), $this->args); } throw $error; @@ -143,7 +136,6 @@ abstract class Worker * A wrapper around 'shutdown' function with non-worker-specific code * * @return void - * * @throws \Exception|\Throwable */ public function tearDown(): void @@ -157,17 +149,17 @@ abstract class Worker $this->shutdown(); } catch (\Throwable $error) { foreach (self::$errorCallbacks as $errorCallback) { - $errorCallback($error, 'shutdown', $this->getName()); + $errorCallback($error, "shutdown", $this->getName()); } throw $error; } } + /** * Register callback. Will be executed when error occurs. - * - * @param callable $callback + * @param callable $callback * @return void */ public static function error(callable $callback): void @@ -177,10 +169,8 @@ abstract class Worker /** * Get internal project database - * - * @param Document $project + * @param Document $project * @return Database - * * @throws Exception */ protected static $databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools @@ -190,6 +180,7 @@ abstract class Worker global $register; $pools = $register->get('pools'); /** @var Group $pools */ + if ($project->isEmpty() || $project->getId() === 'console') { return $this->getConsoleDB(); } @@ -198,30 +189,28 @@ abstract class Worker if (isset(self::$databases[$databaseName])) { $database = self::$databases[$databaseName]; - $database->setNamespace('_'.$project->getInternalId()); - + $database->setNamespace('_' . $project->getInternalId()); return $database; } $dbAdapter = $pools ->get($project->getAttribute('database')) ->pop() - ->getResource(); + ->getResource() + ; $database = new Database($dbAdapter, $this->getCache()); self::$databases[$databaseName] = $database; - $database->setNamespace('_'.$project->getInternalId()); + $database->setNamespace('_' . $project->getInternalId()); return $database; } /** * Get console database - * * @return Database - * * @throws Exception */ protected function getConsoleDB(): Database @@ -229,19 +218,20 @@ abstract class Worker global $register; $pools = $register->get('pools'); /** @var Group $pools */ + $databaseName = 'console'; if (isset(self::$databases[$databaseName])) { $database = self::$databases[$databaseName]; $database->setNamespace('console'); - return $database; } $dbAdapter = $pools ->get('console') ->pop() - ->getResource(); + ->getResource() + ; $database = new Database($dbAdapter, $this->getCache()); @@ -252,9 +242,9 @@ abstract class Worker return $database; } + /** * Get Cache - * * @return Cache */ protected function getCache(): Cache @@ -262,6 +252,7 @@ abstract class Worker global $register; $pools = $register->get('pools'); /** @var Group $pools */ + $list = Config::getParam('pools-cache', []); $adapters = []; @@ -269,7 +260,8 @@ abstract class Worker $adapters[] = $pools ->get($value) ->pop() - ->getResource(); + ->getResource() + ; } return new Cache(new Sharding($adapters)); @@ -277,9 +269,7 @@ abstract class Worker /** * Get usage queue - * * @return Usage - * * @throws Exception */ protected function getUsageQueue(): Usage @@ -297,46 +287,42 @@ abstract class Worker /** * Get Functions Storage Device - * - * @param string $projectId of the project + * @param string $projectId of the project * @return Device */ protected function getFunctionsDevice(string $projectId): Device { - return $this->getDevice(APP_STORAGE_FUNCTIONS.'/app-'.$projectId); + return $this->getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $projectId); } /** * Get Files Storage Device - * - * @param string $projectId of the project + * @param string $projectId of the project * @return Device */ protected function getFilesDevice(string $projectId): Device { - return $this->getDevice(APP_STORAGE_UPLOADS.'/app-'.$projectId); + return $this->getDevice(APP_STORAGE_UPLOADS . '/app-' . $projectId); } /** * Get Builds Storage Device - * - * @param string $projectId of the project + * @param string $projectId of the project * @return Device */ protected function getBuildsDevice(string $projectId): Device { - return $this->getDevice(APP_STORAGE_BUILDS.'/app-'.$projectId); + return $this->getDevice(APP_STORAGE_BUILDS . '/app-' . $projectId); } protected function getCacheDevice(string $projectId): Device { - return $this->getDevice(APP_STORAGE_CACHE.'/app-'.$projectId); + return $this->getDevice(APP_STORAGE_CACHE . '/app-' . $projectId); } /** * Get Device based on selected storage environment - * - * @param string $root path of the device + * @param string $root path of the device * @return Device */ public function getDevice(string $root): Device @@ -357,7 +343,7 @@ abstract class Worker $bucket = $dsn->getPath(); $region = $dsn->getParam('region'); } catch (\Exception $e) { - Console::error($e->getMessage().'Invalid DSN. Defaulting to Local device.'); + Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); } switch ($device) { diff --git a/src/Appwrite/Specification/Format.php b/src/Appwrite/Specification/Format.php index 670fbceecb..c2317c1153 100644 --- a/src/Appwrite/Specification/Format.php +++ b/src/Appwrite/Specification/Format.php @@ -2,10 +2,10 @@ namespace Appwrite\Specification; -use Appwrite\Utopia\Response\Model; use Utopia\App; use Utopia\Config\Config; use Utopia\Route; +use Appwrite\Utopia\Response\Model; abstract class Format { @@ -22,11 +22,8 @@ abstract class Format protected array $models; protected array $services; - protected array $keys; - protected int $authCount; - protected array $params = [ 'name' => '', 'description' => '', @@ -49,8 +46,8 @@ abstract class Format [ 'namespace' => 'users', 'method' => 'getUsage', - 'parameter' => 'provider', - ], + 'parameter' => 'provider' + ] ]; public function __construct(App $app, array $services, array $routes, array $models, array $keys, int $authCount) @@ -86,8 +83,9 @@ abstract class Format * * Set param value * - * @param string $key - * @param string $value + * @param string $key + * @param string $value + * * @return self */ public function setParam(string $key, string $value): self @@ -102,8 +100,9 @@ abstract class Format * * Get param value * - * @param string $key - * @param string $default + * @param string $key + * @param string $default + * * @return string */ public function getParam(string $key, string $default = ''): string @@ -178,10 +177,8 @@ abstract class Format } break; } - return null; } - public function getEnumKeys(string $service, string $method, string $param): array { $values = []; @@ -193,21 +190,18 @@ abstract class Format foreach ($codes as $code => $value) { $values[] = $value['name']; } - return $values; case 'getCreditCard': $codes = Config::getParam('avatar-credit-cards'); foreach ($codes as $code => $value) { $values[] = $value['name']; } - return $values; case 'getFlag': $codes = Config::getParam('avatar-flags'); foreach ($codes as $code => $value) { $values[] = $value['name']; } - return $values; } break; @@ -217,8 +211,7 @@ abstract class Format case 'getCollectionUsage': case 'getDatabaseUsage': // Range Enum Keys - $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; - + $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; return $values; } break; @@ -228,7 +221,6 @@ abstract class Format case 'getFunctionUsage': // Range Enum Keys $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; - return $values; } break; @@ -239,7 +231,6 @@ abstract class Format // Range Enum Keys if ($param == 'range') { $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; - return $values; } } @@ -250,11 +241,9 @@ abstract class Format case 'getBucketUsage': // Range Enum Keys $values = ['Twenty Four Hours', 'Seven Days', 'Thirty Days', 'Ninety Days']; - return $values; } } - return $values; } } diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index f979ca1b4d..94cb0bb90d 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -20,32 +20,30 @@ class OpenAPI3 extends Format protected function getNestedModels(Model $model, array &$usedModels): void { foreach ($model->getRules() as $rule) { - if (! in_array($model->getType(), $usedModels)) { + if (!in_array($model->getType(), $usedModels)) { continue; } if (\is_array($rule['type'])) { foreach ($rule['type'] as $ruleType) { - if (! in_array($ruleType, ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { + if (!in_array($ruleType, ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { $usedModels[] = $ruleType; foreach ($this->models as $m) { if ($m->getType() === $ruleType) { $this->getNestedModels($m, $usedModels); - continue; } } } } } else { - if (! in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { + if (!in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { $usedModels[] = $rule['type']; foreach ($this->models as $m) { if ($m->getType() === $rule['type']) { $this->getNestedModels($m, $usedModels); - continue; } } @@ -127,7 +125,7 @@ class OpenAPI3 extends Format } $id = $route->getLabel('sdk.method', \uniqid()); - $desc = (! empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__.'/../../../../'.$route->getLabel('sdk.description', '')) : null; + $desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__ . '/../../../../' . $route->getLabel('sdk.description', '')) : null; $produces = $route->getLabel('sdk.response.type', null); $model = $route->getLabel('sdk.response.model', 'none'); $routeSecurity = $route->getLabel('sdk.auth', []); @@ -156,7 +154,7 @@ class OpenAPI3 extends Format $temp = [ 'summary' => $route->getDesc(), - 'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id), + 'operationId' => $route->getLabel('sdk.namespace', 'default') . ucfirst($id), 'tags' => [$route->getLabel('sdk.namespace', 'default')], 'description' => ($desc) ? \file_get_contents($desc) : '', 'responses' => [], @@ -165,8 +163,8 @@ class OpenAPI3 extends Format 'weight' => $route->getOrder(), 'cookies' => $route->getLabel('sdk.cookies', false), 'type' => $route->getLabel('sdk.methodType', ''), - 'demo' => Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')).'/'.Template::fromCamelCaseToDash($id).'.md', - 'edit' => 'https://github.com/appwrite/appwrite/edit/master'.$route->getLabel('sdk.description', ''), + 'demo' => Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')) . '/' . Template::fromCamelCaseToDash($id) . '.md', + 'edit' => 'https://github.com/appwrite/appwrite/edit/master' . $route->getLabel('sdk.description', ''), 'rate-limit' => $route->getLabel('abuse-limit', 0), 'rate-time' => $route->getLabel('abuse-time', 3600), 'rate-key' => $route->getLabel('abuse-key', 'url:{url},ip:{ip}'), @@ -190,8 +188,8 @@ class OpenAPI3 extends Format } } - if (! (\is_array($model)) && $model->isNone()) { - $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ + if (!(\is_array($model)) && $model->isNone()) { + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => in_array($produces, [ 'image/*', 'image/jpeg', @@ -205,19 +203,19 @@ class OpenAPI3 extends Format ]; } else { if (\is_array($model)) { - $modelDescription = \implode(', or ', \array_map(fn ($m) => $m->getName(), $model)); + $modelDescription = \join(', or ', \array_map(fn ($m) => $m->getName(), $model)); // model has multiple possible responses, we will use oneOf foreach ($model as $m) { $usedModels[] = $m->getType(); } - $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => $modelDescription, 'content' => [ $produces => [ 'schema' => [ - 'oneOf' => \array_map(fn ($m) => ['$ref' => '#/components/schemas/'.$m->getType()], $model), + 'oneOf' => \array_map(fn ($m) => ['$ref' => '#/components/schemas/' . $m->getType()], $model) ], ], ], @@ -225,12 +223,12 @@ class OpenAPI3 extends Format } else { // Response definition using one type $usedModels[] = $model->getType(); - $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => $model->getName(), 'content' => [ $produces => [ 'schema' => [ - '$ref' => '#/components/schemas/'.$model->getType(), + '$ref' => '#/components/schemas/' . $model->getType(), ], ], ], @@ -239,11 +237,11 @@ class OpenAPI3 extends Format } if ($route->getLabel('sdk.response.code', 500) === 204) { - $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')]['description'] = 'No content'; - unset($temp['responses'][(string) $route->getLabel('sdk.response.code', '500')]['schema']); + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['description'] = 'No content'; + unset($temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['schema']); } - if ((! empty($scope))) { // && 'public' != $scope + if ((!empty($scope))) { // && 'public' != $scope $securities = ['Project' => []]; foreach ($route->getLabel('sdk.auth', []) as $security) { @@ -258,8 +256,8 @@ class OpenAPI3 extends Format $body = [ 'content' => [ - $consumes[0] => [ - 'schema' => [ + $consumes[0] => [ + 'schema' => [ 'type' => 'object', 'properties' => [], ], @@ -278,7 +276,7 @@ class OpenAPI3 extends Format $node = [ 'name' => $name, 'description' => $param['description'], - 'required' => ! $param['optional'], + 'required' => !$param['optional'], ]; foreach ($this->services as $service) { @@ -294,10 +292,10 @@ class OpenAPI3 extends Format $validator = $validator->getValidator(); } - switch ((! empty($validator)) ? \get_class($validator) : '') { + switch ((!empty($validator)) ? \get_class($validator) : '') { case 'Utopia\Validator\Text': $node['schema']['type'] = $validator->getType(); - $node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; + $node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; break; case 'Utopia\Validator\Boolean': $node['schema']['type'] = $validator->getType(); @@ -305,14 +303,14 @@ class OpenAPI3 extends Format break; case 'Utopia\Database\Validator\UID': $node['schema']['type'] = $validator->getType(); - $node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; + $node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; break; case 'Appwrite\Utopia\Database\Validator\CustomId': if ($route->getLabel('sdk.methodType', '') === 'upload') { $node['schema']['x-upload-id'] = true; } $node['schema']['type'] = $validator->getType(); - $node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; + $node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; break; case 'Utopia\Database\Validator\DatetimeValidator': $node['schema']['type'] = $validator->getType(); @@ -369,14 +367,14 @@ class OpenAPI3 extends Format $node['schema']['items'] = [ 'type' => 'string', ]; - $node['schema']['x-example'] = '["'.Permission::read(Role::any()).'"]'; + $node['schema']['x-example'] = '["' . Permission::read(Role::any()) . '"]'; break; case 'Utopia\Database\Validator\Roles': $node['schema']['type'] = $validator->getType(); $node['schema']['items'] = [ 'type' => 'string', ]; - $node['schema']['x-example'] = '["'.Role::any()->toString().'"]'; + $node['schema']['x-example'] = '["' . Role::any()->toString() . '"]'; break; case 'Appwrite\Auth\Validator\Password': $node['schema']['type'] = $validator->getType(); @@ -431,9 +429,9 @@ class OpenAPI3 extends Format } if ($allowed) { - $node['schema']['enum'] = $validator->getList(); - $node['schema']['x-enum-name'] = $this->getEnumName($route->getLabel('sdk.namespace', ''), $route->getLabel('sdk.method', ''), $name); - $node['schema']['x-enum-keys'] = $this->getEnumKeys($route->getLabel('sdk.namespace', ''), $route->getLabel('sdk.method', ''), $name); + $node['schema']['enum'] = $validator->getList(); + $node['schema']['x-enum-name'] = $this->getEnumName($route->getLabel('sdk.namespace', ''), $route->getLabel('sdk.method', ''), $name); + $node['schema']['x-enum-keys'] = $this->getEnumKeys($route->getLabel('sdk.namespace', ''), $route->getLabel('sdk.method', ''), $name); } if ($validator->getType() === 'integer') { $node['format'] = 'int32'; @@ -444,25 +442,25 @@ class OpenAPI3 extends Format break; } - if ($param['optional'] && ! \is_null($param['default'])) { // Param has default value + if ($param['optional'] && !\is_null($param['default'])) { // Param has default value $node['schema']['default'] = $param['default']; } - if (false !== \strpos($url, ':'.$name)) { // Param is in URL path + if (false !== \strpos($url, ':' . $name)) { // Param is in URL path $node['in'] = 'path'; $temp['parameters'][] = $node; } elseif ($route->getMethod() == 'GET') { // Param is in query $node['in'] = 'query'; $temp['parameters'][] = $node; } else { // Param is in payload - if (! $param['optional']) { + if (!$param['optional']) { $bodyRequired[] = $name; } $body['content'][$consumes[0]]['schema']['properties'][$name] = [ 'type' => $node['schema']['type'], 'description' => $node['description'], - 'x-example' => $node['schema']['x-example'] ?? null, + 'x-example' => $node['schema']['x-example'] ?? null ]; if (isset($node['schema']['enum'])) { @@ -493,14 +491,14 @@ class OpenAPI3 extends Format } } - $url = \str_replace(':'.$name, '{'.$name.'}', $url); + $url = \str_replace(':' . $name, '{' . $name . '}', $url); } - if (! empty($bodyRequired)) { + if (!empty($bodyRequired)) { $body['content'][$consumes[0]]['schema']['required'] = $bodyRequired; } - if (! empty($body['content'][$consumes[0]]['schema']['properties'])) { + if (!empty($body['content'][$consumes[0]]['schema']['properties'])) { $temp['requestBody'] = $body; } @@ -512,7 +510,7 @@ class OpenAPI3 extends Format } foreach ($this->models as $model) { - if (! in_array($model->getType(), $usedModels) && $model->getType() !== 'error') { + if (!in_array($model->getType(), $usedModels) && $model->getType() !== 'error') { continue; } @@ -524,7 +522,7 @@ class OpenAPI3 extends Format 'type' => 'object', ]; - if (! empty($rules)) { + if (!empty($rules)) { $output['components']['schemas'][$model->getType()]['properties'] = []; } @@ -532,7 +530,7 @@ class OpenAPI3 extends Format $output['components']['schemas'][$model->getType()]['additionalProperties'] = true; } - if (! empty($required)) { + if (!empty($required)) { $output['components']['schemas'][$model->getType()]['required'] = $required; } @@ -579,19 +577,19 @@ class OpenAPI3 extends Format if ($rule['array']) { $items = [ 'anyOf' => \array_map(function ($type) { - return ['$ref' => '#/components/schemas/'.$type]; - }, $rule['type']), + return ['$ref' => '#/components/schemas/' . $type]; + }, $rule['type']) ]; } else { $items = [ 'oneOf' => \array_map(function ($type) { - return ['$ref' => '#/components/schemas/'.$type]; - }, $rule['type']), + return ['$ref' => '#/components/schemas/' . $type]; + }, $rule['type']) ]; } } else { $items = [ - '$ref' => '#/components/schemas/'.$rule['type'], + '$ref' => '#/components/schemas/' . $rule['type'], ]; } break; @@ -624,7 +622,7 @@ class OpenAPI3 extends Format if ($items) { $output['components']['schemas'][$model->getType()]['properties'][$name]['items'] = $items; } - if (! in_array($name, $required)) { + if (!in_array($name, $required)) { $output['components']['schemas'][$model->getType()]['properties'][$name]['nullable'] = true; } } diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 15aad0238f..6b3d394aad 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -20,32 +20,30 @@ class Swagger2 extends Format protected function getNestedModels(Model $model, array &$usedModels): void { foreach ($model->getRules() as $rule) { - if (! in_array($model->getType(), $usedModels)) { + if (!in_array($model->getType(), $usedModels)) { continue; } if (\is_array($rule['type'])) { foreach ($rule['type'] as $ruleType) { - if (! in_array($ruleType, ['string', 'integer', 'boolean', 'json', 'float'])) { + if (!in_array($ruleType, ['string', 'integer', 'boolean', 'json', 'float'])) { $usedModels[] = $ruleType; foreach ($this->models as $m) { if ($m->getType() === $ruleType) { $this->getNestedModels($m, $usedModels); - continue; } } } } } else { - if (! in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float'])) { + if (!in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float'])) { $usedModels[] = $rule['type']; foreach ($this->models as $m) { if ($m->getType() === $rule['type']) { $this->getNestedModels($m, $usedModels); - continue; } } @@ -126,7 +124,7 @@ class Swagger2 extends Format } $id = $route->getLabel('sdk.method', \uniqid()); - $desc = (! empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__.'/../../../../'.$route->getLabel('sdk.description', '')) : null; + $desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__ . '/../../../../' . $route->getLabel('sdk.description', '')) : null; $produces = $route->getLabel('sdk.response.type', null); $model = $route->getLabel('sdk.response.model', 'none'); $routeSecurity = $route->getLabel('sdk.auth', []); @@ -155,7 +153,7 @@ class Swagger2 extends Format $temp = [ 'summary' => $route->getDesc(), - 'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id), + 'operationId' => $route->getLabel('sdk.namespace', 'default') . ucfirst($id), 'consumes' => [], 'produces' => [], 'tags' => [$route->getLabel('sdk.namespace', 'default')], @@ -166,8 +164,8 @@ class Swagger2 extends Format 'weight' => $route->getOrder(), 'cookies' => $route->getLabel('sdk.cookies', false), 'type' => $route->getLabel('sdk.methodType', ''), - 'demo' => Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')).'/'.Template::fromCamelCaseToDash($id).'.md', - 'edit' => 'https://github.com/appwrite/appwrite/edit/master'.$route->getLabel('sdk.description', ''), + 'demo' => Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')) . '/' . Template::fromCamelCaseToDash($id) . '.md', + 'edit' => 'https://github.com/appwrite/appwrite/edit/master' . $route->getLabel('sdk.description', ''), 'rate-limit' => $route->getLabel('abuse-limit', 0), 'rate-time' => $route->getLabel('abuse-time', 3600), 'rate-key' => $route->getLabel('abuse-key', 'url:{url},ip:{ip}'), @@ -195,8 +193,8 @@ class Swagger2 extends Format } } - if (! (\is_array($model)) && $model->isNone()) { - $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ + if (!(\is_array($model)) && $model->isNone()) { + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => in_array($produces, [ 'image/*', 'image/jpeg', @@ -208,42 +206,42 @@ class Swagger2 extends Format 'image/bmp', ]) ? 'Image' : 'File', 'schema' => [ - 'type' => 'file', + 'type' => 'file' ], ]; } else { if (\is_array($model)) { - $modelDescription = \implode(', or ', \array_map(fn ($m) => $m->getName(), $model)); + $modelDescription = \join(', or ', \array_map(fn ($m) => $m->getName(), $model)); // model has multiple possible responses, we will use oneOf foreach ($model as $m) { $usedModels[] = $m->getType(); } - $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => $modelDescription, 'schema' => [ 'x-oneOf' => \array_map(function ($m) { - return ['$ref' => '#/definitions/'.$m->getType()]; - }, $model), + return ['$ref' => '#/definitions/' . $m->getType()]; + }, $model) ], ]; } else { // Response definition using one type $usedModels[] = $model->getType(); - $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')] = [ + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => $model->getName(), 'schema' => [ - '$ref' => '#/definitions/'.$model->getType(), + '$ref' => '#/definitions/' . $model->getType(), ], ]; } } if (in_array($route->getLabel('sdk.response.code', 500), [204, 301, 302, 308], true)) { - $temp['responses'][(string) $route->getLabel('sdk.response.code', '500')]['description'] = 'No content'; - unset($temp['responses'][(string) $route->getLabel('sdk.response.code', '500')]['schema']); + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['description'] = 'No content'; + unset($temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['schema']); } - if ((! empty($scope))) { // && 'public' != $scope + if ((!empty($scope))) { // && 'public' != $scope $securities = ['Project' => []]; foreach ($route->getLabel('sdk.auth', []) as $security) { @@ -279,7 +277,7 @@ class Swagger2 extends Format $node = [ 'name' => $name, 'description' => $param['description'], - 'required' => ! $param['optional'], + 'required' => !$param['optional'], ]; foreach ($this->services as $service) { @@ -295,10 +293,11 @@ class Swagger2 extends Format $validator = $validator->getValidator(); } - switch ((! empty($validator)) ? \get_class($validator) : '') { + + switch ((!empty($validator)) ? \get_class($validator) : '') { case 'Utopia\Validator\Text': $node['type'] = $validator->getType(); - $node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; + $node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; break; case 'Utopia\Validator\Boolean': $node['type'] = $validator->getType(); @@ -309,11 +308,11 @@ class Swagger2 extends Format $node['x-upload-id'] = true; } $node['type'] = $validator->getType(); - $node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; + $node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; break; case 'Utopia\Database\Validator\UID': $node['type'] = $validator->getType(); - $node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; + $node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; break; case 'Utopia\Database\Validator\DatetimeValidator': $node['type'] = $validator->getType(); @@ -370,7 +369,7 @@ class Swagger2 extends Format $node['items'] = [ 'type' => 'string', ]; - $node['x-example'] = '["'.Permission::read(Role::any()).'"]'; + $node['x-example'] = '["' . Permission::read(Role::any()) . '"]'; break; case 'Utopia\Database\Validator\Roles': $node['type'] = $validator->getType(); @@ -378,7 +377,7 @@ class Swagger2 extends Format $node['items'] = [ 'type' => 'string', ]; - $node['x-example'] = '["'.Role::any()->toString().'"]'; + $node['x-example'] = '["' . Role::any()->toString() . '"]'; break; case 'Appwrite\Auth\Validator\Password': $node['type'] = $validator->getType(); @@ -443,11 +442,11 @@ class Swagger2 extends Format break; } - if ($param['optional'] && ! \is_null($param['default'])) { // Param has default value + if ($param['optional'] && !\is_null($param['default'])) { // Param has default value $node['default'] = $param['default']; } - if (false !== \strpos($url, ':'.$name)) { // Param is in URL path + if (false !== \strpos($url, ':' . $name)) { // Param is in URL path $node['in'] = 'path'; $temp['parameters'][] = $node; } elseif ($route->getMethod() == 'GET') { // Param is in query @@ -461,7 +460,7 @@ class Swagger2 extends Format continue; } - if (! $param['optional']) { + if (!$param['optional']) { $bodyRequired[] = $name; } @@ -492,14 +491,14 @@ class Swagger2 extends Format } } - $url = \str_replace(':'.$name, '{'.$name.'}', $url); + $url = \str_replace(':' . $name, '{' . $name . '}', $url); } - if (! empty($bodyRequired)) { + if (!empty($bodyRequired)) { $body['schema']['required'] = $bodyRequired; } - if (! empty($body['schema']['properties'])) { + if (!empty($body['schema']['properties'])) { $temp['parameters'][] = $body; } @@ -513,7 +512,7 @@ class Swagger2 extends Format } foreach ($this->models as $model) { - if (! in_array($model->getType(), $usedModels)) { + if (!in_array($model->getType(), $usedModels)) { continue; } @@ -525,7 +524,7 @@ class Swagger2 extends Format 'type' => 'object', ]; - if (! empty($rules)) { + if (!empty($rules)) { $output['definitions'][$model->getType()]['properties'] = []; } @@ -533,7 +532,7 @@ class Swagger2 extends Format $output['definitions'][$model->getType()]['additionalProperties'] = true; } - if (! empty($required)) { + if (!empty($required)) { $output['definitions'][$model->getType()]['required'] = $required; } @@ -578,17 +577,17 @@ class Swagger2 extends Format if (\is_array($rule['type'])) { if ($rule['array']) { $items = [ - 'x-anyOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/'.$type], $rule['type']), + 'x-anyOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/' . $type], $rule['type']) ]; } else { $items = [ - 'x-oneOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/'.$type], $rule['type']), + 'x-oneOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/' . $type], $rule['type']) ]; } } else { $items = [ 'type' => $type, - '$ref' => '#/definitions/'.$rule['type'], + '$ref' => '#/definitions/' . $rule['type'], ]; } break; @@ -601,7 +600,6 @@ class Swagger2 extends Format 'description' => $rule['description'] ?? '', 'x-example' => $rule['example'] ?? null, ]; - continue; } @@ -632,7 +630,7 @@ class Swagger2 extends Format if ($items) { $output['definitions'][$model->getType()]['properties'][$name]['items'] = $items; } - if (! in_array($name, $required)) { + if (!in_array($name, $required)) { $output['definitions'][$model->getType()]['properties'][$name]['x-nullable'] = true; } } diff --git a/src/Appwrite/Task/Validator/Cron.php b/src/Appwrite/Task/Validator/Cron.php index a2709bc1c0..03bd1c5220 100644 --- a/src/Appwrite/Task/Validator/Cron.php +++ b/src/Appwrite/Task/Validator/Cron.php @@ -24,7 +24,8 @@ class Cron extends Validator * * Returns true if valid or false if not. * - * @param mixed $value + * @param mixed $value + * * @return bool */ public function isValid($value): bool @@ -33,7 +34,7 @@ class Cron extends Validator return true; } - if (! CronExpression::isValidExpression($value)) { + if (!CronExpression::isValidExpression($value)) { return false; } diff --git a/src/Appwrite/Template/Template.php b/src/Appwrite/Template/Template.php index 6b2bec0aef..c01d54389b 100644 --- a/src/Appwrite/Template/Template.php +++ b/src/Appwrite/Template/Template.php @@ -17,17 +17,18 @@ class Template extends View * * Creates a new Template() from the file at $path * - * @param string $path + * @param string $path + * * @return self + * */ public static function fromFile(string $path): self { - if (! \is_readable($path)) { + if (!\is_readable($path)) { throw new Exception("$path view template is not readable."); } $template = new Template(); - return $template->setPath($path); } @@ -36,8 +37,10 @@ class Template extends View * * Creates a new Template() using a raw string * - * @param string $content + * @param string $content + * * @return self + * */ public static function fromString(string $content): self { @@ -47,7 +50,6 @@ class Template extends View $template = new Template(); $template->content = $content; - return $template; } @@ -69,10 +71,10 @@ class Template extends View if (\is_readable($this->path)) { $template = \file_get_contents($this->path); // Include template file - } elseif (! empty($this->content)) { + } elseif (!empty($this->content)) { $template = $this->print($this->content, self::FILTER_NL2P); } else { - throw new Exception('"'.$this->path.'" template is not readable or not found'); + throw new Exception('"' . $this->path . '" template is not readable or not found'); } // First replace the variables inside the params. Then replace the variables in the template @@ -88,6 +90,7 @@ class Template extends View * Parse URL string to array * * @param $url + * * @return mixed On seriously malformed URLs, parse_url() may return FALSE. */ public static function parseURL($url) @@ -101,24 +104,25 @@ class Template extends View * Convert PHP array to query string * * @param $url + * * @return string */ public static function unParseURL(array $url) { - $scheme = isset($url['scheme']) ? $url['scheme'].'://' : ''; + $scheme = isset($url['scheme']) ? $url['scheme'] . '://' : ''; $host = isset($url['host']) ? $url['host'] : ''; - $port = isset($url['port']) ? ':'.$url['port'] : ''; + $port = isset($url['port']) ? ':' . $url['port'] : ''; $user = isset($url['user']) ? $url['user'] : ''; - $pass = isset($url['pass']) ? ':'.$url['pass'] : ''; + $pass = isset($url['pass']) ? ':' . $url['pass'] : ''; $pass = ($user || $pass) ? "$pass@" : ''; $path = isset($url['path']) ? $url['path'] : ''; - $query = isset($url['query']) && ! empty($url['query']) ? '?'.$url['query'] : ''; + $query = isset($url['query']) && !empty($url['query']) ? '?' . $url['query'] : ''; - $fragment = isset($url['fragment']) ? '#'.$url['fragment'] : ''; + $fragment = isset($url['fragment']) ? '#' . $url['fragment'] : ''; - return $scheme.$user.$pass.$host.$port.$path.$query.$fragment; + return $scheme . $user . $pass . $host . $port . $path . $query . $fragment; } /** @@ -127,7 +131,8 @@ class Template extends View * Merge array of params to query string * * @param $query1 - * @param array $query2 + * @param array $query2 + * * @return string */ public static function mergeQuery($query1, array $query2) @@ -144,7 +149,7 @@ class Template extends View /** * From Camel Case * - * @var string + * @var string $input * * @return string */ @@ -162,7 +167,7 @@ class Template extends View /** * From Camel Case to Dash Case * - * @var string + * @var string $input * * @return string */ diff --git a/src/Appwrite/URL/URL.php b/src/Appwrite/URL/URL.php index bfc6b8ee7d..98250ab429 100644 --- a/src/Appwrite/URL/URL.php +++ b/src/Appwrite/URL/URL.php @@ -9,7 +9,8 @@ class URL * * Take a URL string and split it to array parts * - * @param string $url + * @param string $url + * * @return array */ public static function parse(string $url): array @@ -33,45 +34,46 @@ class URL * * Take URL parts and combine them to a valid string * - * @param array $url - * @param array $ommit + * @param array $url + * @param array $ommit + * * @return string */ public static function unparse(array $url, array $ommit = []): string { if (isset($url['path']) && \mb_substr($url['path'], 0, 1) !== '/') { - $url['path'] = '/'.$url['path']; + $url['path'] = '/' . $url['path']; } $parts = []; - $parts['scheme'] = isset($url['scheme']) ? $url['scheme'].'://' : ''; + $parts['scheme'] = isset($url['scheme']) ? $url['scheme'] . '://' : ''; $parts['host'] = isset($url['host']) ? $url['host'] : ''; - $parts['port'] = isset($url['port']) ? ':'.$url['port'] : ''; + $parts['port'] = isset($url['port']) ? ':' . $url['port'] : ''; $parts['user'] = isset($url['user']) ? $url['user'] : ''; - $parts['pass'] = isset($url['pass']) ? ':'.$url['pass'] : ''; + $parts['pass'] = isset($url['pass']) ? ':' . $url['pass'] : ''; - $parts['pass'] = ($parts['user'] || $parts['pass']) ? $parts['pass'].'@' : ''; + $parts['pass'] = ($parts['user'] || $parts['pass']) ? $parts['pass'] . '@' : ''; $parts['path'] = isset($url['path']) ? $url['path'] : ''; - $parts['query'] = isset($url['query']) && ! empty($url['query']) ? '?'.$url['query'] : ''; + $parts['query'] = isset($url['query']) && !empty($url['query']) ? '?' . $url['query'] : ''; - $parts['fragment'] = isset($url['fragment']) ? '#'.$url['fragment'] : ''; + $parts['fragment'] = isset($url['fragment']) ? '#' . $url['fragment'] : ''; if ($ommit) { foreach ($ommit as $key) { - if (isset($parts[$key])) { - $parts[$key] = ''; + if (isset($parts[ $key ])) { + $parts[ $key ] = ''; } } } - return $parts['scheme'].$parts['user'].$parts['pass'].$parts['host'].$parts['port'].$parts['path'].$parts['query'].$parts['fragment']; + return $parts['scheme'] . $parts['user'] . $parts['pass'] . $parts['host'] . $parts['port'] . $parts['path'] . $parts['query'] . $parts['fragment']; } /** @@ -79,7 +81,8 @@ class URL * * Convert query string to array * - * @param string $query + * @param string $query + * * @return array */ public static function parseQuery(string $query): array @@ -94,7 +97,8 @@ class URL * * Convert query string array to string * - * @param array $query + * @param array $query + * * @return string */ public static function unparseQuery(array $query): string diff --git a/src/Appwrite/Utopia/Database/Validator/CustomId.php b/src/Appwrite/Utopia/Database/Validator/CustomId.php index b6e913cb46..90d550371b 100644 --- a/src/Appwrite/Utopia/Database/Validator/CustomId.php +++ b/src/Appwrite/Utopia/Database/Validator/CustomId.php @@ -12,10 +12,12 @@ class CustomId extends Key * Returns true if valid or false if not. * * @param $value + * * @return bool */ public function isValid($value): bool { + return $value == 'unique()' || parent::isValid($value); } } diff --git a/src/Appwrite/Utopia/Database/Validator/ProjectId.php b/src/Appwrite/Utopia/Database/Validator/ProjectId.php index 482a74fc57..46b0cdf53e 100644 --- a/src/Appwrite/Utopia/Database/Validator/ProjectId.php +++ b/src/Appwrite/Utopia/Database/Validator/ProjectId.php @@ -12,6 +12,7 @@ class ProjectId extends Validator * Returns true if valid or false if not. * * @param $value + * * @return bool */ public function isValid($value): bool diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php b/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php index 86264df395..1463316ad1 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php @@ -2,6 +2,8 @@ namespace Appwrite\Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Select; + class Attributes extends Base { public const ALLOWED_ATTRIBUTES = [ @@ -11,11 +13,12 @@ class Attributes extends Base 'required', 'array', 'status', - 'error', + 'error' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Base.php b/src/Appwrite/Utopia/Database/Validator/Queries/Base.php index eca03206f9..3eea7b7b7e 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Base.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Base.php @@ -2,24 +2,24 @@ namespace Appwrite\Utopia\Database\Validator\Queries; +use Appwrite\Extend\Exception; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; +use Utopia\Database\Validator\Query\Cursor; +use Utopia\Database\Validator\Query\Filter; +use Utopia\Database\Validator\Query\Order; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Cursor; -use Utopia\Database\Validator\Query\Filter; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; -use Utopia\Database\Validator\Query\Order; class Base extends Queries { /** * Expression constructor * - * @param string $collection - * @param string[] $allowedAttributes - * + * @param string $collection + * @param string[] $allowedAttributes * @throws \Exception */ public function __construct(string $collection, array $allowedAttributes) @@ -36,7 +36,7 @@ class Base extends Queries $attributes = []; foreach ($collection['attributes'] as $attribute) { $key = $attribute['$id']; - if (! isset($allowedAttributesLookup[$key])) { + if (!isset($allowedAttributesLookup[$key])) { continue; } diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php b/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php index 91d467b203..c4d187520f 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Buckets.php @@ -10,11 +10,12 @@ class Buckets extends Base 'fileSecurity', 'maximumFileSize', 'encryption', - 'antivirus', + 'antivirus' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Collections.php b/src/Appwrite/Utopia/Database/Validator/Queries/Collections.php index 9bf2381ed2..6e8fcb8339 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Collections.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Collections.php @@ -7,11 +7,12 @@ class Collections extends Base public const ALLOWED_ATTRIBUTES = [ 'name', 'enabled', - 'documentSecurity', + 'documentSecurity' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Databases.php b/src/Appwrite/Utopia/Database/Validator/Queries/Databases.php index e47d9020d1..22f7ad9b82 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Databases.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Databases.php @@ -5,11 +5,12 @@ namespace Appwrite\Utopia\Database\Validator\Queries; class Databases extends Base { public const ALLOWED_ATTRIBUTES = [ - 'name', + 'name' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php b/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php index 20fe9a7123..05b3326af1 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php @@ -13,6 +13,7 @@ class Deployments extends Base /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php b/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php index ca74367164..2bfe46e28d 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php @@ -8,11 +8,12 @@ class Executions extends Base 'trigger', 'status', 'statusCode', - 'duration', + 'duration' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Files.php b/src/Appwrite/Utopia/Database/Validator/Queries/Files.php index 5984d32b9c..1941eabcdb 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Files.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Files.php @@ -10,11 +10,12 @@ class Files extends Base 'mimeType', 'sizeOriginal', 'chunksTotal', - 'chunksUploaded', + 'chunksUploaded' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php b/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php index 77b7e14028..a2ba368953 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php @@ -12,11 +12,12 @@ class Functions extends Base 'schedule', 'scheduleNext', 'schedulePrevious', - 'timeout', + 'timeout' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php b/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php index 346c2f4799..cb0462ee13 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php @@ -14,6 +14,7 @@ class Identities extends Base /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Indexes.php b/src/Appwrite/Utopia/Database/Validator/Queries/Indexes.php index 6ebf3cf50f..d9290e5737 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Indexes.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Indexes.php @@ -14,6 +14,7 @@ class Indexes extends Base /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Memberships.php b/src/Appwrite/Utopia/Database/Validator/Queries/Memberships.php index 73add15ac4..5ff0098662 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Memberships.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Memberships.php @@ -9,11 +9,12 @@ class Memberships extends Base 'teamId', 'invited', 'joined', - 'confirm', + 'confirm' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php b/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php index 3cada3f633..6b9e9e6d32 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php @@ -11,11 +11,12 @@ class Migrations extends Base 'resources', 'statusCounters', 'resourceData', - 'errors', + 'errors' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php b/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php index 6f36d73660..7fff26db7f 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php @@ -2,15 +2,18 @@ namespace Appwrite\Utopia\Database\Validator\Queries; +use Appwrite\Utopia\Database\Validator\Queries\Base; + class Projects extends Base { public const ALLOWED_ATTRIBUTES = [ 'name', - 'teamId', + 'teamId' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php index 00beab4e1d..83dbf665f1 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php @@ -12,6 +12,7 @@ class Providers extends Base /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Teams.php b/src/Appwrite/Utopia/Database/Validator/Queries/Teams.php index ccc5fdbf7c..67aba71598 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Teams.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Teams.php @@ -6,11 +6,12 @@ class Teams extends Base { public const ALLOWED_ATTRIBUTES = [ 'name', - 'total', + 'total' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Users.php b/src/Appwrite/Utopia/Database/Validator/Queries/Users.php index b0fe844017..9b0dfe61e6 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Users.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Users.php @@ -12,11 +12,12 @@ class Users extends Base 'passwordUpdate', 'registration', 'emailVerification', - 'phoneVerification', + 'phoneVerification' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php b/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php index 978c763b84..eff7007c58 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php @@ -2,14 +2,17 @@ namespace Appwrite\Utopia\Database\Validator\Queries; +use Appwrite\Utopia\Database\Validator\Queries\Base; + class Variables extends Base { public const ALLOWED_ATTRIBUTES = [ - 'key', + 'key' ]; /** * Expression constructor + * */ public function __construct() { diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php index 3f4d368e78..229c9dd53d 100644 --- a/src/Appwrite/Utopia/Request.php +++ b/src/Appwrite/Utopia/Request.php @@ -10,7 +10,6 @@ use Utopia\Swoole\Request as UtopiaRequest; class Request extends UtopiaRequest { private static ?Filter $filter = null; - private static ?Route $route = null; public function __construct(SwooleRequest $request) @@ -19,14 +18,14 @@ class Request extends UtopiaRequest } /** - * {@inheritdoc} + * @inheritdoc */ public function getParams(): array { $parameters = parent::getParams(); if (self::hasFilter() && self::hasRoute()) { - $endpointIdentifier = self::getRoute()->getLabel('sdk.namespace', 'unknown').'.'.self::getRoute()->getLabel('sdk.method', 'unknown'); + $endpointIdentifier = self::getRoute()->getLabel('sdk.namespace', 'unknown') . '.' . self::getRoute()->getLabel('sdk.method', 'unknown'); $parameters = self::getFilter()->parse($parameters, $endpointIdentifier); } @@ -36,7 +35,8 @@ class Request extends UtopiaRequest /** * Function to set a response filter * - * @param Filter|null $filter Filter the response filter to set + * @param Filter|null $filter Filter the response filter to set + * * @return void */ public static function setFilter(?Filter $filter): void @@ -67,7 +67,8 @@ class Request extends UtopiaRequest /** * Function to set a request route * - * @param Route|null $route the request route to set + * @param Route|null $route the request route to set + * * @return void */ public static function setRoute(?Route $route): void diff --git a/src/Appwrite/Utopia/Request/Filter.php b/src/Appwrite/Utopia/Request/Filter.php index 4c1ea1bfd1..59346c7e17 100644 --- a/src/Appwrite/Utopia/Request/Filter.php +++ b/src/Appwrite/Utopia/Request/Filter.php @@ -7,8 +7,9 @@ abstract class Filter /** * Parse params to another format. * - * @param array $content - * @param string $model + * @param array $content + * @param string $model + * * @return array */ abstract public function parse(array $content, string $model): array; diff --git a/src/Appwrite/Utopia/Request/Filters/V12.php b/src/Appwrite/Utopia/Request/Filters/V12.php index 96fbf62885..f2a65307ae 100644 --- a/src/Appwrite/Utopia/Request/Filters/V12.php +++ b/src/Appwrite/Utopia/Request/Filters/V12.php @@ -11,44 +11,44 @@ class V12 extends Filter { switch ($model) { // No IDs -> Custom IDs - case 'account.create': - case 'account.createMagicURLSession': - case 'users.create': + case "account.create": + case "account.createMagicURLSession": + case "users.create": $content = $this->addId($content, 'userId'); break; - case 'functions.create': + case "functions.create": $content = $this->addId($content, 'functionId'); break; - case 'teams.create': + case "teams.create": $content = $this->addId($content, 'teamId'); break; - // Status integer -> boolean - case 'users.updateStatus': + // Status integer -> boolean + case "users.updateStatus": $content = $this->convertStatus($content); break; - // Deprecating order type - case 'functions.listExecutions': + // Deprecating order type + case "functions.listExecutions": $content = $this->removeOrderType($content); break; - // The rest (more complex) formats - case 'database.createDocument': + // The rest (more complex) formats + case "database.createDocument": $content = $this->addId($content, 'documentId'); $content = $this->removeParentProperties($content); break; - case 'database.listDocuments': + case "database.listDocuments": $content = $this->removeOrderCast($content); $content = $this->convertOrder($content); $content = $this->convertQueries($content); break; - case 'database.createCollection': + case "database.createCollection": $content = $this->addId($content, 'collectionId'); $content = $this->removeRules($content); $content = $this->addCollectionPermissionLevel($content); break; - case 'database.updateCollection': + case "database.updateCollection": $content = $this->removeRules($content); $content = $this->addCollectionPermissionLevel($content); break; @@ -62,14 +62,12 @@ class V12 extends Filter protected function addId(array $content, string $key): array { $content[$key] = 'unique()'; - return $content; } protected function addCollectionPermissionLevel(array $content): array { $content['permission'] = 'document'; - return $content; } @@ -78,21 +76,18 @@ class V12 extends Filter protected function removeRules(array $content): array { unset($content['rules']); - return $content; } protected function removeOrderType(array $content): array { unset($content['orderType']); - return $content; } protected function removeOrderCast(array $content): array { unset($content['orderCast']); - return $content; } @@ -107,7 +102,6 @@ class V12 extends Filter if (isset($content['parentPropertyType'])) { unset($content['parentPropertyType']); } - return $content; } @@ -118,19 +112,18 @@ class V12 extends Filter if (isset($content['status'])) { $content['status'] = $content['status'] === 2 ? false : true; } - return $content; } protected function convertOrder(array $content): array { if (isset($content['orderField'])) { - $content['orderAttributes'] = [$content['orderField']]; + $content['orderAttributes'] = [ $content['orderField'] ]; unset($content['orderField']); } if (isset($content['orderType'])) { - $content['orderTypes'] = [$content['orderType']]; + $content['orderTypes'] = [ $content['orderType'] ]; unset($content['orderType']); } @@ -141,7 +134,7 @@ class V12 extends Filter { $queries = []; - if (! empty($content['filters'])) { + if (!empty($content['filters'])) { foreach ($content['filters'] as $filter) { $operators = ['=' => 'equal', '!=' => 'notEqual', '>' => 'greater', '<' => 'lesser', '<=' => 'lesserEqual', '>=' => 'greaterEqual']; foreach ($operators as $operator => $operatorVerbose) { @@ -158,10 +151,10 @@ class V12 extends Filter // Let's keep it at true and false string, but without "" around // No action needed } else { - $filterValue = \is_numeric($filterValue) ? $filterValue : '"'.$filterValue.'"'; + $filterValue = \is_numeric($filterValue) ? $filterValue : '"' . $filterValue . '"'; } - $query = $attributeKey.'.'.$operators[$usedOperator].'('.$filterValue.')'; + $query = $attributeKey . '.' . $operators[$usedOperator] . '(' . $filterValue . ')'; \array_push($queries, $query); } } diff --git a/src/Appwrite/Utopia/Request/Filters/V13.php b/src/Appwrite/Utopia/Request/Filters/V13.php index 3f297b5943..e1122fdd71 100644 --- a/src/Appwrite/Utopia/Request/Filters/V13.php +++ b/src/Appwrite/Utopia/Request/Filters/V13.php @@ -11,13 +11,13 @@ class V13 extends Filter { switch ($model) { // Replaced Types - case 'database.createIntegerAttribute': - case 'database.createFloatAttribute': - $content = $this->convertStringToNum($content, 'min'); - $content = $this->convertStringToNum($content, 'max'); - $content = $this->convertStringToNum($content, 'default'); + case "database.createIntegerAttribute": + case "database.createFloatAttribute": + $content = $this->convertStringToNum($content, "min"); + $content = $this->convertStringToNum($content, "max"); + $content = $this->convertStringToNum($content, "default"); break; - case 'functions.createExecution': + case "functions.createExecution": $content = $this->convertExecution($content); } @@ -26,15 +26,13 @@ class V13 extends Filter private function convertStringToNum($content, $value) { - $content[$value] = is_null($content[$value]) ? null : (int) $content[$value]; - + $content[$value] = is_null($content[$value]) ? null : (int)$content[$value]; return $content; } private function convertExecution($content) { $content['async'] = true; - return $content; } } diff --git a/src/Appwrite/Utopia/Request/Filters/V14.php b/src/Appwrite/Utopia/Request/Filters/V14.php index 1b50404f82..7130307f0d 100644 --- a/src/Appwrite/Utopia/Request/Filters/V14.php +++ b/src/Appwrite/Utopia/Request/Filters/V14.php @@ -2,8 +2,8 @@ namespace Appwrite\Utopia\Request\Filters; -use Appwrite\Migration\Version\V13 as MigrationV13; use Appwrite\Utopia\Request\Filter; +use Appwrite\Migration\Version\V13 as MigrationV13; class V14 extends Filter { @@ -11,10 +11,10 @@ class V14 extends Filter public function parse(array $content, string $model): array { switch ($model) { - case 'functions.create': - case 'functions.update': - case 'projects.createWebhook': - case 'projects.updateWebhook': + case "functions.create": + case "functions.update": + case "projects.createWebhook": + case "projects.updateWebhook": $content = $this->convertEvents($content); break; } @@ -27,7 +27,7 @@ class V14 extends Filter $migration = new MigrationV13(); $events = $content['events'] ?? []; - $content['events'] = $migration->migrateEvents($events); + $content['events'] = $migration->migrateEvents($events); return $content; } diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php index d535777350..318096fe0d 100644 --- a/src/Appwrite/Utopia/Request/Filters/V15.php +++ b/src/Appwrite/Utopia/Request/Filters/V15.php @@ -5,8 +5,8 @@ namespace Appwrite\Utopia\Request\Filters; use Appwrite\Utopia\Request\Filter; use Utopia\Database\Database; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Database\Helpers\Role; class V15 extends Filter { @@ -81,11 +81,11 @@ class V15 extends Filter protected function convertLimitAndOffset($content) { if (isset($content['limit'])) { - $content['queries'][] = 'limit('.$content['limit'].')'; + $content['queries'][] = 'limit(' . $content['limit'] . ')'; } if (isset($content['offset'])) { - $content['queries'][] = 'offset('.$content['offset'].')'; + $content['queries'][] = 'offset(' . $content['offset'] . ')'; } unset($content['limit']); @@ -100,9 +100,9 @@ class V15 extends Filter $cursorDirection = $content['cursorDirection'] ?? Database::CURSOR_AFTER; if ($cursorDirection === Database::CURSOR_BEFORE) { - $content['queries'][] = 'cursorBefore("'.$content['cursor'].'")'; + $content['queries'][] = 'cursorBefore("' . $content["cursor"] . '")'; } else { - $content['queries'][] = 'cursorAfter("'.$content['cursor'].'")'; + $content['queries'][] = 'cursorAfter("' . $content["cursor"] . '")'; } } @@ -133,9 +133,9 @@ class V15 extends Filter $attribute = $content['orderAttributes'][$i] ?? ''; if ($type === Database::ORDER_DESC) { - $content['queries'][] = 'orderDesc("'.$attribute.'")'; + $content['queries'][] = 'orderDesc("' . $attribute . '")'; } else { - $content['queries'][] = 'orderAsc("'.$attribute.'")'; + $content['queries'][] = 'orderAsc("' . $attribute . '")'; } } } @@ -194,7 +194,7 @@ class V15 extends Filter protected function convertFilters($content) { - if (! isset($content['queries'])) { + if (!isset($content['queries'])) { return $content; } @@ -214,19 +214,18 @@ class V15 extends Filter $parts = explode($middle, $query); if (count($parts) > 1) { $attribute = $parts[0]; - $value = rtrim($parts[1], ')'); - $content['queries'][$i] = $newOperation.'("'.$attribute.'", ['.$value.'])'; + $value = rtrim($parts[1], ")"); + $content['queries'][$i] = $newOperation . '("' . $attribute . '", [' . $value . '])'; } } } } - return $content; } protected function convertExecute($content) { - if (! isset($content['execute'])) { + if (!isset($content['execute'])) { return $content; } @@ -248,7 +247,7 @@ class V15 extends Filter protected function convertExpire($content) { - if (! isset($content['expire'])) { + if (!isset($content['expire'])) { return $content; } diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 2954fc9d0d..952226a8d9 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -2,6 +2,14 @@ namespace Appwrite\Utopia; +use Appwrite\Utopia\Response\Model\Message; +use Appwrite\Utopia\Response\Model\Subscriber; +use Appwrite\Utopia\Response\Model\Topic; +use Exception; +use Swoole\Http\Request as SwooleRequest; +use Utopia\Swoole\Response as SwooleResponse; +use Swoole\Http\Response as SwooleHTTPResponse; +use Utopia\Database\Document; use Appwrite\Utopia\Response\Filter; use Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response\Model\Account; @@ -12,72 +20,70 @@ use Appwrite\Utopia\Response\Model\AlgoPhpass; use Appwrite\Utopia\Response\Model\AlgoScrypt; use Appwrite\Utopia\Response\Model\AlgoScryptModified; use Appwrite\Utopia\Response\Model\AlgoSha; +use Appwrite\Utopia\Response\Model\None; use Appwrite\Utopia\Response\Model\Any; use Appwrite\Utopia\Response\Model\Attribute; +use Appwrite\Utopia\Response\Model\AttributeList; +use Appwrite\Utopia\Response\Model\AttributeString; +use Appwrite\Utopia\Response\Model\AttributeInteger; +use Appwrite\Utopia\Response\Model\AttributeFloat; use Appwrite\Utopia\Response\Model\AttributeBoolean; -use Appwrite\Utopia\Response\Model\AttributeDatetime; use Appwrite\Utopia\Response\Model\AttributeEmail; use Appwrite\Utopia\Response\Model\AttributeEnum; -use Appwrite\Utopia\Response\Model\AttributeFloat; -use Appwrite\Utopia\Response\Model\AttributeInteger; use Appwrite\Utopia\Response\Model\AttributeIP; -use Appwrite\Utopia\Response\Model\AttributeList; -use Appwrite\Utopia\Response\Model\AttributeRelationship; -use Appwrite\Utopia\Response\Model\AttributeString; use Appwrite\Utopia\Response\Model\AttributeURL; +use Appwrite\Utopia\Response\Model\AttributeDatetime; +use Appwrite\Utopia\Response\Model\AttributeRelationship; use Appwrite\Utopia\Response\Model\AuthProvider; use Appwrite\Utopia\Response\Model\BaseList; -use Appwrite\Utopia\Response\Model\Bucket; -use Appwrite\Utopia\Response\Model\Build; use Appwrite\Utopia\Response\Model\Collection; -use Appwrite\Utopia\Response\Model\ConsoleVariables; +use Appwrite\Utopia\Response\Model\Database; use Appwrite\Utopia\Response\Model\Continent; use Appwrite\Utopia\Response\Model\Country; use Appwrite\Utopia\Response\Model\Currency; -use Appwrite\Utopia\Response\Model\Database; -use Appwrite\Utopia\Response\Model\Deployment; use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Domain; use Appwrite\Utopia\Response\Model\Error; use Appwrite\Utopia\Response\Model\ErrorDev; use Appwrite\Utopia\Response\Model\Execution; +use Appwrite\Utopia\Response\Model\Build; use Appwrite\Utopia\Response\Model\File; +use Appwrite\Utopia\Response\Model\Bucket; +use Appwrite\Utopia\Response\Model\ConsoleVariables; use Appwrite\Utopia\Response\Model\Func; -use Appwrite\Utopia\Response\Model\HealthAntivirus; -use Appwrite\Utopia\Response\Model\HealthQueue; -use Appwrite\Utopia\Response\Model\HealthStatus; -use Appwrite\Utopia\Response\Model\HealthTime; -use Appwrite\Utopia\Response\Model\HealthVersion; use Appwrite\Utopia\Response\Model\Identity; use Appwrite\Utopia\Response\Model\Index; use Appwrite\Utopia\Response\Model\JWT; use Appwrite\Utopia\Response\Model\Key; use Appwrite\Utopia\Response\Model\Language; +use Appwrite\Utopia\Response\Model\User; +use Appwrite\Utopia\Response\Model\Session; +use Appwrite\Utopia\Response\Model\Team; use Appwrite\Utopia\Response\Model\Locale; -use Appwrite\Utopia\Response\Model\LocaleCode; use Appwrite\Utopia\Response\Model\Log; use Appwrite\Utopia\Response\Model\Membership; -use Appwrite\Utopia\Response\Model\Message; use Appwrite\Utopia\Response\Model\Metric; -use Appwrite\Utopia\Response\Model\Migration; -use Appwrite\Utopia\Response\Model\MigrationFirebaseProject; -use Appwrite\Utopia\Response\Model\MigrationReport; -use Appwrite\Utopia\Response\Model\Mock; -use Appwrite\Utopia\Response\Model\None; +use Appwrite\Utopia\Response\Model\Permissions; use Appwrite\Utopia\Response\Model\Phone; use Appwrite\Utopia\Response\Model\Platform; -use Appwrite\Utopia\Response\Model\Preferences; use Appwrite\Utopia\Response\Model\Project; +use Appwrite\Utopia\Response\Model\Rule; +use Appwrite\Utopia\Response\Model\Deployment; +use Appwrite\Utopia\Response\Model\TemplateEmail; +use Appwrite\Utopia\Response\Model\Token; +use Appwrite\Utopia\Response\Model\Webhook; +use Appwrite\Utopia\Response\Model\Preferences; +use Appwrite\Utopia\Response\Model\HealthAntivirus; +use Appwrite\Utopia\Response\Model\HealthQueue; +use Appwrite\Utopia\Response\Model\HealthStatus; +use Appwrite\Utopia\Response\Model\HealthTime; +use Appwrite\Utopia\Response\Model\HealthVersion; +use Appwrite\Utopia\Response\Model\LocaleCode; +use Appwrite\Utopia\Response\Model\Mock; // Keep last use Appwrite\Utopia\Response\Model\Provider; use Appwrite\Utopia\Response\Model\Runtime; -use Appwrite\Utopia\Response\Model\Session; -use Appwrite\Utopia\Response\Model\Subscriber; use Appwrite\Utopia\Response\Model\Target; -use Appwrite\Utopia\Response\Model\Team; -use Appwrite\Utopia\Response\Model\TemplateEmail; use Appwrite\Utopia\Response\Model\TemplateSMS; -use Appwrite\Utopia\Response\Model\Token; // Keep last -use Appwrite\Utopia\Response\Model\Topic; use Appwrite\Utopia\Response\Model\UsageBuckets; use Appwrite\Utopia\Response\Model\UsageCollection; use Appwrite\Utopia\Response\Model\UsageDatabase; @@ -87,13 +93,10 @@ use Appwrite\Utopia\Response\Model\UsageFunctions; use Appwrite\Utopia\Response\Model\UsageProject; use Appwrite\Utopia\Response\Model\UsageStorage; use Appwrite\Utopia\Response\Model\UsageUsers; -use Appwrite\Utopia\Response\Model\User; use Appwrite\Utopia\Response\Model\Variable; -use Appwrite\Utopia\Response\Model\Webhook; -use Exception; -use Swoole\Http\Response as SwooleHTTPResponse; -use Utopia\Database\Document; -use Utopia\Swoole\Response as SwooleResponse; +use Appwrite\Utopia\Response\Model\Migration; +use Appwrite\Utopia\Response\Model\MigrationFirebaseProject; +use Appwrite\Utopia\Response\Model\MigrationReport; /** * @method int getStatusCode() @@ -103,263 +106,152 @@ class Response extends SwooleResponse { // General public const MODEL_NONE = 'none'; - public const MODEL_ANY = 'any'; - public const MODEL_LOG = 'log'; - public const MODEL_LOG_LIST = 'logList'; - public const MODEL_ERROR = 'error'; - public const MODEL_METRIC = 'metric'; - public const MODEL_METRIC_LIST = 'metricList'; - public const MODEL_ERROR_DEV = 'errorDev'; - public const MODEL_BASE_LIST = 'baseList'; - public const MODEL_USAGE_DATABASES = 'usageDatabases'; - public const MODEL_USAGE_DATABASE = 'usageDatabase'; - public const MODEL_USAGE_COLLECTION = 'usageCollection'; - public const MODEL_USAGE_USERS = 'usageUsers'; - public const MODEL_USAGE_BUCKETS = 'usageBuckets'; - public const MODEL_USAGE_STORAGE = 'usageStorage'; - public const MODEL_USAGE_FUNCTIONS = 'usageFunctions'; - public const MODEL_USAGE_FUNCTION = 'usageFunction'; - public const MODEL_USAGE_PROJECT = 'usageProject'; // Database public const MODEL_DATABASE = 'database'; - public const MODEL_DATABASE_LIST = 'databaseList'; - public const MODEL_COLLECTION = 'collection'; - public const MODEL_COLLECTION_LIST = 'collectionList'; - public const MODEL_INDEX = 'index'; - public const MODEL_INDEX_LIST = 'indexList'; - public const MODEL_DOCUMENT = 'document'; - public const MODEL_DOCUMENT_LIST = 'documentList'; // Database Attributes public const MODEL_ATTRIBUTE = 'attribute'; - public const MODEL_ATTRIBUTE_LIST = 'attributeList'; - public const MODEL_ATTRIBUTE_STRING = 'attributeString'; - public const MODEL_ATTRIBUTE_INTEGER = 'attributeInteger'; - public const MODEL_ATTRIBUTE_FLOAT = 'attributeFloat'; - public const MODEL_ATTRIBUTE_BOOLEAN = 'attributeBoolean'; - public const MODEL_ATTRIBUTE_EMAIL = 'attributeEmail'; - public const MODEL_ATTRIBUTE_ENUM = 'attributeEnum'; - public const MODEL_ATTRIBUTE_IP = 'attributeIp'; - public const MODEL_ATTRIBUTE_URL = 'attributeUrl'; - public const MODEL_ATTRIBUTE_DATETIME = 'attributeDatetime'; - public const MODEL_ATTRIBUTE_RELATIONSHIP = 'attributeRelationship'; // Users public const MODEL_ACCOUNT = 'account'; - public const MODEL_USER = 'user'; - public const MODEL_USER_LIST = 'userList'; - public const MODEL_SESSION = 'session'; - public const MODEL_SESSION_LIST = 'sessionList'; - public const MODEL_IDENTITY = 'identity'; - public const MODEL_IDENTITY_LIST = 'identityList'; - public const MODEL_TOKEN = 'token'; - public const MODEL_JWT = 'jwt'; - public const MODEL_PREFERENCES = 'preferences'; // Users password algos public const MODEL_ALGO_MD5 = 'algoMd5'; - public const MODEL_ALGO_SHA = 'algoSha'; - public const MODEL_ALGO_SCRYPT = 'algoScrypt'; - public const MODEL_ALGO_SCRYPT_MODIFIED = 'algoScryptModified'; - public const MODEL_ALGO_BCRYPT = 'algoBcrypt'; - public const MODEL_ALGO_ARGON2 = 'algoArgon2'; - public const MODEL_ALGO_PHPASS = 'algoPhpass'; // Storage public const MODEL_FILE = 'file'; - public const MODEL_FILE_LIST = 'fileList'; - public const MODEL_BUCKET = 'bucket'; - public const MODEL_BUCKET_LIST = 'bucketList'; // Locale public const MODEL_LOCALE = 'locale'; - public const MODEL_LOCALE_CODE = 'localeCode'; - public const MODEL_LOCALE_CODE_LIST = 'localeCodeList'; - public const MODEL_COUNTRY = 'country'; - public const MODEL_COUNTRY_LIST = 'countryList'; - public const MODEL_CONTINENT = 'continent'; - public const MODEL_CONTINENT_LIST = 'continentList'; - public const MODEL_CURRENCY = 'currency'; - public const MODEL_CURRENCY_LIST = 'currencyList'; - public const MODEL_LANGUAGE = 'language'; - public const MODEL_LANGUAGE_LIST = 'languageList'; - public const MODEL_PHONE = 'phone'; - public const MODEL_PHONE_LIST = 'phoneList'; // Messaging public const MODEL_PROVIDER = 'provider'; - public const MODEL_PROVIDER_LIST = 'providerList'; - public const MODEL_MESSAGE = 'message'; - public const MODEL_MESSAGE_LIST = 'messageList'; - public const MODEL_TOPIC = 'topic'; - public const MODEL_TOPIC_LIST = 'topicList'; - public const MODEL_SUBSCRIBER = 'subscriber'; - public const MODEL_SUBSCRIBER_LIST = 'subscriberList'; - public const MODEL_TARGET = 'target'; - public const MODEL_TARGET_LIST = 'targetList'; // Teams public const MODEL_TEAM = 'team'; - public const MODEL_TEAM_LIST = 'teamList'; - public const MODEL_MEMBERSHIP = 'membership'; - public const MODEL_MEMBERSHIP_LIST = 'membershipList'; // Functions public const MODEL_FUNCTION = 'function'; - public const MODEL_FUNCTION_LIST = 'functionList'; - public const MODEL_RUNTIME = 'runtime'; - public const MODEL_RUNTIME_LIST = 'runtimeList'; - public const MODEL_DEPLOYMENT = 'deployment'; - public const MODEL_DEPLOYMENT_LIST = 'deploymentList'; - public const MODEL_EXECUTION = 'execution'; - public const MODEL_EXECUTION_LIST = 'executionList'; - public const MODEL_BUILD = 'build'; - public const MODEL_BUILD_LIST = 'buildList'; // Not used anywhere yet - public const MODEL_FUNC_PERMISSIONS = 'funcPermissions'; // Migrations public const MODEL_MIGRATION = 'migration'; - public const MODEL_MIGRATION_LIST = 'migrationList'; - public const MODEL_MIGRATION_REPORT = 'migrationReport'; - public const MODEL_MIGRATION_FIREBASE_PROJECT = 'firebaseProject'; - public const MODEL_MIGRATION_FIREBASE_PROJECT_LIST = 'firebaseProjectList'; // Project public const MODEL_PROJECT = 'project'; - public const MODEL_PROJECT_LIST = 'projectList'; - public const MODEL_WEBHOOK = 'webhook'; - public const MODEL_WEBHOOK_LIST = 'webhookList'; - public const MODEL_KEY = 'key'; - public const MODEL_KEY_LIST = 'keyList'; - public const MODEL_AUTH_PROVIDER = 'authProvider'; - public const MODEL_AUTH_PROVIDER_LIST = 'authProviderList'; - public const MODEL_PLATFORM = 'platform'; - public const MODEL_PLATFORM_LIST = 'platformList'; - public const MODEL_DOMAIN = 'domain'; - public const MODEL_DOMAIN_LIST = 'domainList'; - public const MODEL_VARIABLE = 'variable'; - public const MODEL_VARIABLE_LIST = 'variableList'; - public const MODEL_SMS_TEMPLATE = 'smsTemplate'; - public const MODEL_EMAIL_TEMPLATE = 'emailTemplate'; // Health public const MODEL_HEALTH_STATUS = 'healthStatus'; - public const MODEL_HEALTH_VERSION = 'healthVersion'; - public const MODEL_HEALTH_QUEUE = 'healthQueue'; - public const MODEL_HEALTH_TIME = 'healthTime'; - public const MODEL_HEALTH_ANTIVIRUS = 'healthAntivirus'; - public const MODEL_HEALTH_STATUS_LIST = 'healthStatusList'; // Console @@ -367,9 +259,7 @@ class Response extends SwooleResponse // Deprecated public const MODEL_PERMISSIONS = 'permissions'; - public const MODEL_RULE = 'rule'; - public const MODEL_TASK = 'task'; // Tests (keep last) @@ -388,7 +278,7 @@ class Response extends SwooleResponse /** * Response constructor. * - * @param float $time + * @param float $time */ public function __construct(SwooleHTTPResponse $response) { @@ -531,7 +421,6 @@ class Response extends SwooleResponse * HTTP content types */ public const CONTENT_TYPE_YAML = 'application/x-yaml'; - public const CONTENT_TYPE_NULL = 'null'; /** @@ -554,15 +443,14 @@ class Response extends SwooleResponse /** * Get Model Object * - * @param string $key + * @param string $key * @return Model - * * @throws Exception */ public function getModel(string $key): Model { - if (! isset($this->models[$key])) { - throw new Exception('Undefined model: '.$key); + if (!isset($this->models[$key])) { + throw new Exception('Undefined model: ' . $key); } return $this->models[$key]; @@ -582,11 +470,10 @@ class Response extends SwooleResponse * Validate response objects and outputs * the response according to given format type * - * @param Document $document - * @param string $model + * @param Document $document + * @param string $model * * return void - * * @throws Exception */ public function dynamic(Document $document, string $model): void @@ -600,11 +487,11 @@ class Response extends SwooleResponse switch ($this->getContentType()) { case self::CONTENT_TYPE_JSON: - $this->json(! empty($output) ? $output : new \stdClass()); + $this->json(!empty($output) ? $output : new \stdClass()); break; case self::CONTENT_TYPE_YAML: - $this->yaml(! empty($output) ? $output : new \stdClass()); + $this->yaml(!empty($output) ? $output : new \stdClass()); break; case self::CONTENT_TYPE_NULL: @@ -614,7 +501,7 @@ class Response extends SwooleResponse if ($model === self::MODEL_NONE) { $this->noContent(); } else { - $this->json(! empty($output) ? $output : new \stdClass()); + $this->json(!empty($output) ? $output : new \stdClass()); } break; } @@ -623,19 +510,18 @@ class Response extends SwooleResponse /** * Generate valid response object from document data * - * @param Document $document - * @param string $model + * @param Document $document + * @param string $model * * return array * @return array - * * @throws Exception */ public function output(Document $document, string $model): array { - $data = new Document($document->getArrayCopy()); - $model = $this->getModel($model); - $output = []; + $data = new Document($document->getArrayCopy()); + $model = $this->getModel($model); + $output = []; $data = $model->filter($document); @@ -646,17 +532,17 @@ class Response extends SwooleResponse } foreach ($model->getRules() as $key => $rule) { - if (! $document->isSet($key) && $rule['required']) { // do not set attribute in response if not required + if (!$document->isSet($key) && $rule['required']) { // do not set attribute in response if not required if (\array_key_exists('default', $rule)) { $data->setAttribute($key, $rule['default']); } else { - throw new Exception('Model '.$model->getName().' is missing response key: '.$key); + throw new Exception('Model ' . $model->getName() . ' is missing response key: ' . $key); } } if ($rule['array']) { - if (! is_array($document[$key])) { - throw new Exception($key.' must be an array of type '.$rule['type']); + if (!is_array($document[$key])) { + throw new Exception($key . ' must be an array of type ' . $rule['type']); } foreach ($document[$key] as $index => $item) { @@ -666,7 +552,7 @@ class Response extends SwooleResponse $condition = false; foreach ($this->getModel($type)->conditions as $attribute => $val) { $condition = $item->getAttribute($attribute) === $val; - if (! $condition) { + if (!$condition) { break; } } @@ -679,8 +565,8 @@ class Response extends SwooleResponse $ruleType = $rule['type']; } - if (! array_key_exists($ruleType, $this->models)) { - throw new Exception('Missing model for rule: '.$ruleType); + if (!array_key_exists($ruleType, $this->models)) { + throw new Exception('Missing model for rule: ' . $ruleType); } $data[$key][$index] = $this->output($item, $ruleType); @@ -705,13 +591,14 @@ class Response extends SwooleResponse * * Generate HTTP response output including the response header (+cookies) and body and prints them. * - * @param string $body + * @param string $body + * * @return void */ public function file(string $body = ''): void { $this->payload = [ - 'payload' => $body, + 'payload' => $body ]; $this->send($body); @@ -725,14 +612,14 @@ class Response extends SwooleResponse * * @see https://en.wikipedia.org/wiki/YAML * - * @param array $data - * @return void + * @param array $data * + * @return void * @throws Exception */ public function yaml(array $data): void { - if (! extension_loaded('yaml')) { + if (!extension_loaded('yaml')) { throw new Exception('Missing yaml extension. Learn more at: https://www.php.net/manual/en/book.yaml.php'); } @@ -753,6 +640,7 @@ class Response extends SwooleResponse * Function to set a response filter * * @param $filter the response filter to set + * * @return void */ public static function setFilter(?Filter $filter) diff --git a/src/Appwrite/Utopia/Response/Filter.php b/src/Appwrite/Utopia/Response/Filter.php index 47cca955fe..9110abd07a 100644 --- a/src/Appwrite/Utopia/Response/Filter.php +++ b/src/Appwrite/Utopia/Response/Filter.php @@ -7,8 +7,9 @@ abstract class Filter /** * Parse the content to another format. * - * @param array $content - * @param string $model + * @param array $content + * @param string $model + * * @return array */ abstract public function parse(array $content, string $model): array; diff --git a/src/Appwrite/Utopia/Response/Filters/V11.php b/src/Appwrite/Utopia/Response/Filters/V11.php index 09f9fbfc06..8fa22f42b2 100644 --- a/src/Appwrite/Utopia/Response/Filters/V11.php +++ b/src/Appwrite/Utopia/Response/Filters/V11.php @@ -42,7 +42,7 @@ class V11 extends Filter $parsedResponse = $this->parseFunctionsList($content); break; - // Convert status from boolean to int + // Convert status from boolean to int case Response::MODEL_USER: $parsedResponse = $this->parseStatus($content); break; @@ -50,7 +50,7 @@ class V11 extends Filter $parsedResponse = $this->parseUserList($content); break; - // Convert all Health responses back to original + // Convert all Health responses back to original case Response::MODEL_HEALTH_STATUS: $parsedResponse = $this->parseHealthStatus($content); break; @@ -67,7 +67,7 @@ class V11 extends Filter $parsedResponse = $this->parseHealthAntivirus($content); break; - // Complex filters + // Complex filters case Response::MODEL_COLLECTION: $parsedResponse = $this->parseCollection($content); break; @@ -101,7 +101,6 @@ class V11 extends Filter $parsedResponse[] = $this->parsePermissions($document); } $content['documents'] = $parsedResponse; - return $content; } @@ -113,7 +112,6 @@ class V11 extends Filter $parsedResponse[] = $this->parsePermissions($file); } $content['files'] = $parsedResponse; - return $content; } @@ -125,7 +123,6 @@ class V11 extends Filter $parsedResponse[] = $this->parseExecutionPermissions($execution); } $content['executions'] = $parsedResponse; - return $content; } @@ -137,7 +134,6 @@ class V11 extends Filter $parsedResponse[] = $this->parseFunctionPermissions($function); } $content['functions'] = $parsedResponse; - return $content; } @@ -149,7 +145,6 @@ class V11 extends Filter $parsedResponse[] = $this->parseStatus($user); } $content['users'] = $parsedResponse; - return $content; } @@ -164,7 +159,6 @@ class V11 extends Filter $parsedResponse = $this->addDate($content, 'dateCreated'); $parsedResponse = $this->addDate($content, 'dateUpdated'); $parsedResponse = $this->parseAttributes($content); - return $parsedResponse; } @@ -176,7 +170,6 @@ class V11 extends Filter $parsedResponse[] = $this->parseCollection($collection); } $content['collections'] = $parsedResponse; - return $content; } @@ -188,7 +181,6 @@ class V11 extends Filter $parsedResponse = $this->removeRule($content, 'userName'); $parsedResponse = $this->removeRule($content, 'mode'); $parsedResponse = $this->removeRule($content, 'sum'); - return $parsedResponse; } @@ -200,7 +192,6 @@ class V11 extends Filter $parsedResponse[] = $this->parseLog($log); } $content['logs'] = $parsedResponse; - return $content; } @@ -212,7 +203,6 @@ class V11 extends Filter $parsedResponse = $this->parseOAuths($content); $parsedResponse = $this->parseAuthsStatus($content); $parsedResponse = $this->removeServicesStatus($content); - return $parsedResponse; } @@ -224,7 +214,6 @@ class V11 extends Filter $parsedResponse[] = $this->parseProject($project); } $content['projects'] = $parsedResponse; - return $content; } @@ -259,6 +248,7 @@ class V11 extends Filter return $content; } + protected function parseHealthQueue(array $content) { // Did not change @@ -313,15 +303,15 @@ class V11 extends Filter protected function parseOAuths(array $content) { - $regexPattern = '/provider([a-zA-Z0-9]+)(Appid|Secret)/'; + $regexPattern = "/provider([a-zA-Z0-9]+)(Appid|Secret)/"; foreach ($content as $key => $value) { \preg_match_all($regexPattern, $key, $regexGroups); if (\count($regexGroups[1]) > 0 && \count($regexGroups[2]) > 0) { $providerName = $regexGroups[1][0]; $valueKey = $regexGroups[2][0]; - $content['usersOauth2'.$providerName.$valueKey] = $value; - unset($content['provider'.$providerName.$valueKey]); + $content['usersOauth2' . $providerName . $valueKey] = $value; + unset($content['provider' . $providerName . $valueKey]); } } @@ -330,7 +320,7 @@ class V11 extends Filter protected function parseAuthsStatus(array $content) { - $regexPattern = '/auth([a-zA-Z0-9]+)/'; + $regexPattern = "/auth([a-zA-Z0-9]+)/"; foreach ($content as $key => $value) { \preg_match_all($regexPattern, $key, $regexGroups); @@ -338,7 +328,7 @@ class V11 extends Filter $providerName = $regexGroups[1][0]; $content[$providerName] = $value; - unset($content['auth'.$providerName]); + unset($content['auth' . $providerName]); } } @@ -387,16 +377,15 @@ class V11 extends Filter protected function parsePermissions(array $content) { - $content['$permissions'] = ['read' => $content['$read'], 'write' => $content['$write']]; + $content['$permissions'] = [ 'read' => $content['$read'], 'write' => $content['$write'] ]; unset($content['$read']); unset($content['$write']); - return $content; } protected function parseFunctionPermissions(array $content) { - $content['$permissions'] = ['execute' => $content['execute']]; + $content['$permissions'] = [ 'execute' => $content['execute'] ]; unset($content['execute']); return $content; @@ -404,7 +393,7 @@ class V11 extends Filter protected function parseExecutionPermissions(array $content) { - $content['$permissions'] = ['read' => $content['$read']]; + $content['$permissions'] = [ 'read' => $content['$read'] ]; unset($content['$read']); return $content; diff --git a/src/Appwrite/Utopia/Response/Filters/V12.php b/src/Appwrite/Utopia/Response/Filters/V12.php index 795135bf43..79d22ad044 100644 --- a/src/Appwrite/Utopia/Response/Filters/V12.php +++ b/src/Appwrite/Utopia/Response/Filters/V12.php @@ -99,7 +99,6 @@ class V12 extends Filter protected function parseError(array $content) { unset($content['type']); - return $content; } @@ -125,7 +124,6 @@ class V12 extends Filter $content['sessions'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); - return $content; } @@ -148,7 +146,6 @@ class V12 extends Filter $content['files'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); - return $content; } @@ -156,7 +153,6 @@ class V12 extends Filter { $content['tag'] = $content['deployment']; unset($content['deployment']); - return $content; } @@ -170,7 +166,6 @@ class V12 extends Filter $content['functions'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); - return $content; } @@ -178,7 +173,6 @@ class V12 extends Filter { $content['functionId'] = $content['resourceId']; $content['command'] = $content['entrypoint']; - return $content; } @@ -192,14 +186,12 @@ class V12 extends Filter $content['deployments'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); - return $content; } protected function parseUsageBuckets(array $content) { unset($content['filesStorage']); - return $content; } @@ -245,7 +237,6 @@ class V12 extends Filter $content['executions'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); - return $content; } @@ -253,7 +244,6 @@ class V12 extends Filter { $content['sum'] = $content['total']; unset($content['total']); - return $content; } @@ -267,7 +257,6 @@ class V12 extends Filter $content['teams'] = $parsedResponse; $content['sum'] = $content['total']; unset($content['total']); - return $content; } @@ -275,7 +264,6 @@ class V12 extends Filter { $content['sum'] = $content['total']; unset($content['total']); - return $content; } } diff --git a/src/Appwrite/Utopia/Response/Filters/V13.php b/src/Appwrite/Utopia/Response/Filters/V13.php index 2c613280ac..d48473593e 100644 --- a/src/Appwrite/Utopia/Response/Filters/V13.php +++ b/src/Appwrite/Utopia/Response/Filters/V13.php @@ -55,7 +55,6 @@ class V13 extends Filter $parsedResponse[] = $this->parseExecution($document); } $content['executions'] = $parsedResponse; - return $content; } @@ -75,7 +74,6 @@ class V13 extends Filter $parsedResponse[] = $this->parseProject($document); } $content['projects'] = $parsedResponse; - return $content; } @@ -100,7 +98,6 @@ class V13 extends Filter $parsedResponse[] = $this->parseMembership($document); } $content['memberships'] = $parsedResponse; - return $content; } } diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index fadf426f1d..232feec201 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -210,13 +210,11 @@ class V15 extends Filter if (array_key_exists($attribute, $content)) { if (empty($content[$attribute])) { $content[$attribute] = 0; - continue; } $content[$attribute] = strtotime($content[$attribute]); } } - return $content; } @@ -227,20 +225,18 @@ class V15 extends Filter unset($content['hashOptions']); $content = $this->parseDatetimeAttributes($content, ['registration', 'passwordUpdate', '$createdAt', '$updatedAt']); - return $content; } protected function parseMetric(array $content) { $content = $this->parseDatetimeAttributes($content, ['date']); - return $content; } protected function parsePermissions(array $content) { - if (! isset($content['$permissions'])) { + if (!isset($content['$permissions'])) { return $content; } @@ -252,10 +248,10 @@ class V15 extends Filter $permission = Permission::parse($permission); $permission_value = $permission->getRole(); if ($permission->getIdentifier()) { - $permission_value .= ':'.$permission->getIdentifier(); + $permission_value .= ':' . $permission->getIdentifier(); } if ($permission->getDimension()) { - $permission_value .= '/'.$permission->getDimension(); + $permission_value .= '/' . $permission->getDimension(); } // Old type permissions meant that 'write' is equivalent to 'create', 'update' and 'delete' @@ -309,7 +305,6 @@ class V15 extends Filter unset($content['documentSecurity']); $content = $this->parsePermissions($content); $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); - return $content; } @@ -317,7 +312,6 @@ class V15 extends Filter { $content = $this->parsePermissions($content); $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); - return $content; } @@ -331,7 +325,6 @@ class V15 extends Filter unset($content['$databaseId']); $content = $this->parsePermissionsCreatedAtUpdatedAt($content); - return $content; } @@ -361,7 +354,6 @@ class V15 extends Filter private function parseCreatedAtUpdatedAt($content) { $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); - return $content; } @@ -394,28 +386,24 @@ class V15 extends Filter private function parseKey($content) { $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'expire']); - return $content; } private function parseLog($content) { $content = $this->parseDatetimeAttributes($content, ['time']); - return $content; } private function parseMembership($content) { $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'invited', 'joined']); - return $content; } private function parseSession($content) { $content = $this->parseDatetimeAttributes($content, ['$createdAt', 'expire', 'providerAccessTokenExpiry']); - return $content; } diff --git a/src/Appwrite/Utopia/Response/Model.php b/src/Appwrite/Utopia/Response/Model.php index 4aa4189248..8a0bb78cba 100644 --- a/src/Appwrite/Utopia/Response/Model.php +++ b/src/Appwrite/Utopia/Response/Model.php @@ -7,19 +7,12 @@ use Utopia\Database\Document; abstract class Model { public const TYPE_STRING = 'string'; - public const TYPE_INTEGER = 'integer'; - public const TYPE_FLOAT = 'double'; - public const TYPE_BOOLEAN = 'boolean'; - public const TYPE_JSON = 'json'; - public const TYPE_DATETIME = 'datetime'; - public const TYPE_DATETIME_EXAMPLE = '2020-10-15T06:38:00.000+00:00'; - public const TYPE_RELATIONSHIP = 'relationship'; /** @@ -47,6 +40,7 @@ abstract class Model */ public array $conditions = []; + /** * Filter Document Structure * @@ -85,8 +79,8 @@ abstract class Model * Add a New Rule * If rule is an array of documents with varying models * - * @param string $key - * @param array $options + * @param string $key + * @param array $options * @return Model */ protected function addRule(string $key, array $options): self @@ -95,7 +89,7 @@ abstract class Model 'required' => true, 'array' => false, 'description' => '', - 'example' => '', + 'example' => '' ], $options); return $this; @@ -105,7 +99,7 @@ abstract class Model * Delete an existing Rule * If rule exists, it will be removed * - * @param string $key + * @param string $key * @return Model */ protected function removeRule(string $key): self diff --git a/src/Appwrite/Utopia/Response/Model/AlgoArgon2.php b/src/Appwrite/Utopia/Response/Model/AlgoArgon2.php index ff2b0f94e0..3e162bb905 100644 --- a/src/Appwrite/Utopia/Response/Model/AlgoArgon2.php +++ b/src/Appwrite/Utopia/Response/Model/AlgoArgon2.php @@ -34,7 +34,8 @@ class AlgoArgon2 extends Model 'description' => 'Number of threads used to compute hash.', 'default' => '', 'example' => 3, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/AlgoScrypt.php b/src/Appwrite/Utopia/Response/Model/AlgoScrypt.php index 066f976433..4dda297d71 100644 --- a/src/Appwrite/Utopia/Response/Model/AlgoScrypt.php +++ b/src/Appwrite/Utopia/Response/Model/AlgoScrypt.php @@ -39,7 +39,8 @@ class AlgoScrypt extends Model 'description' => 'Length used to compute hash.', 'default' => 64, 'example' => 64, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/AlgoScryptModified.php b/src/Appwrite/Utopia/Response/Model/AlgoScryptModified.php index 73104eba7a..40b9df1dad 100644 --- a/src/Appwrite/Utopia/Response/Model/AlgoScryptModified.php +++ b/src/Appwrite/Utopia/Response/Model/AlgoScryptModified.php @@ -33,7 +33,8 @@ class AlgoScryptModified extends Model 'description' => 'Key used to compute hash.', 'default' => '', 'example' => 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ==', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Attribute.php b/src/Appwrite/Utopia/Response/Model/Attribute.php index c7a014bd32..9f9ceca317 100644 --- a/src/Appwrite/Utopia/Response/Model/Attribute.php +++ b/src/Appwrite/Utopia/Response/Model/Attribute.php @@ -46,7 +46,8 @@ class Attribute extends Model 'default' => false, 'required' => false, 'example' => false, - ]); + ]) + ; } public array $conditions = []; diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php index e96140d0b3..05846817ca 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -28,12 +28,13 @@ class AttributeBoolean extends Attribute 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', 'default' => null, 'required' => false, - 'example' => false, - ]); + 'example' => false + ]) + ; } public array $conditions = [ - 'type' => self::TYPE_BOOLEAN, + 'type' => self::TYPE_BOOLEAN ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php index ccad8e7627..4651aebd06 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php @@ -37,11 +37,12 @@ class AttributeDatetime extends Attribute 'example' => self::TYPE_DATETIME_EXAMPLE, 'array' => false, 'required' => false, - ]); + ]) + ; } public array $conditions = [ - 'type' => self::TYPE_DATETIME, + 'type' => self::TYPE_DATETIME ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php index ffcdbc6eb1..078087dd4b 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -35,12 +35,13 @@ class AttributeEmail extends Attribute 'default' => null, 'required' => false, 'example' => 'default@example.com', - ]); + ]) + ; } public array $conditions = [ 'type' => self::TYPE_STRING, - 'format' => \APP_DATABASE_ATTRIBUTE_EMAIL, + 'format' => \APP_DATABASE_ATTRIBUTE_EMAIL ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEnum.php b/src/Appwrite/Utopia/Response/Model/AttributeEnum.php index 0549c3cbe6..992b62ee3a 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEnum.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEnum.php @@ -42,12 +42,13 @@ class AttributeEnum extends Attribute 'default' => null, 'required' => false, 'example' => 'element', - ]); + ]) + ; } public array $conditions = [ 'type' => self::TYPE_STRING, - 'format' => \APP_DATABASE_ATTRIBUTE_ENUM, + 'format' => \APP_DATABASE_ATTRIBUTE_ENUM ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index 28bd88e749..266b89c330 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -43,7 +43,8 @@ class AttributeFloat extends Attribute 'default' => null, 'required' => false, 'example' => 2.5, - ]); + ]) + ; } public array $conditions = [ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php index 2e746d735a..cfa309317a 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeIP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -35,12 +35,13 @@ class AttributeIP extends Attribute 'default' => null, 'required' => false, 'example' => '192.0.2.0', - ]); + ]) + ; } public array $conditions = [ 'type' => self::TYPE_STRING, - 'format' => \APP_DATABASE_ATTRIBUTE_IP, + 'format' => \APP_DATABASE_ATTRIBUTE_IP ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index f672592553..fddfe57445 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -43,7 +43,8 @@ class AttributeInteger extends Attribute 'default' => null, 'required' => false, 'example' => 10, - ]); + ]) + ; } public array $conditions = [ @@ -52,7 +53,6 @@ class AttributeInteger extends Attribute /** * Get Name * - * * @return string */ public function getName(): string diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php index b093dd7fe9..8b04475a14 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeList.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -27,12 +27,13 @@ class AttributeList extends Model Response::MODEL_ATTRIBUTE_IP, Response::MODEL_ATTRIBUTE_DATETIME, Response::MODEL_ATTRIBUTE_RELATIONSHIP, - Response::MODEL_ATTRIBUTE_STRING, // needs to be last, since its condition would dominate any other string attribute + Response::MODEL_ATTRIBUTE_STRING // needs to be last, since its condition would dominate any other string attribute ], 'description' => 'List of attributes.', 'default' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php b/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php index 73b6a566f2..d88fbd1530 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php @@ -47,7 +47,8 @@ class AttributeRelationship extends Attribute 'description' => 'Whether this is the parent or child side of the relationship', 'default' => '', 'example' => 'parent|child', - ]); + ]) + ; } public array $conditions = [ @@ -82,7 +83,7 @@ class AttributeRelationship extends Attribute public function filter(Document $document): Document { $options = $document->getAttribute('options'); - if (! \is_null($options)) { + if (!\is_null($options)) { $document->setAttribute('relatedCollection', $options['relatedCollection']); $document->setAttribute('relationType', $options['relationType']); $document->setAttribute('twoWay', $options['twoWay']); @@ -90,7 +91,6 @@ class AttributeRelationship extends Attribute $document->setAttribute('side', $options['side']); $document->setAttribute('onDelete', $options['onDelete']); } - return $document; } } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index eb72d705e6..12bb42009d 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -23,7 +23,8 @@ class AttributeString extends Attribute 'default' => null, 'required' => false, 'example' => 'default', - ]); + ]) + ; } public array $conditions = [ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php index 78bd9c24d2..633d5b49d7 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeURL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -35,12 +35,13 @@ class AttributeURL extends Attribute 'default' => null, 'required' => false, 'example' => 'http://example.com', - ]); + ]) + ; } public array $conditions = [ 'type' => self::TYPE_STRING, - 'format' => \APP_DATABASE_ATTRIBUTE_URL, + 'format' => \APP_DATABASE_ATTRIBUTE_URL ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/AuthProvider.php b/src/Appwrite/Utopia/Response/Model/AuthProvider.php index 840a2aa661..0171a3c152 100644 --- a/src/Appwrite/Utopia/Response/Model/AuthProvider.php +++ b/src/Appwrite/Utopia/Response/Model/AuthProvider.php @@ -43,7 +43,8 @@ class AuthProvider extends Model 'type' => self::TYPE_BOOLEAN, 'description' => 'Auth Provider is active and can be used to create session.', 'example' => '', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/BaseList.php b/src/Appwrite/Utopia/Response/Model/BaseList.php index cb0010a4e9..0c2cc072f3 100644 --- a/src/Appwrite/Utopia/Response/Model/BaseList.php +++ b/src/Appwrite/Utopia/Response/Model/BaseList.php @@ -17,12 +17,12 @@ class BaseList extends Model protected string $type = ''; /** - * @param string $name - * @param string $type - * @param string $key - * @param string $model - * @param bool $paging - * @param bool $public + * @param string $name + * @param string $type + * @param string $key + * @param string $model + * @param bool $paging + * @param bool $public */ public function __construct(string $name, string $type, string $key, string $model, bool $paging = true, bool $public = true) { @@ -34,13 +34,13 @@ class BaseList extends Model $namesWithCap = [ 'documents', 'collections', 'users', 'files', 'buckets', 'functions', 'deployments', 'executions', 'projects', 'webhooks', 'keys', - 'platforms', 'domains', 'memberships', 'teams', 'targets', + 'platforms', 'domains', 'memberships', 'teams', 'targets' ]; if (\in_array($name, $namesWithCap)) { - $description = 'Total number of '.$key.' documents that matched your query used as reference for offset pagination. When the `total` number of '.$key.' documents available is greater than 5000, total returned will be capped at 5000, and cursor pagination should be used. Read more about [pagination](https://appwrite.io/docs/pagination).'; + $description = 'Total number of ' . $key . ' documents that matched your query used as reference for offset pagination. When the `total` number of ' . $key . ' documents available is greater than 5000, total returned will be capped at 5000, and cursor pagination should be used. Read more about [pagination](https://appwrite.io/docs/pagination).'; } else { - $description = 'Total number of '.$key.' documents that matched your query.'; + $description = 'Total number of ' . $key . ' documents that matched your query.'; } $this->addRule('total', [ @@ -52,7 +52,7 @@ class BaseList extends Model } $this->addRule($key, [ 'type' => $model, - 'description' => 'List of '.$key.'.', + 'description' => 'List of ' . $key . '.', 'default' => [], 'array' => true, ]); diff --git a/src/Appwrite/Utopia/Response/Model/Bucket.php b/src/Appwrite/Utopia/Response/Model/Bucket.php index 16f1b02f24..0276c1d1f9 100644 --- a/src/Appwrite/Utopia/Response/Model/Bucket.php +++ b/src/Appwrite/Utopia/Response/Model/Bucket.php @@ -64,14 +64,14 @@ class Bucket extends Model 'description' => 'Allowed file extensions.', 'default' => [], 'example' => ['jpg', 'png'], - 'array' => true, + 'array' => true ]) ->addRule('compression', [ 'type' => self::TYPE_STRING, - 'description' => 'Compression algorithm choosen for compression. Will be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd).', + 'description' => 'Compression algorithm choosen for compression. Will be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd).', 'default' => '', 'example' => 'gzip', - 'array' => false, + 'array' => false ]) ->addRule('encryption', [ 'type' => self::TYPE_BOOLEAN, @@ -84,7 +84,8 @@ class Bucket extends Model 'description' => 'Virus scanning is enabled.', 'default' => true, 'example' => false, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Build.php b/src/Appwrite/Utopia/Response/Model/Build.php index f8709bd027..b76f0ee083 100644 --- a/src/Appwrite/Utopia/Response/Model/Build.php +++ b/src/Appwrite/Utopia/Response/Model/Build.php @@ -62,7 +62,8 @@ class Build extends Model 'description' => 'The build duration in seconds.', 'default' => 0, 'example' => 0, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Collection.php b/src/Appwrite/Utopia/Response/Model/Collection.php index 2c876f2809..ae3e283378 100644 --- a/src/Appwrite/Utopia/Response/Model/Collection.php +++ b/src/Appwrite/Utopia/Response/Model/Collection.php @@ -33,7 +33,7 @@ class Collection extends Model 'description' => 'Collection permissions. [Learn more about permissions](/docs/permissions).', 'default' => '', 'example' => ['read("any")'], - 'array' => true, + 'array' => true ]) ->addRule('databaseId', [ 'type' => self::TYPE_STRING, @@ -82,8 +82,9 @@ class Collection extends Model 'description' => 'Collection indexes.', 'default' => [], 'example' => new \stdClass(), - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Continent.php b/src/Appwrite/Utopia/Response/Model/Continent.php index 4fd5c9e095..5291424a4a 100644 --- a/src/Appwrite/Utopia/Response/Model/Continent.php +++ b/src/Appwrite/Utopia/Response/Model/Continent.php @@ -21,7 +21,8 @@ class Continent extends Model 'description' => 'Continent two letter code.', 'default' => '', 'example' => 'EU', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Country.php b/src/Appwrite/Utopia/Response/Model/Country.php index 866460f929..64590a54d4 100644 --- a/src/Appwrite/Utopia/Response/Model/Country.php +++ b/src/Appwrite/Utopia/Response/Model/Country.php @@ -21,7 +21,8 @@ class Country extends Model 'description' => 'Country two-character ISO 3166-1 alpha code.', 'default' => '', 'example' => 'US', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Currency.php b/src/Appwrite/Utopia/Response/Model/Currency.php index e938f8a454..883ef486d8 100644 --- a/src/Appwrite/Utopia/Response/Model/Currency.php +++ b/src/Appwrite/Utopia/Response/Model/Currency.php @@ -51,7 +51,8 @@ class Currency extends Model 'description' => 'Currency plural name', 'default' => '', 'example' => 'US dollars', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Database.php b/src/Appwrite/Utopia/Response/Model/Database.php index 14e89419c3..bd9ae4625c 100644 --- a/src/Appwrite/Utopia/Response/Model/Database.php +++ b/src/Appwrite/Utopia/Response/Model/Database.php @@ -39,7 +39,8 @@ class Database extends Model 'description' => 'Database enabled.', 'default' => true, 'example' => false, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Deployment.php b/src/Appwrite/Utopia/Response/Model/Deployment.php index be571810b8..8862d6a14e 100644 --- a/src/Appwrite/Utopia/Response/Model/Deployment.php +++ b/src/Appwrite/Utopia/Response/Model/Deployment.php @@ -87,7 +87,8 @@ class Deployment extends Model 'description' => 'The current build time in seconds.', 'default' => 0, 'example' => 128, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Domain.php b/src/Appwrite/Utopia/Response/Model/Domain.php index 9218a6fdf9..135bb52f90 100644 --- a/src/Appwrite/Utopia/Response/Model/Domain.php +++ b/src/Appwrite/Utopia/Response/Model/Domain.php @@ -62,7 +62,8 @@ class Domain extends Model 'description' => 'Certificate ID.', 'default' => '', 'example' => '6ejea5c13377e', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Error.php b/src/Appwrite/Utopia/Response/Model/Error.php index 6fc182214d..99cf3cbce2 100644 --- a/src/Appwrite/Utopia/Response/Model/Error.php +++ b/src/Appwrite/Utopia/Response/Model/Error.php @@ -33,7 +33,8 @@ class Error extends Model 'description' => 'Server version number.', 'default' => '', 'example' => '1.0', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/ErrorDev.php b/src/Appwrite/Utopia/Response/Model/ErrorDev.php index 4911da6bc7..9319397c77 100644 --- a/src/Appwrite/Utopia/Response/Model/ErrorDev.php +++ b/src/Appwrite/Utopia/Response/Model/ErrorDev.php @@ -34,7 +34,8 @@ class ErrorDev extends Error 'default' => [], 'example' => '', 'array' => true, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Execution.php b/src/Appwrite/Utopia/Response/Model/Execution.php index d4bd212e93..8672a91598 100644 --- a/src/Appwrite/Utopia/Response/Model/Execution.php +++ b/src/Appwrite/Utopia/Response/Model/Execution.php @@ -83,7 +83,8 @@ class Execution extends Model 'description' => 'The script execution duration in seconds.', 'default' => 0, 'example' => 0.400, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/File.php b/src/Appwrite/Utopia/Response/Model/File.php index a9a89d2a41..53469f46b3 100644 --- a/src/Appwrite/Utopia/Response/Model/File.php +++ b/src/Appwrite/Utopia/Response/Model/File.php @@ -76,7 +76,8 @@ class File extends Model 'description' => 'Total number of chunks uploaded', 'default' => 0, 'example' => 17890, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Func.php b/src/Appwrite/Utopia/Response/Model/Func.php index b3424b5e7c..c4044c0f2e 100644 --- a/src/Appwrite/Utopia/Response/Model/Func.php +++ b/src/Appwrite/Utopia/Response/Model/Func.php @@ -4,6 +4,8 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; +use stdClass; +use Utopia\Database\Document; class Func extends Model { @@ -64,7 +66,7 @@ class Func extends Model 'description' => 'Function variables.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('events', [ 'type' => self::TYPE_STRING, @@ -84,7 +86,8 @@ class Func extends Model 'description' => 'Function execution timeout in seconds.', 'default' => 15, 'example' => 15, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthAntivirus.php b/src/Appwrite/Utopia/Response/Model/HealthAntivirus.php index 97d608ff09..7a74195371 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthAntivirus.php +++ b/src/Appwrite/Utopia/Response/Model/HealthAntivirus.php @@ -21,7 +21,8 @@ class HealthAntivirus extends Model 'description' => 'Antivirus status. Possible values can are: `disabled`, `offline`, `online`', 'default' => '', 'example' => 'online', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthQueue.php b/src/Appwrite/Utopia/Response/Model/HealthQueue.php index 5990a4c5d3..da7c49a43f 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthQueue.php +++ b/src/Appwrite/Utopia/Response/Model/HealthQueue.php @@ -15,7 +15,8 @@ class HealthQueue extends Model 'description' => 'Amount of actions in the queue.', 'default' => 0, 'example' => 8, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthStatus.php b/src/Appwrite/Utopia/Response/Model/HealthStatus.php index 2bd8706763..ba340107ac 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthStatus.php +++ b/src/Appwrite/Utopia/Response/Model/HealthStatus.php @@ -27,7 +27,8 @@ class HealthStatus extends Model 'description' => 'Service status. Possible values can are: `pass`, `fail`', 'default' => '', 'example' => 'pass', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthTime.php b/src/Appwrite/Utopia/Response/Model/HealthTime.php index 0484b8ec33..042d073ce5 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthTime.php +++ b/src/Appwrite/Utopia/Response/Model/HealthTime.php @@ -27,7 +27,8 @@ class HealthTime extends Model 'description' => 'Difference of unix remote and local timestamps in milliseconds.', 'default' => 0, 'example' => 93, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/HealthVersion.php b/src/Appwrite/Utopia/Response/Model/HealthVersion.php index 6fab34576d..15a73c0e75 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthVersion.php +++ b/src/Appwrite/Utopia/Response/Model/HealthVersion.php @@ -15,7 +15,8 @@ class HealthVersion extends Model 'description' => 'Version of the Appwrite instance.', 'default' => '', 'example' => '0.11.0', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Identity.php b/src/Appwrite/Utopia/Response/Model/Identity.php index c23948acbf..ff7f57a3e6 100644 --- a/src/Appwrite/Utopia/Response/Model/Identity.php +++ b/src/Appwrite/Utopia/Response/Model/Identity.php @@ -69,7 +69,8 @@ class Identity extends Model 'description' => 'Identity Provider Refresh Token.', 'default' => '', 'example' => 'MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Index.php b/src/Appwrite/Utopia/Response/Model/Index.php index dcda9d11c6..3d3d1a3b52 100644 --- a/src/Appwrite/Utopia/Response/Model/Index.php +++ b/src/Appwrite/Utopia/Response/Model/Index.php @@ -48,7 +48,8 @@ class Index extends Model 'example' => [], 'array' => true, 'required' => false, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/JWT.php b/src/Appwrite/Utopia/Response/Model/JWT.php index debb81b28e..a2563a2ad8 100644 --- a/src/Appwrite/Utopia/Response/Model/JWT.php +++ b/src/Appwrite/Utopia/Response/Model/JWT.php @@ -14,7 +14,8 @@ class JWT extends Model 'type' => self::TYPE_STRING, 'description' => 'JWT encoded string.', 'example' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Key.php b/src/Appwrite/Utopia/Response/Model/Key.php index 1dba4e771b..1179a73d62 100644 --- a/src/Appwrite/Utopia/Response/Model/Key.php +++ b/src/Appwrite/Utopia/Response/Model/Key.php @@ -60,17 +60,18 @@ class Key extends Model ]) ->addRule('accessedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after '.APP_KEY_ACCCESS / 60 / 60 .' hours.', + 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_KEY_ACCCESS / 60 / 60 . ' hours.', 'default' => '', - 'example' => self::TYPE_DATETIME_EXAMPLE, + 'example' => self::TYPE_DATETIME_EXAMPLE ]) ->addRule('sdks', [ 'type' => self::TYPE_STRING, 'description' => 'List of SDK user agents that used this key.', 'default' => null, 'example' => 'appwrite:flutter', - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Language.php b/src/Appwrite/Utopia/Response/Model/Language.php index c3f1072c82..64f99a006f 100644 --- a/src/Appwrite/Utopia/Response/Model/Language.php +++ b/src/Appwrite/Utopia/Response/Model/Language.php @@ -27,7 +27,8 @@ class Language extends Model 'description' => 'Language native name.', 'default' => '', 'example' => 'Italiano', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Locale.php b/src/Appwrite/Utopia/Response/Model/Locale.php index 61f371e7ac..fdfa363acd 100644 --- a/src/Appwrite/Utopia/Response/Model/Locale.php +++ b/src/Appwrite/Utopia/Response/Model/Locale.php @@ -51,7 +51,8 @@ class Locale extends Model 'description' => 'Currency code in [ISO 4217-1](http://en.wikipedia.org/wiki/ISO_4217) three-character format', 'default' => '', 'example' => 'USD', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/LocaleCode.php b/src/Appwrite/Utopia/Response/Model/LocaleCode.php index d629c9a1a5..e73ceff6a5 100644 --- a/src/Appwrite/Utopia/Response/Model/LocaleCode.php +++ b/src/Appwrite/Utopia/Response/Model/LocaleCode.php @@ -21,7 +21,8 @@ class LocaleCode extends Model 'description' => 'Locale name', 'default' => '', 'example' => 'US', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Log.php b/src/Appwrite/Utopia/Response/Model/Log.php index 7177cad078..bc2c923494 100644 --- a/src/Appwrite/Utopia/Response/Model/Log.php +++ b/src/Appwrite/Utopia/Response/Model/Log.php @@ -135,7 +135,8 @@ class Log extends Model 'description' => 'Country name.', 'default' => '', 'example' => 'United States', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Membership.php b/src/Appwrite/Utopia/Response/Model/Membership.php index 2364ca5ec8..c134142185 100644 --- a/src/Appwrite/Utopia/Response/Model/Membership.php +++ b/src/Appwrite/Utopia/Response/Model/Membership.php @@ -82,7 +82,8 @@ class Membership extends Model 'default' => [], 'example' => ['owner'], 'array' => true, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Metric.php b/src/Appwrite/Utopia/Response/Model/Metric.php index 6b52f97e21..16cf7f7df2 100644 --- a/src/Appwrite/Utopia/Response/Model/Metric.php +++ b/src/Appwrite/Utopia/Response/Model/Metric.php @@ -20,7 +20,7 @@ class Metric extends Model 'type' => self::TYPE_DATETIME, 'description' => 'The date at which this metric was aggregated in ISO 8601 format.', 'default' => '', - 'example' => self::TYPE_DATETIME_EXAMPLE, + 'example' => self::TYPE_DATETIME_EXAMPLE ]); } diff --git a/src/Appwrite/Utopia/Response/Model/Migration.php b/src/Appwrite/Utopia/Response/Model/Migration.php index 33bccd23d2..78e8658032 100644 --- a/src/Appwrite/Utopia/Response/Model/Migration.php +++ b/src/Appwrite/Utopia/Response/Model/Migration.php @@ -51,7 +51,7 @@ class Migration extends Model 'description' => 'Resources to migration.', 'default' => [], 'example' => ['user'], - 'array' => true, + 'array' => true ]) ->addRule('statusCounters', [ 'type' => self::TYPE_JSON, @@ -70,7 +70,8 @@ class Migration extends Model 'description' => 'All errors that occurred during the migration process.', 'default' => [], 'example' => [], - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Mock.php b/src/Appwrite/Utopia/Response/Model/Mock.php index 7332e589f1..afdae66084 100644 --- a/src/Appwrite/Utopia/Response/Model/Mock.php +++ b/src/Appwrite/Utopia/Response/Model/Mock.php @@ -15,7 +15,8 @@ class Mock extends Model 'description' => 'Result message.', 'default' => '', 'example' => 'Success', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Phone.php b/src/Appwrite/Utopia/Response/Model/Phone.php index d732d0dc2e..226955919b 100644 --- a/src/Appwrite/Utopia/Response/Model/Phone.php +++ b/src/Appwrite/Utopia/Response/Model/Phone.php @@ -27,7 +27,8 @@ class Phone extends Model 'description' => 'Country name.', 'default' => '', 'example' => 'United States', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Platform.php b/src/Appwrite/Utopia/Response/Model/Platform.php index a25d819947..4b8ffb1486 100644 --- a/src/Appwrite/Utopia/Response/Model/Platform.php +++ b/src/Appwrite/Utopia/Response/Model/Platform.php @@ -73,7 +73,8 @@ class Platform extends Model 'description' => 'HTTP basic authentication password.', 'default' => '', 'example' => 'password', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 511952b142..35c3cf0e1f 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -178,7 +178,7 @@ class Project extends Model 'description' => 'Status for custom SMTP', 'default' => false, 'example' => false, - 'array' => false, + 'array' => false ]) ->addRule('smtpSender', [ 'type' => self::TYPE_STRING, @@ -215,7 +215,8 @@ class Project extends Model 'description' => 'SMTP server secure protocol', 'default' => '', 'example' => 'tls', - ]); + ]) + ; $services = Config::getParam('services', []); $auth = Config::getParam('auth', []); @@ -225,16 +226,17 @@ class Project extends Model $key = $method['key'] ?? ''; $this - ->addRule('auth'.ucfirst($key), [ + ->addRule('auth' . ucfirst($key), [ 'type' => self::TYPE_BOOLEAN, - 'description' => $name.' auth method status', + 'description' => $name . ' auth method status', 'example' => true, 'default' => true, - ]); + ]) + ; } foreach ($services as $service) { - if (! $service['optional']) { + if (!$service['optional']) { continue; } @@ -242,12 +244,13 @@ class Project extends Model $key = $service['key'] ?? ''; $this - ->addRule('serviceStatusFor'.ucfirst($key), [ + ->addRule('serviceStatusFor' . ucfirst($key), [ 'type' => self::TYPE_BOOLEAN, - 'description' => $name.' service status', + 'description' => $name . ' service status', 'example' => true, 'default' => true, - ]); + ]) + ; } } @@ -293,12 +296,12 @@ class Project extends Model $services = Config::getParam('services', []); foreach ($services as $service) { - if (! $service['optional']) { + if (!$service['optional']) { continue; } $key = $service['key'] ?? ''; $value = $values[$key] ?? true; - $document->setAttribute('serviceStatusFor'.ucfirst($key), $value); + $document->setAttribute('serviceStatusFor' . ucfirst($key), $value); } // Auth @@ -315,7 +318,7 @@ class Project extends Model foreach ($auth as $index => $method) { $key = $method['key']; $value = $authValues[$key] ?? true; - $document->setAttribute('auth'.ucfirst($key), $value); + $document->setAttribute('auth' . ucfirst($key), $value); } // Providers @@ -324,7 +327,7 @@ class Project extends Model $projectProviders = []; foreach ($providers as $key => $provider) { - if (! $provider['enabled']) { + if (!$provider['enabled']) { // Disabled by Appwrite configuration, exclude from response continue; } @@ -332,13 +335,13 @@ class Project extends Model $projectProviders[] = new Document([ 'key' => $key, 'name' => $provider['name'] ?? '', - 'appId' => $providerValues[$key.'Appid'] ?? '', - 'secret' => $providerValues[$key.'Secret'] ?? '', - 'enabled' => $providerValues[$key.'Enabled'] ?? false, + 'appId' => $providerValues[$key . 'Appid'] ?? '', + 'secret' => $providerValues[$key . 'Secret'] ?? '', + 'enabled' => $providerValues[$key . 'Enabled'] ?? false, ]); } - $document->setAttribute('providers', $projectProviders); + $document->setAttribute("providers", $projectProviders); return $document; } diff --git a/src/Appwrite/Utopia/Response/Model/Runtime.php b/src/Appwrite/Utopia/Response/Model/Runtime.php index 43cf711994..8bc42cb418 100644 --- a/src/Appwrite/Utopia/Response/Model/Runtime.php +++ b/src/Appwrite/Utopia/Response/Model/Runtime.php @@ -20,7 +20,7 @@ class Runtime extends Model 'type' => self::TYPE_STRING, 'description' => 'Runtime Name.', 'default' => '', - 'example' => 'Python', + 'example' => 'Python' ]) ->addRule('version', [ 'type' => self::TYPE_STRING, @@ -52,7 +52,8 @@ class Runtime extends Model 'default' => '', 'example' => 'amd64', 'array' => true, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Session.php b/src/Appwrite/Utopia/Response/Model/Session.php index 7b71780c4e..d961966b24 100644 --- a/src/Appwrite/Utopia/Response/Model/Session.php +++ b/src/Appwrite/Utopia/Response/Model/Session.php @@ -159,7 +159,8 @@ class Session extends Model 'description' => 'Returns true if this the current user session.', 'default' => false, 'example' => true, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Team.php b/src/Appwrite/Utopia/Response/Model/Team.php index e180afbbeb..d080a82bb1 100644 --- a/src/Appwrite/Utopia/Response/Model/Team.php +++ b/src/Appwrite/Utopia/Response/Model/Team.php @@ -46,7 +46,8 @@ class Team extends Model 'description' => 'Team preferences as a key-value object', 'default' => new \stdClass(), 'example' => ['theme' => 'pink', 'timezone' => 'UTC'], - ]); + ]) + ; } /** @@ -64,7 +65,6 @@ class Team extends Model if (is_array($prefs) && empty($prefs)) { $document->setAttribute('prefs', new \stdClass()); } - return $document; } diff --git a/src/Appwrite/Utopia/Response/Model/Template.php b/src/Appwrite/Utopia/Response/Model/Template.php index 9d4f81068a..3ce9cacdb3 100644 --- a/src/Appwrite/Utopia/Response/Model/Template.php +++ b/src/Appwrite/Utopia/Response/Model/Template.php @@ -26,6 +26,7 @@ abstract class Template extends Model 'description' => 'Template message', 'default' => '', 'example' => 'Click on the link to verify your account.', - ]); + ]) + ; } } diff --git a/src/Appwrite/Utopia/Response/Model/TemplateEmail.php b/src/Appwrite/Utopia/Response/Model/TemplateEmail.php index 1babef9f90..ecdf89e774 100644 --- a/src/Appwrite/Utopia/Response/Model/TemplateEmail.php +++ b/src/Appwrite/Utopia/Response/Model/TemplateEmail.php @@ -33,7 +33,8 @@ class TemplateEmail extends Template 'description' => 'Email subject', 'default' => '', 'example' => 'Please verify your email address', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/TemplateSMS.php b/src/Appwrite/Utopia/Response/Model/TemplateSMS.php index f0abcdc511..2b19ef4878 100644 --- a/src/Appwrite/Utopia/Response/Model/TemplateSMS.php +++ b/src/Appwrite/Utopia/Response/Model/TemplateSMS.php @@ -10,7 +10,6 @@ class TemplateSMS extends Template { parent::__construct(); } - /** * Get Name * diff --git a/src/Appwrite/Utopia/Response/Model/Token.php b/src/Appwrite/Utopia/Response/Model/Token.php index 05bbe10302..c409e37f03 100644 --- a/src/Appwrite/Utopia/Response/Model/Token.php +++ b/src/Appwrite/Utopia/Response/Model/Token.php @@ -39,7 +39,8 @@ class Token extends Model 'description' => 'Token expiration date in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageBuckets.php b/src/Appwrite/Utopia/Response/Model/UsageBuckets.php index 1f708a0b4d..83b8744760 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageBuckets.php +++ b/src/Appwrite/Utopia/Response/Model/UsageBuckets.php @@ -21,15 +21,16 @@ class UsageBuckets extends Model 'description' => 'Aggregated stats for total number of files in this bucket.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('filesStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total storage of files in this bucket.', 'default' => [], 'example' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageCollection.php b/src/Appwrite/Utopia/Response/Model/UsageCollection.php index fd5350af86..5abcf46b7d 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageCollection.php +++ b/src/Appwrite/Utopia/Response/Model/UsageCollection.php @@ -21,8 +21,9 @@ class UsageCollection extends Model 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageDatabase.php b/src/Appwrite/Utopia/Response/Model/UsageDatabase.php index fac50676a6..58d49c506e 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageDatabase.php +++ b/src/Appwrite/Utopia/Response/Model/UsageDatabase.php @@ -21,15 +21,16 @@ class UsageDatabase extends Model 'description' => 'Aggregated stats for total number of collections.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('documentsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageDatabases.php b/src/Appwrite/Utopia/Response/Model/UsageDatabases.php index 20c2a1aecb..a6008ca9e6 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageDatabases.php +++ b/src/Appwrite/Utopia/Response/Model/UsageDatabases.php @@ -21,22 +21,23 @@ class UsageDatabases extends Model 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('collectionsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of collections.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('documentsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageFunction.php b/src/Appwrite/Utopia/Response/Model/UsageFunction.php index 013bf4056d..03acaa750a 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageFunction.php +++ b/src/Appwrite/Utopia/Response/Model/UsageFunction.php @@ -21,42 +21,42 @@ class UsageFunction extends Model 'description' => 'Aggregated stats for number of function deployments.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('deploymentsStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function deployments storage.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('buildsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function builds.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('buildsStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for builds storage.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('buildsTime', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function build compute.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('executionsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function executions.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('executionsTime', [ @@ -64,8 +64,9 @@ class UsageFunction extends Model 'description' => 'Aggregated stats for function execution compute.', 'default' => [], 'example' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageFunctions.php b/src/Appwrite/Utopia/Response/Model/UsageFunctions.php index 003f6390ad..6ab36e21ac 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageFunctions.php +++ b/src/Appwrite/Utopia/Response/Model/UsageFunctions.php @@ -21,49 +21,49 @@ class UsageFunctions extends Model 'description' => 'Aggregated stats for number of functions.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('deploymentsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function deployments.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('deploymentsStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function deployments storage.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('buildsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function builds.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('buildsStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for builds storage.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('buildsTime', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function build compute.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('executionsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of function executions.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('executionsTime', [ @@ -71,8 +71,9 @@ class UsageFunctions extends Model 'description' => 'Aggregated stats for function execution compute.', 'default' => [], 'example' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageProject.php b/src/Appwrite/Utopia/Response/Model/UsageProject.php index 41acef102f..641613809a 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageProject.php +++ b/src/Appwrite/Utopia/Response/Model/UsageProject.php @@ -21,57 +21,58 @@ class UsageProject extends Model 'description' => 'Aggregated stats for number of requests.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('network', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for consumed bandwidth.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('executionsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function executions.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('documentsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of documents.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('databasesTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of databases.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('usersTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of users.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('filesStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for the occupied storage size (in bytes).', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('bucketsTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of buckets.', 'default' => [], 'example' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageStorage.php b/src/Appwrite/Utopia/Response/Model/UsageStorage.php index 4d83948fb8..88d0beca01 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageStorage.php +++ b/src/Appwrite/Utopia/Response/Model/UsageStorage.php @@ -21,22 +21,23 @@ class UsageStorage extends Model 'description' => 'Aggregated stats for total number of buckets.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('filesTotal', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of files.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('filesStorage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for the occupied storage size (in bytes).', 'default' => [], 'example' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/UsageUsers.php b/src/Appwrite/Utopia/Response/Model/UsageUsers.php index 71774bf61d..c0cc4baa54 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageUsers.php +++ b/src/Appwrite/Utopia/Response/Model/UsageUsers.php @@ -21,7 +21,7 @@ class UsageUsers extends Model 'description' => 'Aggregated stats for total number of users.', 'default' => [], 'example' => [], - 'array' => true, + 'array' => true ]) ->addRule('sessionsTotal', [ @@ -29,8 +29,9 @@ class UsageUsers extends Model 'description' => 'Aggregated stats for sessions created.', 'default' => [], 'example' => [], - 'array' => true, - ]); + 'array' => true + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/User.php b/src/Appwrite/Utopia/Response/Model/User.php index a69c30f9d1..d6988b47f4 100644 --- a/src/Appwrite/Utopia/Response/Model/User.php +++ b/src/Appwrite/Utopia/Response/Model/User.php @@ -129,10 +129,11 @@ class User extends Model ]) ->addRule('accessedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after '.APP_USER_ACCCESS / 60 / 60 .' hours.', + 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_USER_ACCCESS / 60 / 60 . ' hours.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, - ]); + ]) + ; } /** @@ -150,7 +151,6 @@ class User extends Model if (is_array($prefs) && empty($prefs)) { $document->setAttribute('prefs', new \stdClass()); } - return $document; } diff --git a/src/Appwrite/Utopia/Response/Model/Variable.php b/src/Appwrite/Utopia/Response/Model/Variable.php index 7d84e8803f..f4b3bcf2bb 100644 --- a/src/Appwrite/Utopia/Response/Model/Variable.php +++ b/src/Appwrite/Utopia/Response/Model/Variable.php @@ -46,7 +46,8 @@ class Variable extends Model 'description' => 'Function ID.', 'default' => '', 'example' => '5e5ea5c16897e', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Webhook.php b/src/Appwrite/Utopia/Response/Model/Webhook.php index d9e0f4be3c..781bb9186d 100644 --- a/src/Appwrite/Utopia/Response/Model/Webhook.php +++ b/src/Appwrite/Utopia/Response/Model/Webhook.php @@ -75,7 +75,8 @@ class Webhook extends Model 'description' => 'Signature key which can be used to validated incoming', 'default' => '', 'example' => 'ad3d581ca230e2b7059c545e5a', - ]); + ]) + ; } /** diff --git a/src/Appwrite/Utopia/View.php b/src/Appwrite/Utopia/View.php index ba0a1f0fc6..e4ed8164c9 100644 --- a/src/Appwrite/Utopia/View.php +++ b/src/Appwrite/Utopia/View.php @@ -11,9 +11,8 @@ class View extends OldView * * Convert all applicable characters to HTML entities * - * @param string $str + * @param string $str * @return string - * * @deprecated Use print method with escape filter */ public function escape($str) diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index 4e158eb362..bd49e5cf20 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -8,21 +8,13 @@ use Utopia\App; class Executor { public const METHOD_GET = 'GET'; - public const METHOD_POST = 'POST'; - public const METHOD_PUT = 'PUT'; - public const METHOD_PATCH = 'PATCH'; - public const METHOD_DELETE = 'DELETE'; - public const METHOD_HEAD = 'HEAD'; - public const METHOD_OPTIONS = 'OPTIONS'; - public const METHOD_CONNECT = 'CONNECT'; - public const METHOD_TRACE = 'TRACE'; private bool $selfSigned = false; @@ -37,7 +29,7 @@ class Executor public function __construct(string $endpoint) { - if (! filter_var($endpoint, FILTER_VALIDATE_URL)) { + if (!filter_var($endpoint, FILTER_VALIDATE_URL)) { throw new Exception('Unsupported endpoint'); } @@ -46,7 +38,7 @@ class Executor $this->memory = intval(App::getEnv('_APP_FUNCTIONS_MEMORY', '512')); $this->headers = [ 'content-type' => 'application/json', - 'authorization' => 'Bearer '.App::getEnv('_APP_EXECUTOR_SECRET', ''), + 'authorization' => 'Bearer ' . App::getEnv('_APP_EXECUTOR_SECRET', ''), ]; } @@ -55,16 +47,16 @@ class Executor * * Launches a runtime container for a deployment ready for execution * - * @param string $deploymentId - * @param string $projectId - * @param string $source - * @param string $image - * @param bool $remove - * @param string $entrypoint - * @param string $workdir - * @param string $destination - * @param array $variables - * @param array $commands + * @param string $deploymentId + * @param string $projectId + * @param string $source + * @param string $image + * @param bool $remove + * @param string $entrypoint + * @param string $workdir + * @param string $destination + * @param array $variables + * @param array $commands */ public function createRuntime( string $deploymentId, @@ -79,8 +71,8 @@ class Executor array $commands = [] ) { $runtimeId = "$projectId-$deploymentId"; - $route = '/runtimes'; - $headers = ['x-opr-runtime-id' => $runtimeId]; + $route = "/runtimes"; + $headers = [ 'x-opr-runtime-id' => $runtimeId ]; $params = [ 'runtimeId' => $runtimeId, 'source' => $source, @@ -95,7 +87,7 @@ class Executor 'memory' => $this->memory, ]; - $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); + $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $timeout); @@ -111,14 +103,15 @@ class Executor /** * Create an execution * - * @param string $projectId - * @param string $deploymentId - * @param string $payload - * @param array $variables - * @param int $timeout - * @param string $image - * @param string $source - * @param string $entrypoint + * @param string $projectId + * @param string $deploymentId + * @param string $payload + * @param array $variables + * @param int $timeout + * @param string $image + * @param string $source + * @param string $entrypoint + * * @return array */ public function createExecution( @@ -132,8 +125,8 @@ class Executor string $entrypoint, ) { $runtimeId = "$projectId-$deploymentId"; - $route = '/runtimes/'.$runtimeId.'/execution'; - $headers = ['x-opr-runtime-id' => $runtimeId]; + $route = '/runtimes/' . $runtimeId . '/execution'; + $headers = [ 'x-opr-runtime-id' => $runtimeId ]; $params = [ 'runtimeId' => $runtimeId, 'variables' => $variables, @@ -147,7 +140,7 @@ class Executor 'memory' => $this->memory, ]; - $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); + $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $timeout); @@ -165,23 +158,22 @@ class Executor * * Make an API call * - * @param string $method - * @param string $path - * @param array $params - * @param array $headers - * @param bool $decode + * @param string $method + * @param string $path + * @param array $params + * @param array $headers + * @param bool $decode * @return array|string - * * @throws Exception */ public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true, int $timeout = 15) { - $headers = array_merge($this->headers, $headers); - $ch = curl_init($this->endpoint.$path.(($method == self::METHOD_GET && ! empty($params)) ? '?'.http_build_query($params) : '')); - $responseHeaders = []; - $responseStatus = -1; - $responseType = ''; - $responseBody = ''; + $headers = array_merge($this->headers, $headers); + $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); + $responseHeaders = []; + $responseStatus = -1; + $responseType = ''; + $responseBody = ''; switch ($headers['content-type']) { case 'application/json': @@ -198,7 +190,7 @@ class Executor } foreach ($headers as $i => $header) { - $headers[] = $i.':'.$header; + $headers[] = $i . ':' . $header; unset($headers[$i]); } @@ -231,8 +223,8 @@ class Executor curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - $responseBody = curl_exec($ch); - $responseType = $responseHeaders['content-type'] ?? ''; + $responseBody = curl_exec($ch); + $responseType = $responseHeaders['content-type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($decode) { @@ -241,7 +233,7 @@ class Executor $json = json_decode($responseBody, true); if ($json === null) { - throw new Exception('Failed to parse response: '.$responseBody); + throw new Exception('Failed to parse response: ' . $responseBody); } $responseBody = $json; @@ -251,7 +243,7 @@ class Executor } if ((curl_errno($ch)/* || 200 != $responseStatus*/)) { - throw new Exception(curl_error($ch).' with status code '.$responseStatus, $responseStatus); + throw new Exception(curl_error($ch) . ' with status code ' . $responseStatus, $responseStatus); } curl_close($ch); @@ -260,21 +252,21 @@ class Executor return [ 'headers' => $responseHeaders, - 'body' => $responseBody, + 'body' => $responseBody ]; } /** * Parse Cookie String * - * @param string $cookie + * @param string $cookie * @return array */ public function parseCookie(string $cookie): array { $cookies = []; - parse_str(strtr($cookie, ['&' => '%26', '+' => '%2B', ';' => '&']), $cookies); + parse_str(strtr($cookie, array('&' => '%26', '+' => '%2B', ';' => '&')), $cookies); return $cookies; } @@ -282,8 +274,8 @@ class Executor /** * Flatten params array to PHP multiple format * - * @param array $data - * @param string $prefix + * @param array $data + * @param string $prefix * @return array */ protected function flatten(array $data, string $prefix = ''): array diff --git a/tests/e2e/Client.php b/tests/e2e/Client.php index 6a9176232b..21e4ccc958 100644 --- a/tests/e2e/Client.php +++ b/tests/e2e/Client.php @@ -7,21 +7,13 @@ use Exception; class Client { public const METHOD_GET = 'GET'; - public const METHOD_POST = 'POST'; - public const METHOD_PUT = 'PUT'; - public const METHOD_PATCH = 'PATCH'; - public const METHOD_DELETE = 'DELETE'; - public const METHOD_HEAD = 'HEAD'; - public const METHOD_OPTIONS = 'OPTIONS'; - public const METHOD_CONNECT = 'CONNECT'; - public const METHOD_TRACE = 'TRACE'; /** @@ -60,7 +52,8 @@ class Client * * Your Appwrite project ID. You can find your project ID in your Appwrite console project settings. * - * @param string $value + * @param string $value + * * @return self $this */ public function setProject(string $value): self @@ -75,7 +68,8 @@ class Client * * Your Appwrite project secret key. You can can create a new API key from your Appwrite console API keys dashboard. * - * @param string $value + * @param string $value + * * @return self $this */ public function setKey(string $value): self @@ -88,7 +82,8 @@ class Client /** * Set Locale * - * @param string $value + * @param string $value + * * @return self $this */ public function setLocale(string $value): self @@ -101,7 +96,8 @@ class Client /** * Set Mode * - * @param string $value + * @param string $value + * * @return self $this */ public function setMode(string $value): self @@ -112,7 +108,7 @@ class Client } /** - * @param bool $status true + * @param bool $status true * @return self $this */ public function setSelfSigned(bool $status = true): self @@ -123,7 +119,7 @@ class Client } /** - * @param string $endpoint + * @param string $endpoint * @return self $this */ public function setEndpoint(string $endpoint): self @@ -142,8 +138,9 @@ class Client } /** - * @param string $key - * @param string $value + * @param string $key + * @param string $value + * * @return self $this */ public function addHeader(string $key, string $value): self @@ -158,20 +155,19 @@ class Client * * Make an API call * - * @param string $method - * @param string $path - * @param array $params - * @param array $headers - * @param bool $decode + * @param string $method + * @param string $path + * @param array $params + * @param array $headers + * @param bool $decode * @return array - * * @throws Exception */ public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true): array { - $headers = array_merge($this->headers, $headers); - $ch = curl_init($this->endpoint.$path.(($method == self::METHOD_GET && ! empty($params)) ? '?'.http_build_query($params) : '')); - $responseHeaders = []; + $headers = array_merge($this->headers, $headers); + $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); + $responseHeaders = []; $query = match ($headers['content-type']) { 'application/json' => json_encode($params), @@ -181,7 +177,7 @@ class Client }; foreach ($headers as $i => $header) { - $headers[] = $i.':'.$header; + $headers[] = $i . ':' . $header; unset($headers[$i]); } @@ -216,15 +212,15 @@ class Client curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - $responseBody = curl_exec($ch); - $responseType = $responseHeaders['content-type'] ?? ''; + $responseBody = curl_exec($ch); + $responseType = $responseHeaders['content-type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($decode && substr($responseType, 0, strpos($responseType, ';')) == 'application/json') { $json = json_decode($responseBody, true); if ($json === null) { - throw new Exception('Failed to parse response: '.$responseBody); + throw new Exception('Failed to parse response: ' . $responseBody); } $responseBody = $json; @@ -232,7 +228,7 @@ class Client } if ((curl_errno($ch))) { - throw new Exception(curl_error($ch).' with status code '.$responseStatus, $responseStatus); + throw new Exception(curl_error($ch) . ' with status code ' . $responseStatus, $responseStatus); } curl_close($ch); @@ -240,19 +236,19 @@ class Client $responseHeaders['status-code'] = $responseStatus; if ($responseStatus === 500) { - echo 'Server error('.$method.': '.$path.'. Params: '.json_encode($params).'): '.json_encode($responseBody)."\n"; + echo 'Server error(' . $method . ': ' . $path . '. Params: ' . json_encode($params) . '): ' . json_encode($responseBody) . "\n"; } return [ 'headers' => $responseHeaders, - 'body' => $responseBody, + 'body' => $responseBody ]; } /** * Parse Cookie String * - * @param string $cookie + * @param string $cookie * @return array */ public function parseCookie(string $cookie): array @@ -267,8 +263,8 @@ class Client /** * Flatten params array to PHP multiple format * - * @param array $data - * @param string $prefix + * @param array $data + * @param string $prefix * @return array */ protected function flatten(array $data, string $prefix = ''): array diff --git a/tests/e2e/General/AbuseTest.php b/tests/e2e/General/AbuseTest.php index ded164af21..f5a2829974 100644 --- a/tests/e2e/General/AbuseTest.php +++ b/tests/e2e/General/AbuseTest.php @@ -34,13 +34,13 @@ class AbuseTest extends Scope $max = 120; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'documentId' => ID::unique(), 'data' => [ - 'title' => 'The Hulk '.$i, + 'title' => 'The Hulk ' . $i, ], ]); @@ -59,7 +59,7 @@ class AbuseTest extends Scope $collectionId = $data['collectionId']; $max = 120; - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -73,12 +73,12 @@ class AbuseTest extends Scope $documentId = $document['body']['$id']; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$documentId, [ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'data' => [ - 'title' => 'The Hulk '.$i, + 'title' => 'The Hulk ' . $i, ], ]); @@ -98,7 +98,7 @@ class AbuseTest extends Scope $max = 60; for ($i = 0; $i <= $max + 1; $i++) { - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -111,7 +111,7 @@ class AbuseTest extends Scope $documentId = $document['body']['$id']; - $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$documentId, [ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -131,12 +131,12 @@ class AbuseTest extends Scope $max = 60; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../resources/logo.png'), 'image/png', 'permissions.png'), ]); if ($i < $max) { @@ -153,23 +153,23 @@ class AbuseTest extends Scope $bucketId = $data['bucketId']; $max = 60; - $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $response['body']['$id']; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $response = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'name' => 'permissions'.$i.'.png', + 'name' => 'permissions' . $i . '.png', ]); if ($i < $max) { @@ -187,18 +187,18 @@ class AbuseTest extends Scope $max = 60; for ($i = 0; $i <= $max + 1; $i++) { - $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $response = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $response['body']['$id']; - $response = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $response = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -216,7 +216,7 @@ class AbuseTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'AbuseDatabase', @@ -227,10 +227,10 @@ class AbuseTest extends Scope $databaseId = $database['body']['$id']; - $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', [ + $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -244,10 +244,10 @@ class AbuseTest extends Scope $collectionId = $movies['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', [ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'key' => 'title', 'size' => 256, diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php index e3533e31d6..087b984f9d 100644 --- a/tests/e2e/General/HTTPTest.php +++ b/tests/e2e/General/HTTPTest.php @@ -68,7 +68,7 @@ class HTTPTest extends Scope { // Preparation $previousEndpoint = $this->client->getEndpoint(); - $this->client->setEndpoint('http://localhost'); + $this->client->setEndpoint("http://localhost"); /** * Test for SUCCESS @@ -96,7 +96,7 @@ class HTTPTest extends Scope public function testSpecs() { - $directory = __DIR__.'/../../../app/config/specs/'; + $directory = __DIR__ . '/../../../app/config/specs/'; $files = scandir($directory); $client = new Client(); @@ -120,7 +120,7 @@ class HTTPTest extends Scope break; } } - if (! $allowed) { + if (!$allowed) { continue; } @@ -129,7 +129,7 @@ class HTTPTest extends Scope */ $response = $client->call(Client::METHOD_POST, '/validator/debug', [ 'content-type' => 'application/json', - ], json_decode(file_get_contents($directory.$file), true)); + ], json_decode(file_get_contents($directory . $file), true)); $response['body'] = json_decode($response['body'], true); $this->assertEquals(200, $response['headers']['status-code']); diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index d9a662b6ac..c8c4f21165 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -2,12 +2,13 @@ namespace Tests\E2E\General; -use CURLFile; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; +use CURLFile; use Tests\E2E\Services\Functions\FunctionsBase; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -19,7 +20,6 @@ class UsageTest extends Scope use FunctionsBase; private const WAIT = 35; - private const CREATE = 20; protected string $projectId; @@ -46,21 +46,21 @@ class UsageTest extends Scope $headers['x-appwrite-key'] = $project['apiKey']; $headers['content-type'] = 'application/json'; - $usersTotal = 0; + $usersTotal = 0; $requestsTotal = 0; for ($i = 0; $i < self::CREATE; $i++) { - $email = uniqid().'user@usage.test'; + $email = uniqid() . 'user@usage.test'; $password = 'password'; - $name = uniqid().'User'; + $name = uniqid() . 'User'; $res = $this->client->call( Client::METHOD_POST, '/users', $headers, [ - 'userId' => 'unique()', - 'email' => $email, + 'userId' => 'unique()', + 'email' => $email, 'password' => $password, - 'name' => $name, + 'name' => $name, ] ); @@ -71,7 +71,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $userId = $res['body']['$id']; - $res = $this->client->call(Client::METHOD_DELETE, '/users/'.$userId, $headers); + $res = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, $headers); $this->assertEmpty($res['body']); $requestsTotal++; $usersTotal--; @@ -79,10 +79,10 @@ class UsageTest extends Scope } return [ - 'projectId' => $projectId, - 'headers' => $headers, - 'usersTotal' => $usersTotal, - 'requestsTotal' => $requestsTotal, + 'projectId' => $projectId, + 'headers' => $headers, + 'usersTotal' => $usersTotal, + 'requestsTotal' => $requestsTotal ]; } @@ -93,15 +93,15 @@ class UsageTest extends Scope { sleep(self::WAIT); - $projectId = $data['projectId']; - $headers = $data['headers']; - $usersTotal = $data['usersTotal']; + $projectId = $data['projectId']; + $headers = $data['headers']; + $usersTotal = $data['usersTotal']; $requestsTotal = $data['requestsTotal']; $consoleHeaders = [ 'origin' => 'http://localhost', 'x-appwrite-project' => 'console', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], 'x-appwrite-project' => $projectId, 'x-appwrite-mode' => 'admin', ]; @@ -151,8 +151,9 @@ class UsageTest extends Scope $storageTotal = 0; $filesTotal = 0; + for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid().' bucket'; + $name = uniqid() . ' bucket'; $res = $this->client->call( Client::METHOD_POST, '/storage/buckets', @@ -178,7 +179,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/storage/buckets/'.$bucketId, + '/storage/buckets/' . $bucketId, $headers ); $this->assertEmpty($res['body']); @@ -190,19 +191,19 @@ class UsageTest extends Scope // upload some files $files = [ [ - 'path' => realpath(__DIR__.'/../../resources/logo.png'), + 'path' => realpath(__DIR__ . '/../../resources/logo.png'), 'name' => 'logo.png', ], [ - 'path' => realpath(__DIR__.'/../../resources/file.png'), + 'path' => realpath(__DIR__ . '/../../resources/file.png'), 'name' => 'file.png', ], [ - 'path' => realpath(__DIR__.'/../../resources/disk-a/kitten-3.gif'), + 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-3.gif'), 'name' => 'kitten-3.gif', ], [ - 'path' => realpath(__DIR__.'/../../resources/disk-a/kitten-1.jpg'), + 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'), 'name' => 'kitten-1.jpg', ], ]; @@ -212,7 +213,7 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_POST, - '/storage/buckets/'.$bucketId.'/files', + '/storage/buckets/' . $bucketId . '/files', array_merge($headers, ['content-type' => 'multipart/form-data']), [ 'fileId' => 'unique()', @@ -231,13 +232,13 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/storage/buckets/'.$bucketId.'/files/'.$fileId, + '/storage/buckets/' . $bucketId . '/files/' . $fileId, $headers ); $this->assertEmpty($res['body']); $requestsTotal++; $filesTotal--; - $storageTotal -= $fileSize; + $storageTotal -= $fileSize; } } @@ -255,11 +256,11 @@ class UsageTest extends Scope */ public function testStorageStats(array $data): array { - $bucketId = $data['bucketId']; - $bucketsTotal = $data['bucketsTotal']; + $bucketId = $data['bucketId']; + $bucketsTotal = $data['bucketsTotal']; $requestsTotal = $data['requestsTotal']; - $storageTotal = $data['storageTotal']; - $filesTotal = $data['filesTotal']; + $storageTotal = $data['storageTotal']; + $filesTotal = $data['filesTotal']; sleep(self::WAIT); @@ -300,7 +301,7 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_GET, - '/storage/'.$bucketId.'/usage?range=30d', + '/storage/' . $bucketId . '/usage?range=30d', array_merge( $data['headers'], $data['consoleHeaders'] @@ -327,7 +328,7 @@ class UsageTest extends Scope $documentsTotal = 0; for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid().' database'; + $name = uniqid() . ' database'; $res = $this->client->call( Client::METHOD_POST, '/databases', @@ -338,6 +339,7 @@ class UsageTest extends Scope ] ); + $this->assertEquals($name, $res['body']['name']); $this->assertNotEmpty($res['body']['$id']); $databaseId = $res['body']['$id']; @@ -348,7 +350,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/databases/'.$databaseId, + '/databases/' . $databaseId, $headers ); $this->assertEmpty($res['body']); @@ -359,10 +361,10 @@ class UsageTest extends Scope } for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid().' collection'; + $name = uniqid() . ' collection'; $res = $this->client->call( Client::METHOD_POST, - '/databases/'.$databaseId.'/collections', + '/databases/' . $databaseId . '/collections', $headers, [ 'collectionId' => 'unique()', @@ -387,7 +389,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/databases/'.$databaseId.'/collections/'.$collectionId, + '/databases/' . $databaseId . '/collections/' . $collectionId, $headers ); $this->assertEmpty($res['body']); @@ -398,7 +400,7 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_POST, - '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes'.'/string', + '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes' . '/string', $headers, [ 'key' => 'name', @@ -413,14 +415,14 @@ class UsageTest extends Scope sleep(self::WAIT); for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid().' collection'; + $name = uniqid() . ' collection'; $res = $this->client->call( Client::METHOD_POST, - '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', + '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', $headers, [ 'documentId' => 'unique()', - 'data' => ['name' => $name], + 'data' => ['name' => $name] ] ); $this->assertEquals($name, $res['body']['name']); @@ -433,7 +435,7 @@ class UsageTest extends Scope if ($i < (self::CREATE / 2)) { $res = $this->client->call( Client::METHOD_DELETE, - '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$documentId, + '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, $headers ); $this->assertEmpty($res['body']); @@ -453,8 +455,10 @@ class UsageTest extends Scope } /** @depends testPrepareDatabaseStats */ + public function testDatabaseStats(array $data): array { + $projectId = $data['projectId']; $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; @@ -498,7 +502,7 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_GET, - '/databases/'.$databaseId.'/usage?range=30d', + '/databases/' . $databaseId . '/usage?range=30d', $data['consoleHeaders'] ); $res = $res['body']; @@ -509,7 +513,7 @@ class UsageTest extends Scope $this->assertEquals($documentsTotal, $res['documentsTotal'][array_key_last($res['documentsTotal'])]['value']); $this->validateDates($res['documentsTotal']); - $res = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/usage?range=30d', $data['consoleHeaders']); + $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', $data['consoleHeaders']); $res = $res['body']; $this->assertEquals($documentsTotal, $res['documentsTotal'][array_key_last($res['documentsTotal'])]['value']); @@ -520,6 +524,7 @@ class UsageTest extends Scope return $data; } + /** @depends testDatabaseStats */ public function testPrepareFunctionsStats(array $data): array { @@ -556,17 +561,17 @@ class UsageTest extends Scope $this->assertEquals(201, $response1['headers']['status-code']); $this->assertNotEmpty($response1['body']['$id']); - $code = realpath(__DIR__.'/../../resources/functions').'/php/code.tar.gz'; + $code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz"; $this->packageCode('php'); $deployment = $this->client->call( Client::METHOD_POST, - '/functions/'.$functionId.'/deployments', - array_merge($headers, ['content-type' => 'multipart/form-data']), + '/functions/' . $functionId . '/deployments', + array_merge($headers, ['content-type' => 'multipart/form-data',]), [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), - 'activate' => true, + 'activate' => true ] ); @@ -582,7 +587,7 @@ class UsageTest extends Scope $response = $this->client->call( Client::METHOD_PATCH, - '/functions/'.$functionId.'/deployments/'.$deploymentId, + '/functions/' . $functionId . '/deployments/' . $deploymentId, $headers ); @@ -595,7 +600,7 @@ class UsageTest extends Scope $execution = $this->client->call( Client::METHOD_POST, - '/functions/'.$functionId.'/executions', + '/functions/' . $functionId . '/executions', $headers, [ 'async' => false, @@ -616,7 +621,7 @@ class UsageTest extends Scope $execution = $this->client->call( Client::METHOD_POST, - '/functions/'.$functionId.'/executions', + '/functions/' . $functionId . '/executions', $headers, [ 'async' => false, @@ -635,7 +640,7 @@ class UsageTest extends Scope $execution = $this->client->call( Client::METHOD_POST, - '/functions/'.$functionId.'/executions', + '/functions/' . $functionId . '/executions', $headers, [ 'async' => true, @@ -650,7 +655,7 @@ class UsageTest extends Scope $execution = $this->client->call( Client::METHOD_GET, - '/functions/'.$functionId.'/executions/'.$execution['body']['$id'], + '/functions/' . $functionId . '/executions/' . $execution['body']['$id'], $headers ); @@ -681,7 +686,7 @@ class UsageTest extends Scope $response = $this->client->call( Client::METHOD_GET, - '/functions/'.$functionId.'/usage?range=30d', + '/functions/' . $functionId . '/usage?range=30d', $data['consoleHeaders'] ); diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index 7146ebc392..ee41129fde 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -13,19 +13,19 @@ trait ProjectCustom protected static $project = []; /** - * @param bool $fresh + * @param bool $fresh * @return array */ public function getProject(bool $fresh = false): array { - if (! empty(self::$project) && ! $fresh) { + if (!empty(self::$project) && !$fresh) { return self::$project; } $team = $this->client->call(Client::METHOD_POST, '/teams', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'teamId' => ID::unique(), @@ -38,7 +38,7 @@ trait ProjectCustom $project = $this->client->call(Client::METHOD_POST, '/projects', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'projectId' => ID::unique(), @@ -52,10 +52,10 @@ trait ProjectCustom $this->assertEquals(201, $project['headers']['status-code']); $this->assertNotEmpty($project['body']); - $key = $this->client->call(Client::METHOD_POST, '/projects/'.$project['body']['$id'].'/keys', [ + $key = $this->client->call(Client::METHOD_POST, '/projects/' . $project['body']['$id'] . '/keys', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'name' => 'Demo Project Key', @@ -92,10 +92,10 @@ trait ProjectCustom $this->assertNotEmpty($key['body']); $this->assertNotEmpty($key['body']['secret']); - $webhook = $this->client->call(Client::METHOD_POST, '/projects/'.$project['body']['$id'].'/webhooks', [ + $webhook = $this->client->call(Client::METHOD_POST, '/projects/' . $project['body']['$id'] . '/webhooks', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'name' => 'Webhook Test', @@ -104,7 +104,7 @@ trait ProjectCustom // 'functions.*', TODO @christyjacob4 : enable test once we allow functions.* events 'buckets.*', 'teams.*', - 'users.*', + 'users.*' ], 'url' => 'http://request-catcher:5000/webhook', 'security' => false, @@ -130,12 +130,13 @@ trait ProjectCustom public function getNewKey(array $scopes) { + $projectId = self::$project['$id']; - $key = $this->client->call(Client::METHOD_POST, '/projects/'.$projectId.'/keys', [ + $key = $this->client->call(Client::METHOD_POST, '/projects/' . $projectId . '/keys', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], 'x-appwrite-project' => 'console', ], [ 'name' => 'Demo Project Key', diff --git a/tests/e2e/Scopes/Scope.php b/tests/e2e/Scopes/Scope.php index 4eaf846c27..14eb83897b 100644 --- a/tests/e2e/Scopes/Scope.php +++ b/tests/e2e/Scopes/Scope.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Scopes; use Appwrite\Tests\Retryable; -use PHPUnit\Framework\TestCase; use Tests\E2E\Client; +use PHPUnit\Framework\TestCase; use Utopia\Database\Helpers\ID; abstract class Scope extends TestCase @@ -12,7 +12,6 @@ abstract class Scope extends TestCase use Retryable; protected ?Client $client = null; - protected string $endpoint = 'http://localhost/v1'; protected function setUp(): void @@ -73,7 +72,7 @@ abstract class Scope extends TestCase return self::$root; } - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -99,7 +98,7 @@ abstract class Scope extends TestCase 'password' => $password, ]); - $session = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_console']; + $session = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_console']; self::$root = [ '$id' => ID::custom($root['body']['$id']), @@ -125,7 +124,7 @@ abstract class Scope extends TestCase return self::$user[$this->getProject()['$id']]; } - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -151,7 +150,7 @@ abstract class Scope extends TestCase 'password' => $password, ]); - $token = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $token = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; self::$user[$this->getProject()['$id']] = [ '$id' => ID::custom($user['body']['$id']), diff --git a/tests/e2e/Scopes/SideClient.php b/tests/e2e/Scopes/SideClient.php index 2348da8e6b..54f77a9747 100644 --- a/tests/e2e/Scopes/SideClient.php +++ b/tests/e2e/Scopes/SideClient.php @@ -8,7 +8,7 @@ trait SideClient { return [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$this->getUser()['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $this->getUser()['session'], ]; } diff --git a/tests/e2e/Scopes/SideConsole.php b/tests/e2e/Scopes/SideConsole.php index f067977c14..74a0dd0c60 100644 --- a/tests/e2e/Scopes/SideConsole.php +++ b/tests/e2e/Scopes/SideConsole.php @@ -8,8 +8,8 @@ trait SideConsole { return [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], - 'x-appwrite-mode' => 'admin', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'x-appwrite-mode' => 'admin' ]; } diff --git a/tests/e2e/Scopes/SideServer.php b/tests/e2e/Scopes/SideServer.php index f72ac1f2e2..b5e15150e9 100644 --- a/tests/e2e/Scopes/SideServer.php +++ b/tests/e2e/Scopes/SideServer.php @@ -12,7 +12,7 @@ trait SideServer public function getHeaders(): array { return [ - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]; } diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 84c32aede9..291d55b221 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -4,15 +4,15 @@ namespace Tests\E2E\Services\Account; use Appwrite\Tests\Retry; use Tests\E2E\Client; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; +use Utopia\Database\DateTime; use Utopia\Database\Validator\Datetime as DatetimeValidator; trait AccountBase { public function testCreateAccount(): array { - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -126,13 +126,13 @@ trait AccountBase $this->assertNotFalse(\DateTime::createFromFormat('Y-m-d\TH:i:s.uP', $response['body']['expire'])); $sessionId = $response['body']['$id']; - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; // apiKey is only available in custom client test $apiKey = $this->getProject()['apiKey']; - if (! empty($apiKey)) { + if (!empty($apiKey)) { $userId = $response['body']['userId']; - $response = $this->client->call(Client::METHOD_GET, '/users/'.$userId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/' . $userId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -163,7 +163,7 @@ trait AccountBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]), [ - 'email' => $email.'x', + 'email' => $email . 'x', 'password' => $password, ]); @@ -175,7 +175,7 @@ trait AccountBase 'x-appwrite-project' => $this->getProject()['$id'], ]), [ 'email' => $email, - 'password' => $password.'x', + 'password' => $password . 'x', ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -213,7 +213,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -237,7 +237,7 @@ trait AccountBase $response = $this->client->call(Client::METHOD_GET, '/account', [ 'content-type' => 'application/json', - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session.'xx', + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session . 'xx', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -260,7 +260,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -297,7 +297,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -357,7 +357,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -365,7 +365,7 @@ trait AccountBase $this->assertNotEmpty($response['body']['logs']); $this->assertCount(3, $response['body']['logs']); $this->assertIsNumeric($response['body']['total']); - $this->assertContains($response['body']['logs'][1]['event'], ['session.create']); + $this->assertContains($response['body']['logs'][1]['event'], ["session.create"]); $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['logs'][1]['time'])); @@ -387,7 +387,7 @@ trait AccountBase $this->assertEquals('--', $response['body']['logs'][1]['countryCode']); $this->assertEquals('Unknown', $response['body']['logs'][1]['countryName']); - $this->assertContains($response['body']['logs'][2]['event'], ['user.create']); + $this->assertContains($response['body']['logs'][2]['event'], ["user.create"]); $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['logs'][2]['time'])); @@ -413,9 +413,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'queries' => ['limit(1)'], + 'queries' => [ 'limit(1)' ], ]); $this->assertEquals($responseLimit['headers']['status-code'], 200); @@ -430,9 +430,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'queries' => ['offset(1)'], + 'queries' => [ 'offset(1)' ], ]); $this->assertEquals($responseOffset['headers']['status-code'], 200); @@ -447,9 +447,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'queries' => ['limit(1)', 'offset(1)'], + 'queries' => [ 'limit(1)', 'offset(1)' ], ]); $this->assertEquals($responseLimitOffset['headers']['status-code'], 200); @@ -491,9 +491,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'name' => $newName, + 'name' => $newName ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -519,7 +519,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -528,9 +528,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'name' => 'ocSRq1d3QphHivJyUmYY7WMnrxyjdk5YvVwcDqx2zS0coxESN8RmsQwLWw5Whnf0WbVohuFWTRAaoKgCOO0Y0M7LwgFnZmi8881Y72222222222222222222222222222', + 'name' => 'ocSRq1d3QphHivJyUmYY7WMnrxyjdk5YvVwcDqx2zS0coxESN8RmsQwLWw5Whnf0WbVohuFWTRAaoKgCOO0Y0M7LwgFnZmi8881Y72222222222222222222222222222' ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -557,7 +557,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'password' => 'new-password', 'oldPassword' => $password, @@ -595,7 +595,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -607,7 +607,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'password' => 'new-password', 'oldPassword' => $password, @@ -621,9 +621,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'password' => 'new-password', + 'password' => 'new-password' ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -637,7 +637,7 @@ trait AccountBase */ public function testUpdateAccountEmail($data): array { - $newEmail = uniqid().'new@localhost.test'; + $newEmail = uniqid() . 'new@localhost.test'; $session = $data['session'] ?? ''; /** @@ -647,7 +647,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'email' => $newEmail, 'password' => 'new-password', @@ -675,7 +675,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -691,9 +691,9 @@ trait AccountBase 'x-appwrite-project' => $this->getProject()['$id'], ]), [ 'userId' => ID::unique(), - 'email' => $data['email'], - 'password' => $data['password'], - 'name' => $data['name'], + 'email' => $data['email'], + 'password' => $data['password'], + 'name' => $data['name'], ]); $this->assertEquals($response['headers']['status-code'], 201); @@ -703,6 +703,7 @@ trait AccountBase $this->assertEquals($response['body']['email'], $data['email']); $this->assertEquals($response['body']['name'], $data['name']); + $data['email'] = $newEmail; return $data; @@ -713,7 +714,7 @@ trait AccountBase */ public function testUpdateAccountPrefs($data): array { - $newEmail = uniqid().'new@localhost.test'; + $newEmail = uniqid() . 'new@localhost.test'; $session = $data['session'] ?? ''; /** @@ -723,12 +724,12 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'prefs' => [ 'prefKey1' => 'prefValue1', 'prefKey2' => 'prefValue2', - ], + ] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -752,9 +753,21 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'prefs' => '{}', + 'prefs' => '{}' + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + + $response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]), [ + 'prefs' => '[]' ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -763,20 +776,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'prefs' => '[]', - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, - ]), [ - 'prefs' => '{"test": "value"}', + 'prefs' => '{"test": "value"}' ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -784,29 +786,29 @@ trait AccountBase /** * Prefs size exceeded */ - $prefsObject = ['longValue' => str_repeat('🍰', 100000)]; + $prefsObject = ["longValue" => str_repeat("🍰", 100000)]; $response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'prefs' => $prefsObject, + 'prefs' => $prefsObject ]); $this->assertEquals(400, $response['headers']['status-code']); // Now let's test the same thing, but with normal symbol instead of multi-byte cake emoji - $prefsObject = ['longValue' => str_repeat('-', 100000)]; + $prefsObject = ["longValue" => str_repeat("-", 100000)]; $response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'prefs' => $prefsObject, + 'prefs' => $prefsObject ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -830,7 +832,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'url' => 'http://localhost/verification', @@ -848,14 +850,14 @@ trait AccountBase $this->assertEquals('Account Verification', $lastEmail['subject']); $verification = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); - $expireTime = strpos($lastEmail['text'], 'expire='.urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0); + $expireTime = strpos($lastEmail['text'], 'expire=' . urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0); $this->assertNotFalse($expireTime); - $secretTest = strpos($lastEmail['text'], 'secret='.$response['body']['secret'], 0); + $secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0); $this->assertNotFalse($secretTest); - $userIDTest = strpos($lastEmail['text'], 'userId='.$response['body']['userId'], 0); + $userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0); $this->assertNotFalse($userIDTest); @@ -866,7 +868,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'url' => 'localhost/verification', ]); @@ -877,7 +879,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'url' => 'http://remotehost/verification', ]); @@ -905,7 +907,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'userId' => $id, 'secret' => $verification, @@ -920,7 +922,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'userId' => ID::custom('ewewe'), 'secret' => $verification, @@ -932,7 +934,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'userId' => $id, 'secret' => 'sdasdasdasd', @@ -965,7 +967,7 @@ trait AccountBase ]); $sessionNewId = $response['body']['$id']; - $sessionNew = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $sessionNew = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $this->assertEquals($response['headers']['status-code'], 201); @@ -973,16 +975,16 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, ]); $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionNewId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionNewId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, ])); $this->assertEquals($response['headers']['status-code'], 204); @@ -991,7 +993,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -1003,7 +1005,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -1031,14 +1033,14 @@ trait AccountBase 'password' => $password, ]); - $sessionNew = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $sessionNew = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $this->assertEquals($response['headers']['status-code'], 201); $response = $this->client->call(Client::METHOD_GET, '/account', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -1047,7 +1049,7 @@ trait AccountBase $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/current', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -1059,7 +1061,7 @@ trait AccountBase $response = $this->client->call(Client::METHOD_GET, '/account', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$sessionNew, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $sessionNew, 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -1082,7 +1084,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 204); @@ -1113,7 +1115,7 @@ trait AccountBase 'password' => $password, ]); - $data['session'] = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $data['session'] = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; return $data; } @@ -1151,15 +1153,15 @@ trait AccountBase $recovery = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); - $expireTime = strpos($lastEmail['text'], 'expire='.urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0); + $expireTime = strpos($lastEmail['text'], 'expire=' . urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0); $this->assertNotFalse($expireTime); - $secretTest = strpos($lastEmail['text'], 'secret='.$response['body']['secret'], 0); + $secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0); $this->assertNotFalse($secretTest); - $userIDTest = strpos($lastEmail['text'], 'userId='.$response['body']['userId'], 0); + $userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0); $this->assertNotFalse($userIDTest); @@ -1266,7 +1268,7 @@ trait AccountBase ]), [ 'userId' => $id, 'secret' => $recovery, - 'password' => $newPassowrd.'x', + 'password' => $newPassowrd . 'x', 'passwordAgain' => $newPassowrd, ]); @@ -1277,7 +1279,7 @@ trait AccountBase public function testCreateMagicUrl(): array { - $email = \time().'user@appwrite.io'; + $email = \time() . 'user@appwrite.io'; /** * Test for SUCCESS @@ -1305,15 +1307,15 @@ trait AccountBase $token = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); - $expireTime = strpos($lastEmail['text'], 'expire='.urlencode($response['body']['expire']), 0); + $expireTime = strpos($lastEmail['text'], 'expire=' . urlencode($response['body']['expire']), 0); $this->assertNotFalse($expireTime); - $secretTest = strpos($lastEmail['text'], 'secret='.$response['body']['secret'], 0); + $secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0); $this->assertNotFalse($secretTest); - $userIDTest = strpos($lastEmail['text'], 'userId='.$response['body']['userId'], 0); + $userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0); $this->assertNotFalse($userIDTest); @@ -1389,13 +1391,13 @@ trait AccountBase $this->assertNotEmpty($response['body']['userId']); $sessionId = $response['body']['$id']; - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -1430,6 +1432,7 @@ trait AccountBase $this->assertEquals(401, $response['headers']['status-code']); + $data['sessionId'] = $sessionId; $data['session'] = $session; @@ -1451,9 +1454,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'password' => 'new-password', + 'password' => 'new-password' ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -1489,7 +1492,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -1501,7 +1504,7 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'password' => 'new-password', 'oldPassword' => 'wrong-password', @@ -1515,9 +1518,9 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'password' => 'new-password', + 'password' => 'new-password' ]); $this->assertEquals($response['headers']['status-code'], 401); diff --git a/tests/e2e/Services/Account/AccountConsoleClientTest.php b/tests/e2e/Services/Account/AccountConsoleClientTest.php index c1a248ac49..b517d8c408 100644 --- a/tests/e2e/Services/Account/AccountConsoleClientTest.php +++ b/tests/e2e/Services/Account/AccountConsoleClientTest.php @@ -3,11 +3,11 @@ namespace Tests\E2E\Services\Account; use Appwrite\Extend\Exception; -use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; +use Tests\E2E\Client; use Utopia\Database\Validator\Datetime as DatetimeValidator; class AccountConsoleClientTest extends Scope @@ -18,7 +18,7 @@ class AccountConsoleClientTest extends Scope public function testCreateAccountWithInvite(): void { - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -34,7 +34,7 @@ class AccountConsoleClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'code' => 'Invalid Code', + 'code' => 'Invalid Code' ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -66,7 +66,7 @@ class AccountConsoleClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'code' => 'code-zero', + 'code' => 'code-zero' ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -76,7 +76,7 @@ class AccountConsoleClientTest extends Scope $this->assertEquals($response['body']['email'], $email); $this->assertEquals($response['body']['name'], $name); - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $response = $this->client->call(Client::METHOD_POST, '/account/invite', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', @@ -86,7 +86,7 @@ class AccountConsoleClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'code' => 'code-one', + 'code' => 'code-one' ]); $this->assertEquals(201, $response['headers']['status-code']); diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 7ca0798a61..d225496a65 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -3,16 +3,18 @@ namespace Tests\E2E\Services\Account; use Appwrite\Extend\Exception; +use Appwrite\SMS\Adapter\Mock; use Appwrite\Tests\Retry; -use function sleep; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; +use function sleep; + class AccountCustomClientTest extends Scope { use AccountBase; @@ -21,7 +23,7 @@ class AccountCustomClientTest extends Scope public function testCreateAccountWithInvite(): void { - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -38,7 +40,7 @@ class AccountCustomClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'code' => 'Invalid Code', + 'code' => 'Invalid Code' ]); $this->assertEquals($response['headers']['status-code'], 401); @@ -57,11 +59,11 @@ class AccountCustomClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => 'console', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), [ 'provider' => $provider, 'appId' => $appId, @@ -71,7 +73,7 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/'.$provider, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -86,11 +88,11 @@ class AccountCustomClientTest extends Scope /** * Test for Failure when disabled */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => 'console', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), [ 'provider' => $provider, 'appId' => $appId, @@ -100,7 +102,7 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/'.$provider, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -116,7 +118,7 @@ class AccountCustomClientTest extends Scope public function testBlockedAccount(): array { - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name (blocked)'; @@ -150,18 +152,18 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 201); $sessionId = $response['body']['$id']; - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_PATCH, '/users/'.$id.'/status', [ + $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $id . '/status', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -175,7 +177,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 401); @@ -194,9 +196,10 @@ class AccountCustomClientTest extends Scope return []; } + public function testSelfBlockedAccount(): array { - $email = uniqid().'user55@localhost.test'; + $email = uniqid() . 'user55@localhost.test'; $password = 'password'; $name = 'User Name (self blocked)'; @@ -229,13 +232,13 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 201); - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -243,20 +246,20 @@ class AccountCustomClientTest extends Scope $response = $this->client->call(Client::METHOD_PATCH, '/account/status', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ], [ 'status' => false, ]); $this->assertEquals($response['headers']['status-code'], 200); - $this->assertStringContainsString('a_session_'.$this->getProject()['$id'].'=deleted', $response['headers']['set-cookie']); + $this->assertStringContainsString('a_session_' . $this->getProject()['$id'] . '=deleted', $response['headers']['set-cookie']); $this->assertEquals('[]', $response['headers']['x-fallback-cookies']); $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 401); @@ -277,7 +280,7 @@ class AccountCustomClientTest extends Scope public function testCreateJWT(): array { - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name (JWT)'; @@ -311,13 +314,13 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 201); $sessionId = $response['body']['$id']; - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -326,7 +329,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 201); @@ -354,11 +357,11 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 204); @@ -391,13 +394,13 @@ class AccountCustomClientTest extends Scope $this->assertNotEmpty($response['body']); $this->assertNotEmpty($response['body']['$id']); - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; \usleep(1000 * 30); // wait for 30ms to let the shutdown update accessedAt $apiKey = $this->getProject()['apiKey']; $userId = $response['body']['userId']; - $response = $this->client->call(Client::METHOD_GET, '/users/'.$userId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/' . $userId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -414,7 +417,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]); $this->assertEquals(401, $response['headers']['status-code']); @@ -434,7 +437,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'oldPassword' => '', ]); @@ -449,7 +452,7 @@ class AccountCustomClientTest extends Scope */ public function testUpdateAnonymousAccountEmail($session) { - $email = uniqid().'new@localhost.test'; + $email = uniqid() . 'new@localhost.test'; /** * Test for FAILURE @@ -458,7 +461,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'email' => $email, 'password' => '', @@ -472,7 +475,7 @@ class AccountCustomClientTest extends Scope public function testConvertAnonymousAccount() { $session = $this->testCreateAnonymousAccount(); - $email = uniqid().'new@localhost.test'; + $email = uniqid() . 'new@localhost.test'; $password = 'new-password'; /** @@ -485,14 +488,14 @@ class AccountCustomClientTest extends Scope ]), [ 'userId' => ID::unique(), 'email' => $email, - 'password' => $password, + 'password' => $password ]); $response = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'email' => $email, 'password' => $password, @@ -503,13 +506,13 @@ class AccountCustomClientTest extends Scope /** * Test for SUCCESS */ - $email = uniqid().'new@localhost.test'; + $email = uniqid() . 'new@localhost.test'; $response = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'email' => $email, 'password' => $password, @@ -537,11 +540,12 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'url' => 'http://localhost', + 'url' => 'http://localhost' ]); + $this->assertEquals($response['headers']['status-code'], 201); return []; @@ -561,18 +565,18 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); $userId = $response['body']['$id'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => 'console', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), [ 'provider' => $provider, 'appId' => $appId, @@ -582,17 +586,17 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['headers']['status-code'], 200); - $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/'.$provider, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'success' => 'http://localhost/v1/mock/tests/general/oauth2/success', 'failure' => 'http://localhost/v1/mock/tests/general/oauth2/failure', ]); - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('success', $response['body']['result']); @@ -601,7 +605,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -617,7 +621,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals(200, $response['headers']['status-code']); @@ -633,7 +637,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals(200, $response['headers']['status-code']); @@ -652,7 +656,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -660,11 +664,11 @@ class AccountCustomClientTest extends Scope $sessionID = $response['body']['$id']; - $response = $this->client->call(Client::METHOD_GET, '/account/sessions/'.$sessionID, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/account/sessions/' . $sessionID, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -674,7 +678,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 404); @@ -737,7 +741,7 @@ class AccountCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'search' => '"'.$email.'"', + 'search' => '"' . $email . '"', ]); @@ -762,6 +766,7 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['body']['users'][0]['email'], $email); } + public function testCreatePhone(): array { $number = '+123456789'; @@ -793,7 +798,7 @@ class AccountCustomClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]), [ - 'userId' => ID::unique(), + 'userId' => ID::unique() ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -869,13 +874,13 @@ class AccountCustomClientTest extends Scope $this->assertNotEmpty($response['body']['$id']); $this->assertNotEmpty($response['body']['userId']); - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -910,19 +915,19 @@ class AccountCustomClientTest extends Scope public function testConvertPhoneToPassword(array $data): array { $session = $data['session']; - $email = uniqid().'new@localhost.test'; + $email = uniqid() . 'new@localhost.test'; $password = 'new-password'; /** * Test for SUCCESS */ - $email = uniqid().'new@localhost.test'; + $email = uniqid() . 'new@localhost.test'; $response = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'email' => $email, 'password' => $password, @@ -964,10 +969,10 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'phone' => $newPhone, - 'password' => 'new-password', + 'password' => 'new-password' ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -992,7 +997,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), []); $this->assertEquals($response['headers']['status-code'], 400); @@ -1017,7 +1022,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); @@ -1031,7 +1036,7 @@ class AccountCustomClientTest extends Scope $smsRequest = $this->getLastRequest(); return \array_merge($data, [ - 'token' => $smsRequest['data']['message'], + 'token' => $smsRequest['data']['message'] ]); } @@ -1051,7 +1056,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'userId' => $id, 'secret' => $secret, @@ -1066,7 +1071,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'userId' => ID::custom('ewewe'), 'secret' => $secret, @@ -1078,7 +1083,7 @@ class AccountCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'userId' => $id, 'secret' => '999999', diff --git a/tests/e2e/Services/Account/AccountCustomServerTest.php b/tests/e2e/Services/Account/AccountCustomServerTest.php index 6c6c2df654..143277608d 100644 --- a/tests/e2e/Services/Account/AccountCustomServerTest.php +++ b/tests/e2e/Services/Account/AccountCustomServerTest.php @@ -15,7 +15,7 @@ class AccountCustomServerTest extends Scope public function testCreateAccount(): array { - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; diff --git a/tests/e2e/Services/Avatars/AvatarsBase.php b/tests/e2e/Services/Avatars/AvatarsBase.php index a7518d38af..e2ddc1a863 100644 --- a/tests/e2e/Services/Avatars/AvatarsBase.php +++ b/tests/e2e/Services/Avatars/AvatarsBase.php @@ -45,6 +45,7 @@ trait AvatarsBase /** * Test for FAILURE */ + $response = $this->client->call(Client::METHOD_GET, '/avatars/credit-cards/unknown', [ 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -107,6 +108,7 @@ trait AvatarsBase /** * Test for FAILURE */ + $response = $this->client->call(Client::METHOD_GET, '/avatars/browsers/unknown', [ 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -260,7 +262,7 @@ trait AvatarsBase $response = $this->client->call(Client::METHOD_GET, '/avatars/image', [ 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'url' => 'invalid://appwrite.io/images/apple.png', + 'url' => 'invalid://appwrite.io/images/apple.png' ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -347,7 +349,7 @@ trait AvatarsBase $this->assertEquals(400, $image->getImageWidth()); $this->assertEquals(400, $image->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/qr/qr-default.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/qr/qr-default.png')), strlen($response['body'])); $response = $this->client->call(Client::METHOD_GET, '/avatars/qr', [ 'x-appwrite-project' => $this->getProject()['$id'], @@ -365,7 +367,7 @@ trait AvatarsBase $this->assertEquals(200, $image->getImageWidth()); $this->assertEquals(200, $image->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/qr/qr-size-200.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/qr/qr-size-200.png')), strlen($response['body'])); $response = $this->client->call(Client::METHOD_GET, '/avatars/qr', [ 'x-appwrite-project' => $this->getProject()['$id'], @@ -384,7 +386,7 @@ trait AvatarsBase $this->assertEquals(200, $image->getImageWidth()); $this->assertEquals(200, $image->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/qr/qr-size-200-margin-10.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/qr/qr-size-200-margin-10.png')), strlen($response['body'])); $response = $this->client->call(Client::METHOD_GET, '/avatars/qr', [ 'x-appwrite-project' => $this->getProject()['$id'], @@ -400,7 +402,7 @@ trait AvatarsBase $this->assertEquals(200, $image->getImageWidth()); $this->assertEquals(200, $image->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/qr/qr-size-200-margin-10.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/qr/qr-size-200-margin-10.png')), strlen($response['body'])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('attachment; filename="qr.png"', $response['headers']['content-disposition']); @@ -446,6 +448,7 @@ trait AvatarsBase return []; } + public function testGetInitials() { /** @@ -526,11 +529,11 @@ trait AvatarsBase $image = new \Imagick(); $image->readImageBlob($response['body']); - $original = new \Imagick(__DIR__.'/../../../resources/initials.png'); + $original = new \Imagick(__DIR__ . '/../../../resources/initials.png'); $this->assertEquals($image->getImageWidth(), $original->getImageWidth()); $this->assertEquals($image->getImageHeight(), $original->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $this->assertEquals(strlen(\file_get_contents(__DIR__.'/../../../resources/initials.png')), strlen($response['body'])); + $this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/initials.png')), strlen($response['body'])); } } diff --git a/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php b/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php index bfd17ef1e9..a59d694114 100644 --- a/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php +++ b/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Avatars; -use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\SideClient; class AvatarsConsoleClientTest extends Scope diff --git a/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php b/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php index edf09d5ba1..dc399971a0 100644 --- a/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php +++ b/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Avatars; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; class AvatarsCustomClientTest extends Scope diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 9bc081d2ab..c2c1c70bd6 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -5,11 +5,12 @@ namespace Tests\E2E\Services\Databases; use Appwrite\Extend\Exception; use Tests\E2E\Client; use Utopia\Database\Database; -use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; use Utopia\Database\Validator\Datetime as DatetimeValidator; trait DatabasesBase @@ -22,10 +23,10 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'databaseId' => ID::unique(), - 'name' => 'Test Database', + 'name' => 'Test Database' ]); $this->assertNotEmpty($database['body']['$id']); @@ -44,10 +45,10 @@ trait DatabasesBase /** * Test for SUCCESS */ - $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -60,10 +61,10 @@ trait DatabasesBase $this->assertEquals(201, $movies['headers']['status-code']); $this->assertEquals($movies['body']['name'], 'Movies'); - $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -92,10 +93,10 @@ trait DatabasesBase /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$data['moviesId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Movies', 'enabled' => false, @@ -106,7 +107,7 @@ trait DatabasesBase $this->assertFalse($response['body']['enabled']); if ($this->getSide() === 'client') { - $responseCreateDocument = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $responseCreateDocument = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -123,14 +124,14 @@ trait DatabasesBase $this->assertEquals(404, $responseCreateDocument['headers']['status-code']); - $responseListDocument = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $responseListDocument = $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())); $this->assertEquals(404, $responseListDocument['headers']['status-code']); - $responseGetDocument = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/someID', array_merge([ + $responseGetDocument = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/someID', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -138,10 +139,10 @@ trait DatabasesBase $this->assertEquals(404, $responseGetDocument['headers']['status-code']); } - $response = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$data['moviesId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Movies', 'enabled' => true, @@ -159,20 +160,20 @@ trait DatabasesBase { $databaseId = $data['databaseId']; - $title = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/string', array_merge([ + $title = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); - $description = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/string', array_merge([ + $description = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'description', 'size' => 512, @@ -180,10 +181,10 @@ trait DatabasesBase 'default' => '', ]); - $tagline = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/string', array_merge([ + $tagline = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'tagline', 'size' => 512, @@ -191,10 +192,10 @@ trait DatabasesBase 'default' => '', ]); - $releaseYear = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/integer', array_merge([ + $releaseYear = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'releaseYear', 'required' => true, @@ -202,20 +203,20 @@ trait DatabasesBase 'max' => 2200, ]); - $duration = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/integer', array_merge([ + $duration = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'duration', 'required' => false, 'min' => 60, ]); - $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/string', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'actors', 'size' => 256, @@ -223,25 +224,25 @@ trait DatabasesBase 'array' => true, ]); - $datetime = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/datetime', array_merge([ + $datetime = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'birthDay', 'required' => false, ]); - $relationship = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes/relationship', array_merge([ + $relationship = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $data['actorsId'], 'type' => 'oneToMany', 'twoWay' => true, 'key' => 'starringActors', - 'twoWayKey' => 'movie', + 'twoWayKey' => 'movie' ]); $this->assertEquals(202, $title['headers']['status-code']); @@ -297,10 +298,10 @@ trait DatabasesBase // wait for database worker to create attributes sleep(2); - $movies = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'], array_merge([ + $movies = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertIsArray($movies['body']['attributes']); @@ -323,7 +324,7 @@ trait DatabasesBase public function testListAttributes(array $data): void { $databaseId = $data['databaseId']; - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -332,7 +333,7 @@ trait DatabasesBase ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(2, \count($response['body']['attributes'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/attributes', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -349,10 +350,10 @@ trait DatabasesBase public function testAttributeResponseModels(array $data): array { $databaseId = $data['databaseId']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Response Models', @@ -365,12 +366,12 @@ trait DatabasesBase $collectionId = $collection['body']['$id']; - $attributesPath = '/databases/'.$databaseId."/collections/{$collectionId}/attributes"; + $attributesPath = "/databases/" . $databaseId . "/collections/{$collectionId}/attributes"; - $string = $this->client->call(Client::METHOD_POST, $attributesPath.'/string', array_merge([ + $string = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'string', 'size' => 16, @@ -378,20 +379,20 @@ trait DatabasesBase 'default' => 'default', ]); - $email = $this->client->call(Client::METHOD_POST, $attributesPath.'/email', array_merge([ + $email = $this->client->call(Client::METHOD_POST, $attributesPath . '/email', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'email', 'required' => false, 'default' => 'default@example.com', ]); - $enum = $this->client->call(Client::METHOD_POST, $attributesPath.'/enum', array_merge([ + $enum = $this->client->call(Client::METHOD_POST, $attributesPath . '/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'enum', 'elements' => ['yes', 'no', 'maybe'], @@ -399,80 +400,80 @@ trait DatabasesBase 'default' => 'maybe', ]); - $ip = $this->client->call(Client::METHOD_POST, $attributesPath.'/ip', array_merge([ + $ip = $this->client->call(Client::METHOD_POST, $attributesPath . '/ip', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'ip', 'required' => false, 'default' => '192.0.2.0', ]); - $url = $this->client->call(Client::METHOD_POST, $attributesPath.'/url', array_merge([ + $url = $this->client->call(Client::METHOD_POST, $attributesPath . '/url', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'url', 'required' => false, 'default' => 'http://example.com', ]); - $integer = $this->client->call(Client::METHOD_POST, $attributesPath.'/integer', array_merge([ + $integer = $this->client->call(Client::METHOD_POST, $attributesPath . '/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'integer', 'required' => false, 'min' => 1, 'max' => 5, - 'default' => 3, + 'default' => 3 ]); - $float = $this->client->call(Client::METHOD_POST, $attributesPath.'/float', array_merge([ + $float = $this->client->call(Client::METHOD_POST, $attributesPath . '/float', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'float', 'required' => false, 'min' => 1.5, 'max' => 5.5, - 'default' => 3.5, + 'default' => 3.5 ]); - $boolean = $this->client->call(Client::METHOD_POST, $attributesPath.'/boolean', array_merge([ + $boolean = $this->client->call(Client::METHOD_POST, $attributesPath . '/boolean', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'boolean', 'required' => false, 'default' => true, ]); - $datetime = $this->client->call(Client::METHOD_POST, $attributesPath.'/datetime', array_merge([ + $datetime = $this->client->call(Client::METHOD_POST, $attributesPath . '/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'datetime', 'required' => false, 'default' => null, ]); - $relationship = $this->client->call(Client::METHOD_POST, $attributesPath.'/relationship', array_merge([ + $relationship = $this->client->call(Client::METHOD_POST, $attributesPath . '/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $data['actorsId'], 'type' => 'oneToMany', 'twoWay' => true, 'key' => 'relationship', - 'twoWayKey' => 'twoWayKey', + 'twoWayKey' => 'twoWayKey' ]); $this->assertEquals(202, $string['headers']['status-code']); @@ -562,64 +563,64 @@ trait DatabasesBase // Wait for database worker to create attributes sleep(5); - $stringResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$string['body']['key'], array_merge([ + $stringResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $string['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $emailResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$email['body']['key'], array_merge([ + $emailResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $email['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $enumResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$enum['body']['key'], array_merge([ + $enumResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $enum['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $ipResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$ip['body']['key'], array_merge([ + $ipResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $ip['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $urlResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$url['body']['key'], array_merge([ + $urlResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $url['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $integerResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$integer['body']['key'], array_merge([ + $integerResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $integer['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $floatResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$float['body']['key'], array_merge([ + $floatResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $float['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $booleanResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$boolean['body']['key'], array_merge([ + $booleanResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $boolean['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $datetimeResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$datetime['body']['key'], array_merge([ + $datetimeResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $datetime['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $relationshipResponse = $this->client->call(Client::METHOD_GET, $attributesPath.'/'.$relationship['body']['key'], array_merge([ + $relationshipResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $relationship['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $stringResponse['headers']['status-code']); @@ -715,10 +716,10 @@ trait DatabasesBase $this->assertEquals($relationship['body']['twoWay'], $relationshipResponse['body']['twoWay']); $this->assertEquals($relationship['body']['twoWayKey'], $relationshipResponse['body']['twoWayKey']); - $attributes = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes', array_merge([ + $attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $attributes['headers']['status-code']); @@ -811,10 +812,10 @@ trait DatabasesBase $this->assertEquals($relationshipResponse['body']['twoWay'], $attributes[9]['twoWay']); $this->assertEquals($relationshipResponse['body']['twoWayKey'], $attributes[9]['twoWayKey']); - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -910,10 +911,10 @@ trait DatabasesBase /** * Test for FAILURE */ - $badEnum = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ + $badEnum = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'enum', 'elements' => ['yes', 'no', ''], @@ -934,10 +935,10 @@ trait DatabasesBase { $databaseId = $data['databaseId']; - $titleIndex = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $titleIndex = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'titleIndex', 'type' => 'fulltext', @@ -950,10 +951,10 @@ trait DatabasesBase $this->assertCount(1, $titleIndex['body']['attributes']); $this->assertEquals('title', $titleIndex['body']['attributes'][0]); - $releaseYearIndex = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $releaseYearIndex = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'releaseYear', 'type' => 'key', @@ -966,10 +967,10 @@ trait DatabasesBase $this->assertCount(1, $releaseYearIndex['body']['attributes']); $this->assertEquals('releaseYear', $releaseYearIndex['body']['attributes'][0]); - $releaseWithDate = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $releaseWithDate = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'releaseYearDated', 'type' => 'key', @@ -987,10 +988,10 @@ trait DatabasesBase // wait for database worker to create index sleep(2); - $movies = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'], array_merge([ + $movies = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), []); $this->assertIsArray($movies['body']['indexes']); @@ -1002,10 +1003,10 @@ trait DatabasesBase $this->assertEquals('available', $movies['body']['indexes'][1]['status']); $this->assertEquals('available', $movies['body']['indexes'][2]['status']); - $releaseWithDate = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $releaseWithDate = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'birthDay', 'type' => 'key', @@ -1019,10 +1020,10 @@ trait DatabasesBase $this->assertEquals('birthDay', $releaseWithDate['body']['attributes'][0]); // Test for failure - $fulltextReleaseYear = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $fulltextReleaseYear = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'releaseYearDated', 'type' => 'fulltext', @@ -1032,10 +1033,10 @@ trait DatabasesBase $this->assertEquals(400, $fulltextReleaseYear['headers']['status-code']); $this->assertEquals($fulltextReleaseYear['body']['message'], 'Attribute "releaseYear" cannot be part of a FULLTEXT index, must be of type string'); - $noAttributes = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $noAttributes = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'none', 'type' => 'key', @@ -1045,10 +1046,10 @@ trait DatabasesBase $this->assertEquals(400, $noAttributes['headers']['status-code']); $this->assertEquals($noAttributes['body']['message'], 'No attributes provided for index'); - $duplicates = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $duplicates = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'duplicate', 'type' => 'fulltext', @@ -1058,7 +1059,7 @@ trait DatabasesBase $this->assertEquals(400, $duplicates['headers']['status-code']); $this->assertEquals($duplicates['body']['message'], 'Duplicate attributes provided'); - $tooLong = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $tooLong = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -1080,7 +1081,7 @@ trait DatabasesBase public function testListIndexes(array $data): void { $databaseId = $data['databaseId']; - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -1089,7 +1090,7 @@ trait DatabasesBase ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(2, \count($response['body']['indexes'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -1106,7 +1107,7 @@ trait DatabasesBase public function testCreateDocument(array $data): array { $databaseId = $data['databaseId']; - $document1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1118,16 +1119,16 @@ trait DatabasesBase 'actors' => [ 'Chris Evans', 'Samuel Jackson', - ], + ] ], 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); - $document2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $document2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1140,16 +1141,16 @@ trait DatabasesBase 'Tom Holland', 'Zendaya Maree Stoermer', 'Samuel Jackson', - ], + ] ], 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); - $document3 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $document3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1168,10 +1169,10 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); - $document4 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $document4 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1183,7 +1184,7 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); $this->assertEquals(201, $document1['headers']['status-code']); @@ -1231,7 +1232,7 @@ trait DatabasesBase $this->assertEquals(400, $document4['headers']['status-code']); // Delete document 4 with incomplete path - $this->assertEquals(404, $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/', array_merge([ + $this->assertEquals(404, $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()))['headers']['status-code']); @@ -1245,7 +1246,7 @@ trait DatabasesBase public function testListDocuments(array $data): array { $databaseId = $data['databaseId']; - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1267,7 +1268,7 @@ trait DatabasesBase $this->assertEquals($databaseId, $document['$databaseId']); } - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1289,10 +1290,10 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'databaseId' => ID::custom('default'), - 'name' => 'Default', + 'name' => 'Default' ]); $this->assertNotEmpty($database['body']['$id']); @@ -1301,10 +1302,11 @@ trait DatabasesBase /** * Test for SUCCESS */ + $movies = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -1326,7 +1328,8 @@ trait DatabasesBase /** * Test for SUCCESS */ - $documents = $this->client->call(Client::METHOD_GET, '/database/collections/'.$data['moviesId'].'/documents', array_merge([ + + $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1344,7 +1347,7 @@ trait DatabasesBase { $databaseId = $data['databaseId']; foreach ($data['documents'] as $document) { - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$document['$collectionId'].'/documents/'.$document['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $document['$collectionId'] . '/documents/' . $document['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1370,7 +1373,7 @@ trait DatabasesBase $databaseId = $data['databaseId']; $document = $data['documents'][0]; - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$document['$collectionId'].'/documents/'.$document['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $document['$collectionId'] . '/documents/' . $document['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1394,7 +1397,7 @@ trait DatabasesBase /** * Test after without order. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $base = $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())); @@ -1405,11 +1408,11 @@ trait DatabasesBase $this->assertEquals('Spider-Man: Homecoming', $base['body']['documents'][2]['title']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['cursorAfter("'.$base['body']['documents'][0]['$id'].'")'], + 'queries' => ['cursorAfter("' . $base['body']['documents'][0]['$id'] . '")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1417,11 +1420,11 @@ trait DatabasesBase $this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][1]['$id']); $this->assertCount(2, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['cursorAfter("'.$base['body']['documents'][2]['$id'].'")'], + 'queries' => ['cursorAfter("' . $base['body']['documents'][2]['$id'] . '")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1430,7 +1433,7 @@ trait DatabasesBase /** * Test with ASC order and after. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $base = $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()), [ @@ -1443,11 +1446,11 @@ trait DatabasesBase $this->assertEquals(2019, $base['body']['documents'][2]['releaseYear']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['cursorAfter("'.$base['body']['documents'][1]['$id'].'")', 'orderAsc("releaseYear")'], + 'queries' => ['cursorAfter("' . $base['body']['documents'][1]['$id'] . '")', 'orderAsc("releaseYear")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1457,7 +1460,7 @@ trait DatabasesBase /** * Test with DESC order and after. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $base = $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()), [ @@ -1470,11 +1473,11 @@ trait DatabasesBase $this->assertEquals(2019, $base['body']['documents'][0]['releaseYear']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['cursorAfter("'.$base['body']['documents'][1]['$id'].'")', 'orderDesc("releaseYear")'], + 'queries' => ['cursorAfter("' . $base['body']['documents'][1]['$id'] . '")', 'orderDesc("releaseYear")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1484,7 +1487,7 @@ trait DatabasesBase /** * Test after with unknown document. */ - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1505,7 +1508,7 @@ trait DatabasesBase /** * Test before without order. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $base = $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())); @@ -1516,11 +1519,11 @@ trait DatabasesBase $this->assertEquals('Spider-Man: Homecoming', $base['body']['documents'][2]['title']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['cursorBefore("'.$base['body']['documents'][2]['$id'].'")'], + 'queries' => ['cursorBefore("' . $base['body']['documents'][2]['$id'] . '")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1528,11 +1531,11 @@ trait DatabasesBase $this->assertEquals($base['body']['documents'][1]['$id'], $documents['body']['documents'][1]['$id']); $this->assertCount(2, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['cursorBefore("'.$base['body']['documents'][0]['$id'].'")'], + 'queries' => ['cursorBefore("' . $base['body']['documents'][0]['$id'] . '")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1541,7 +1544,7 @@ trait DatabasesBase /** * Test with ASC order and after. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $base = $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()), [ @@ -1554,11 +1557,11 @@ trait DatabasesBase $this->assertEquals(2019, $base['body']['documents'][2]['releaseYear']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['cursorBefore("'.$base['body']['documents'][1]['$id'].'")', 'orderAsc("releaseYear")'], + 'queries' => ['cursorBefore("' . $base['body']['documents'][1]['$id'] . '")', 'orderAsc("releaseYear")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1568,7 +1571,7 @@ trait DatabasesBase /** * Test with DESC order and after. */ - $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $base = $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()), [ @@ -1581,11 +1584,11 @@ trait DatabasesBase $this->assertEquals(2019, $base['body']['documents'][0]['releaseYear']); $this->assertCount(3, $base['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['cursorBefore("'.$base['body']['documents'][1]['$id'].'")', 'orderDesc("releaseYear")'], + 'queries' => ['cursorBefore("' . $base['body']['documents'][1]['$id'] . '")', 'orderDesc("releaseYear")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -1601,7 +1604,7 @@ trait DatabasesBase public function testListDocumentsLimitAndOffset(array $data): array { $databaseId = $data['databaseId']; - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1612,7 +1615,7 @@ trait DatabasesBase $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']); $this->assertCount(1, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1633,7 +1636,7 @@ trait DatabasesBase public function testDocumentsListQueries(array $data): array { $databaseId = $data['databaseId']; - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1644,18 +1647,18 @@ trait DatabasesBase $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']); $this->assertCount(1, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['equal("$id", "'.$documents['body']['documents'][0]['$id'].'")'], + 'queries' => ['equal("$id", "' . $documents['body']['documents'][0]['$id'] . '")'], ]); $this->assertEquals(200, $documents['headers']['status-code']); $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']); $this->assertCount(1, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1666,7 +1669,7 @@ trait DatabasesBase $this->assertEquals(2017, $documents['body']['documents'][0]['releaseYear']); $this->assertCount(1, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1678,7 +1681,7 @@ trait DatabasesBase $this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']); $this->assertCount(2, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1688,7 +1691,7 @@ trait DatabasesBase $this->assertCount(1, $documents['body']['documents']); $this->assertEquals('Captain America', $documents['body']['documents'][0]['title']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1699,7 +1702,7 @@ trait DatabasesBase $this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['title']); $this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['title']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1708,7 +1711,7 @@ trait DatabasesBase $this->assertCount(3, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1717,7 +1720,7 @@ trait DatabasesBase $this->assertCount(0, $documents['body']['documents']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1725,7 +1728,7 @@ trait DatabasesBase ]); $this->assertEquals(200, $documents['headers']['status-code']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1746,11 +1749,11 @@ trait DatabasesBase $conditions[] = $i; } - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['equal("releaseYear", ['.implode(',', $conditions).'])'], + 'queries' => ['equal("releaseYear", [' . implode(',', $conditions) . '])'], ]); $this->assertEquals(400, $documents['headers']['status-code']); @@ -1758,19 +1761,19 @@ trait DatabasesBase $conditions = []; for ($i = 0; $i < 101; $i++) { - $conditions[] = '['.$i.'] Too long title to cross 2k chars query limit'; + $conditions[] = "[" . $i . "] Too long title to cross 2k chars query limit"; } - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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' => ['search("title", '.implode(',', $conditions).')'], + 'queries' => ['search("title", ' . implode(',', $conditions) . ')'], ]); $this->assertEquals(400, $documents['headers']['status-code']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $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()), [ @@ -1788,7 +1791,7 @@ trait DatabasesBase public function testUpdateDocument(array $data): array { $databaseId = $data['databaseId']; - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1798,7 +1801,7 @@ trait DatabasesBase 'releaseYear' => 2017, 'birthDay' => '1976-06-12 14:12:55', 'actors' => [], - '$createdAt' => 5, // Should be ignored + '$createdAt' => 5 // Should be ignored ], 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), @@ -1822,7 +1825,7 @@ trait DatabasesBase $this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $document['body']['$permissions']); $this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $document['body']['$permissions']); - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1847,7 +1850,7 @@ trait DatabasesBase $this->assertContains(Permission::update(Role::users()), $document['body']['$permissions']); $this->assertContains(Permission::delete(Role::users()), $document['body']['$permissions']); - $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1861,7 +1864,7 @@ trait DatabasesBase $this->assertEquals($document['body']['title'], 'Thor: Ragnarok'); $this->assertEquals($document['body']['releaseYear'], 2017); - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-timestamp' => DateTime::formatTz(DateTime::now()), @@ -1876,7 +1879,8 @@ trait DatabasesBase /** * Test for failure */ - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-timestamp' => 'invalid', @@ -1890,7 +1894,7 @@ trait DatabasesBase $this->assertEquals('Invalid X-Appwrite-Timestamp header value', $response['body']['message']); $this->assertEquals(Exception::GENERAL_ARGUMENT_INVALID, $response['body']['type']); - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-timestamp' => DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -1000)), @@ -1913,7 +1917,7 @@ trait DatabasesBase public function testDeleteDocument(array $data): array { $databaseId = $data['databaseId']; - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1928,28 +1932,28 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); $id = $document['body']['$id']; $this->assertEquals(201, $document['headers']['status-code']); - $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $document['headers']['status-code']); - $document = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(204, $document['headers']['status-code']); - $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1964,7 +1968,7 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'InvalidDocumentDatabase', @@ -1973,10 +1977,10 @@ trait DatabasesBase $this->assertEquals('InvalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'invalidDocumentStructure', @@ -1992,48 +1996,48 @@ trait DatabasesBase $collectionId = $collection['body']['$id']; - $email = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email', array_merge([ + $email = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'email', 'required' => false, ]); - $enum = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ + $enum = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'enum', 'elements' => ['yes', 'no', 'maybe'], 'required' => false, ]); - $ip = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip', array_merge([ + $ip = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'ip', 'required' => false, ]); - $url = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url', array_merge([ + $url = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'url', 'size' => 256, 'required' => false, ]); - $range = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ + $range = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'range', 'required' => false, @@ -2042,10 +2046,10 @@ trait DatabasesBase ]); // TODO@kodumbeats min and max are rounded in error message - $floatRange = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float', array_merge([ + $floatRange = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'floatRange', 'required' => false, @@ -2053,10 +2057,10 @@ trait DatabasesBase 'max' => 1.4, ]); - $probability = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float', array_merge([ + $probability = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'probability', 'required' => false, @@ -2065,20 +2069,20 @@ trait DatabasesBase 'max' => 1, ]); - $upperBound = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ + $upperBound = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'upperBound', 'required' => false, 'max' => 10, ]); - $lowerBound = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ + $lowerBound = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'lowerBound', 'required' => false, @@ -2088,9 +2092,10 @@ trait DatabasesBase /** * Test for failure */ - $invalidRange = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ + + $invalidRange = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'invalidRange', 'required' => false, @@ -2098,9 +2103,9 @@ trait DatabasesBase 'max' => 3, ]); - $defaultArray = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ + $defaultArray = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'defaultArray', 'required' => false, @@ -2108,54 +2113,54 @@ trait DatabasesBase 'array' => true, ]); - $defaultRequired = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ + $defaultRequired = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'attributeId' => ID::custom('defaultRequired'), 'required' => true, - 'default' => 12, + 'default' => 12 ]); - $enumDefault = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ + $enumDefault = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'attributeId' => ID::custom('enumDefault'), 'elements' => ['north', 'west'], - 'default' => 'south', + 'default' => 'south' ]); - $enumDefaultStrict = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ + $enumDefaultStrict = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'attributeId' => ID::custom('enumDefault'), 'elements' => ['north', 'west'], - 'default' => 'NORTH', + 'default' => 'NORTH' ]); - $goodDatetime = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime', array_merge([ + $goodDatetime = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'birthDay', 'required' => false, - 'default' => null, + 'default' => null ]); - $datetimeDefault = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime', array_merge([ + $datetimeDefault = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'badBirthDay', 'required' => false, - 'default' => 'bad', + 'default' => 'bad' ]); $this->assertEquals(202, $email['headers']['status-code']); @@ -2179,7 +2184,7 @@ trait DatabasesBase // wait for worker to add attributes sleep(3); - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -2190,7 +2195,8 @@ trait DatabasesBase /** * Test for successful validation */ - $goodEmail = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + + $goodEmail = $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()), [ @@ -2202,10 +2208,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $goodEnum = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $goodEnum = $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()), [ @@ -2217,10 +2223,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $goodIp = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $goodIp = $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()), [ @@ -2232,10 +2238,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $goodUrl = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $goodUrl = $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()), [ @@ -2247,10 +2253,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $goodRange = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $goodRange = $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()), [ @@ -2262,10 +2268,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $goodFloatRange = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $goodFloatRange = $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()), [ @@ -2277,10 +2283,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $goodProbability = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $goodProbability = $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()), [ @@ -2292,10 +2298,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $notTooHigh = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $notTooHigh = $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()), [ @@ -2307,10 +2313,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $notTooLow = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $notTooLow = $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()), [ @@ -2322,7 +2328,7 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); $this->assertEquals(201, $goodEmail['headers']['status-code']); @@ -2339,7 +2345,7 @@ trait DatabasesBase * Test that custom validators reject documents */ - $badEmail = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $badEmail = $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()), [ @@ -2351,10 +2357,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $badEnum = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $badEnum = $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()), [ @@ -2366,10 +2372,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $badIp = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $badIp = $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()), [ @@ -2381,10 +2387,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $badUrl = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $badUrl = $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()), [ @@ -2396,10 +2402,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $badRange = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $badRange = $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()), [ @@ -2411,10 +2417,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $badFloatRange = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $badFloatRange = $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()), [ @@ -2426,10 +2432,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $badProbability = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $badProbability = $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()), [ @@ -2441,10 +2447,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $tooHigh = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $tooHigh = $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()), [ @@ -2456,10 +2462,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $tooLow = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $tooLow = $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()), [ @@ -2471,10 +2477,10 @@ trait DatabasesBase Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); - $badTime = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $badTime = $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()), [ @@ -2482,8 +2488,8 @@ trait DatabasesBase 'data' => [ 'birthDay' => '2020-10-10 27:30:10+01:00', ], - 'read' => ['user:'.$this->getUser()['$id']], - 'write' => ['user:'.$this->getUser()['$id']], + 'read' => ['user:' . $this->getUser()['$id']], + 'write' => ['user:' . $this->getUser()['$id']], ]); $this->assertEquals(400, $badEmail['headers']['status-code']); @@ -2513,7 +2519,7 @@ trait DatabasesBase public function testDefaultPermissions(array $data): array { $databaseId = $data['databaseId']; - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2546,7 +2552,7 @@ trait DatabasesBase // Updated Permissions - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2557,7 +2563,7 @@ trait DatabasesBase ], 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), + Permission::update(Role::user($this->getUser()['$id'])) ], ]); @@ -2574,7 +2580,7 @@ trait DatabasesBase Permission::update(Role::user($this->getUser()['$id'])), ], $document['body']['$permissions']); - $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2591,7 +2597,7 @@ trait DatabasesBase // Reset Permissions - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2610,7 +2616,7 @@ trait DatabasesBase $this->assertEquals([], $document['body']['$permissions']); // Check client side can no longer read the document. - $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2632,7 +2638,7 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'EnforceCollectionAndDocumentPermissions', @@ -2642,10 +2648,10 @@ trait DatabasesBase $databaseId = $database['body']['$id']; $user = $this->getUser()['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'enforceCollectionAndDocumentPermissions', @@ -2666,10 +2672,10 @@ trait DatabasesBase sleep(2); - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'attribute', 'size' => 64, @@ -2682,10 +2688,10 @@ trait DatabasesBase // wait for db to add attribute sleep(2); - $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'key_attribute', 'type' => 'key', @@ -2698,7 +2704,7 @@ trait DatabasesBase // wait for db to add attribute sleep(2); - $document1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $document1 = $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()), [ @@ -2710,12 +2716,12 @@ trait DatabasesBase Permission::read(Role::user($user)), Permission::update(Role::user($user)), Permission::delete(Role::user($user)), - ], + ] ]); $this->assertEquals(201, $document1['headers']['status-code']); - $document2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $document2 = $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()), [ @@ -2726,15 +2732,15 @@ trait DatabasesBase 'permissions' => [ Permission::update(Role::user($user)), Permission::delete(Role::user($user)), - ], + ] ]); $this->assertEquals(201, $document2['headers']['status-code']); - $document3 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ + $document3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'documentId' => ID::unique(), 'data' => [ @@ -2748,7 +2754,7 @@ trait DatabasesBase $this->assertEquals(201, $document3['headers']['status-code']); - $documentsUser1 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $documentsUser1 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2757,7 +2763,7 @@ trait DatabasesBase $this->assertEquals(3, $documentsUser1['body']['total']); $this->assertCount(3, $documentsUser1['body']['documents']); - $document3GetWithCollectionRead = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document3['body']['$id'], array_merge([ + $document3GetWithCollectionRead = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document3['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2765,7 +2771,7 @@ trait DatabasesBase // Current user has read permission on the collection so can get any document $this->assertEquals(200, $document3GetWithCollectionRead['headers']['status-code']); - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; $this->client->call(Client::METHOD_POST, '/account', [ @@ -2786,33 +2792,33 @@ trait DatabasesBase 'email' => $email, 'password' => $password, ]); - $session2 = $this->client->parseCookie((string) $session2['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session2 = $this->client->parseCookie((string)$session2['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; - $document3GetWithDocumentRead = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document3['body']['$id'], [ + $document3GetWithDocumentRead = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document3['body']['$id'], [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, ]); // Current user has no collection permissions but has read permission for this document $this->assertEquals(200, $document3GetWithDocumentRead['headers']['status-code']); - $document2GetFailure = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document2['body']['$id'], [ + $document2GetFailure = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document2['body']['$id'], [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, ]); // Current user has no collection or document permissions for this document $this->assertEquals(404, $document2GetFailure['headers']['status-code']); - $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ + $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, ]); // Current user has no collection permissions but has read permission for one document @@ -2825,7 +2831,7 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'EnforceCollectionPermissions', @@ -2835,10 +2841,10 @@ trait DatabasesBase $databaseId = $database['body']['$id']; $user = $this->getUser()['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'enforceCollectionPermissions', @@ -2858,10 +2864,10 @@ trait DatabasesBase sleep(2); - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'attribute', 'size' => 64, @@ -2874,10 +2880,10 @@ trait DatabasesBase // wait for db to add attribute sleep(2); - $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'key_attribute', 'type' => 'key', @@ -2890,7 +2896,7 @@ trait DatabasesBase // wait for db to add attribute sleep(2); - $document1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $document1 = $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()), [ @@ -2902,12 +2908,12 @@ trait DatabasesBase Permission::read(Role::user($user)), Permission::update(Role::user($user)), Permission::delete(Role::user($user)), - ], + ] ]); $this->assertEquals(201, $document1['headers']['status-code']); - $document2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $document2 = $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()), [ @@ -2918,15 +2924,15 @@ trait DatabasesBase 'permissions' => [ Permission::update(Role::user($user)), Permission::delete(Role::user($user)), - ], + ] ]); $this->assertEquals(201, $document2['headers']['status-code']); - $document3 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ + $document3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'documentId' => ID::unique(), 'data' => [ @@ -2940,7 +2946,7 @@ trait DatabasesBase $this->assertEquals(201, $document3['headers']['status-code']); - $documentsUser1 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $documentsUser1 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2949,7 +2955,7 @@ trait DatabasesBase $this->assertEquals(3, $documentsUser1['body']['total']); $this->assertCount(3, $documentsUser1['body']['documents']); - $document3GetWithCollectionRead = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document3['body']['$id'], array_merge([ + $document3GetWithCollectionRead = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document3['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2957,7 +2963,7 @@ trait DatabasesBase // Current user has read permission on the collection so can get any document $this->assertEquals(200, $document3GetWithCollectionRead['headers']['status-code']); - $email = uniqid().'user2@localhost.test'; + $email = uniqid() . 'user2@localhost.test'; $password = 'password'; $name = 'User Name'; $this->client->call(Client::METHOD_POST, '/account', [ @@ -2978,43 +2984,43 @@ trait DatabasesBase 'email' => $email, 'password' => $password, ]); - $session2 = $this->client->parseCookie((string) $session2['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session2 = $this->client->parseCookie((string)$session2['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; - $document3GetWithDocumentRead = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents/'.$document3['body']['$id'], [ + $document3GetWithDocumentRead = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document3['body']['$id'], [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, ]); // Current user has no collection permissions and document permissions are disabled $this->assertEquals(404, $document3GetWithDocumentRead['headers']['status-code']); - $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ + $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, ]); // Current user has no collection permissions and document permissions are disabled $this->assertEquals(404, $documentsUser2['headers']['status-code']); // Enable document permissions - $collection = $this->client->call(CLient::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$collectionId, [ + $collection = $this->client->call(CLient::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'name' => $collection['body']['name'], 'documentSecurity' => true, ]); - $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', [ + $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session2, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, ]); // Current user has no collection permissions read access to one document @@ -3028,10 +3034,10 @@ trait DatabasesBase public function testUniqueIndexDuplicate(array $data): array { $databaseId = $data['databaseId']; - $uniqueIndex = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/indexes', array_merge([ + $uniqueIndex = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'unique_title', 'type' => 'unique', @@ -3043,7 +3049,7 @@ trait DatabasesBase sleep(2); // test for failure - $duplicate = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $duplicate = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3054,19 +3060,19 @@ trait DatabasesBase 'actors' => [ 'Chris Evans', 'Samuel Jackson', - ], + ] ], 'permissions' => [ Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); $this->assertEquals(409, $duplicate['headers']['status-code']); // Test for exception when updating document to conflict - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3077,19 +3083,19 @@ trait DatabasesBase 'actors' => [ 'Chris Evans', 'Samuel Jackson', - ], + ] ], 'permissions' => [ Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); $this->assertEquals(201, $document['headers']['status-code']); // Test for exception when updating document to conflict - $duplicate = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/documents/'.$document['body']['$id'], array_merge([ + $duplicate = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $document['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3100,13 +3106,13 @@ trait DatabasesBase 'actors' => [ 'Chris Evans', 'Samuel Jackson', - ], + ] ], 'permissions' => [ Permission::read(Role::user(ID::custom($this->getUser()['$id']))), Permission::update(Role::user(ID::custom($this->getUser()['$id']))), Permission::delete(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); $this->assertEquals(409, $duplicate['headers']['status-code']); @@ -3125,15 +3131,15 @@ trait DatabasesBase ], $this->getHeaders()) : [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]; - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$data['databaseId'].'/collections/'.$data['moviesId'].'/documents', $headers, [ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['moviesId'] . '/documents', $headers, [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Creation Date Test', - 'releaseYear' => 2000, - ], + 'releaseYear' => 2000 + ] ]); $this->assertEquals($document['body']['title'], 'Creation Date Test'); @@ -3144,10 +3150,10 @@ trait DatabasesBase \sleep(1); - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$data['databaseId'].'/collections/'.$data['moviesId'].'/documents/'.$documentId, $headers, [ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, $headers, [ 'data' => [ 'title' => 'Updated Date Test', - ], + ] ]); $updatedAtSecond = $document['body']['$updatedAt']; @@ -3158,12 +3164,12 @@ trait DatabasesBase \sleep(1); - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$data['databaseId'].'/collections/'.$data['moviesId'].'/documents/'.$documentId, $headers, [ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, $headers, [ 'data' => [ 'title' => 'Again Updated Date Test', '$createdAt' => '2022-08-01 13:09:23.040', // $createdAt is not updatable - '$updatedAt' => '2022-08-01 13:09:23.050', // system will update it not api - ], + '$updatedAt' => '2022-08-01 13:09:23.050' // system will update it not api + ] ]); $this->assertEquals($document['body']['title'], 'Again Updated Date Test'); @@ -3182,7 +3188,7 @@ trait DatabasesBase $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'Empty Permissions', @@ -3192,10 +3198,10 @@ trait DatabasesBase $databaseId = $database['body']['$id']; // Create collection - $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -3214,10 +3220,10 @@ trait DatabasesBase $moviesId = $movies['body']['$id']; // create attribute - $title = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/attributes/string', array_merge([ + $title = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'title', 'size' => 256, @@ -3230,7 +3236,7 @@ trait DatabasesBase sleep(2); // add document - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3254,20 +3260,20 @@ trait DatabasesBase $this->assertContains(Permission::delete(Role::any()), $document['body']['$permissions']); // Send only read permission - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'permissions' => [ Permission::read(Role::user(ID::custom($this->getUser()['$id']))), - ], + ] ]); $this->assertEquals(200, $document['headers']['status-code']); $this->assertCount(1, $document['body']['$permissions']); // Send only mutation permissions - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents/'.$id, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3285,7 +3291,7 @@ trait DatabasesBase } // remove collection - $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$moviesId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $moviesId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3303,39 +3309,39 @@ trait DatabasesBase /** * Test for SUCCESS */ - $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), - 'name' => 'Boolean', + 'name' => 'Boolean' ]); $this->assertEquals(201, $collection['headers']['status-code']); $collectionId = $collection['body']['$id']; - $true = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean', array_merge([ + $true = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'true', 'required' => false, - 'default' => true, + 'default' => true ]); $this->assertEquals(202, $true['headers']['status-code']); - $false = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean', array_merge([ + $false = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'false', 'required' => false, - 'default' => false, + 'default' => false ]); $this->assertEquals(202, $false['headers']['status-code']); @@ -3348,10 +3354,10 @@ trait DatabasesBase { $databaseId = $data['databaseId']; - $person = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $person = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => 'person', 'name' => 'person', @@ -3366,10 +3372,10 @@ trait DatabasesBase $this->assertEquals(201, $person['headers']['status-code']); - $library = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $library = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => 'library', 'name' => 'library', @@ -3383,10 +3389,10 @@ trait DatabasesBase $this->assertEquals(201, $library['headers']['status-code']); - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'fullName', 'size' => 255, @@ -3395,10 +3401,10 @@ trait DatabasesBase sleep(1); // Wait for worker - $relation = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/attributes/relationship', array_merge([ + $relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => 'library', 'type' => Database::RELATION_ONE_TO_ONE, @@ -3409,10 +3415,10 @@ trait DatabasesBase sleep(1); // Wait for worker - $libraryName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$library['body']['$id'].'/attributes/string', array_merge([ + $libraryName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $library['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'libraryName', 'size' => 255, @@ -3427,10 +3433,10 @@ trait DatabasesBase $this->assertEquals('relationship', $relation['body']['type']); $this->assertEquals('processing', $relation['body']['status']); - $attributes = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/attributes', array_merge([ + $attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $attributes['headers']['status-code']); @@ -3445,7 +3451,7 @@ trait DatabasesBase $attribute = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$person['body']['$id']}/attributes/library", array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $attribute['headers']['status-code']); @@ -3459,7 +3465,7 @@ trait DatabasesBase $this->assertEquals('person', $attribute['body']['twoWayKey']); $this->assertEquals(Database::RELATION_MUTATE_CASCADE, $attribute['body']['onDelete']); - $person1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents', array_merge([ + $person1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3477,13 +3483,13 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); $this->assertEquals('Library 1', $person1['body']['library']['libraryName']); // Create without nested ID - $person2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents', array_merge([ + $person2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3497,7 +3503,7 @@ trait DatabasesBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); $this->assertEquals('Library 2', $person2['body']['library']['libraryName']); @@ -3514,21 +3520,21 @@ trait DatabasesBase $this->assertArrayNotHasKey('$internalId', $person1['body']); $this->assertArrayNotHasKey('$internalId', $person1['body']['library']); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents', array_merge([ + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ 'equal("library", "library1")', - 'select(["fullName","library.*"])', - ], + 'select(["fullName","library.*"])' + ] ]); $this->assertEquals(1, $documents['body']['total']); $this->assertEquals('Library 1', $documents['body']['documents'][0]['library']['libraryName']); $this->assertArrayHasKey('fullName', $documents['body']['documents'][0]); - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents', array_merge([ + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3540,10 +3546,10 @@ trait DatabasesBase $this->assertEquals(400, $documents['headers']['status-code']); $this->assertEquals('Invalid query: Cannot query nested attribute on: library', $documents['body']['message']); - $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/attributes/library', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/attributes/library', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); sleep(2); @@ -3553,12 +3559,12 @@ trait DatabasesBase $attribute = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$person['body']['$id']}/attributes/library", array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(404, $attribute['headers']['status-code']); - $person1 = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$person['body']['$id'].'/documents/'.$person1['body']['$id'], array_merge([ + $person1 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents/' . $person1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3566,10 +3572,10 @@ trait DatabasesBase $this->assertArrayNotHasKey('library', $person1['body']); //Test Deletion of related twoKey - $attributes = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$library['body']['$id'].'/attributes', array_merge([ + $attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $library['body']['$id'] . '/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $attributes['headers']['status-code']); @@ -3593,10 +3599,10 @@ trait DatabasesBase $libraryCollection = $data['libraryCollection']; // One person can own several libraries - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$personCollection.'/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $personCollection . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => 'library', 'type' => Database::RELATION_ONE_TO_MANY, @@ -3607,20 +3613,20 @@ trait DatabasesBase sleep(1); - $libraryAttributesResponse = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$libraryCollection.'/attributes', array_merge([ + $libraryAttributesResponse = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $libraryCollection . '/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertIsArray($libraryAttributesResponse['body']['attributes']); $this->assertEquals(2, $libraryAttributesResponse['body']['total']); $this->assertEquals('person_one_to_many', $libraryAttributesResponse['body']['attributes'][1]['key']); - $libraryCollectionResponse = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$libraryCollection, array_merge([ + $libraryCollectionResponse = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $libraryCollection, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertIsArray($libraryCollectionResponse['body']['attributes']); @@ -3629,7 +3635,7 @@ trait DatabasesBase $attribute = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$personCollection}/attributes/libraries", array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $attribute['headers']['status-code']); @@ -3643,7 +3649,7 @@ trait DatabasesBase $this->assertEquals('person_one_to_many', $attribute['body']['twoWayKey']); $this->assertEquals('restrict', $attribute['body']['onDelete']); - $person2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$personCollection.'/documents', array_merge([ + $person2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $personCollection . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3668,21 +3674,21 @@ trait DatabasesBase Permission::delete(Role::any()), ], 'libraryName' => 'Library 11', - ], + ] ], ], 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()), - ], + ] ]); $this->assertEquals(201, $person2['headers']['status-code']); $this->assertArrayHasKey('libraries', $person2['body']); $this->assertEquals(2, count($person2['body']['libraries'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$personCollection.'/documents/'.$person2['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $personCollection . '/documents/' . $person2['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3692,7 +3698,7 @@ trait DatabasesBase $this->assertArrayHasKey('libraries', $response['body']); $this->assertEquals(2, count($response['body']['libraries'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$libraryCollection.'/documents/library11', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $libraryCollection . '/documents/library11', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3701,10 +3707,10 @@ trait DatabasesBase $this->assertArrayHasKey('person_one_to_many', $response['body']); $this->assertEquals('person10', $response['body']['person_one_to_many']['$id']); - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$personCollection.'/attributes/libraries/relationship', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $personCollection . '/attributes/libraries/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'onDelete' => Database::RELATION_MUTATE_CASCADE, ]); @@ -3714,7 +3720,7 @@ trait DatabasesBase $attribute = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$personCollection}/attributes/libraries", array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $attribute['headers']['status-code']); @@ -3738,10 +3744,10 @@ trait DatabasesBase $databaseId = $data['databaseId']; // Create album collection - $albums = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $albums = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Albums', @@ -3753,10 +3759,10 @@ trait DatabasesBase ]); // Create album name attribute - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$albums['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $albums['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'name', 'size' => 255, @@ -3764,10 +3770,10 @@ trait DatabasesBase ]); // Create artist collection - $artists = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $artists = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Artists', @@ -3779,10 +3785,10 @@ trait DatabasesBase ]); // Create artist name attribute - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$artists['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $artists['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'name', 'size' => 255, @@ -3790,10 +3796,10 @@ trait DatabasesBase ]); // Create relationship - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$albums['body']['$id'].'/attributes/relationship', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $albums['body']['$id'] . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $artists['body']['$id'], 'type' => Database::RELATION_MANY_TO_ONE, @@ -3820,7 +3826,7 @@ trait DatabasesBase ]; // Create album - $album = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$albums['body']['$id'].'/documents', array_merge([ + $album = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $albums['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3842,7 +3848,7 @@ trait DatabasesBase $this->assertEquals($permissions, $album['body']['$permissions']); $this->assertEquals($permissions, $album['body']['artist']['$permissions']); - $album = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$albums['body']['$id'].'/documents/album1', array_merge([ + $album = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $albums['body']['$id'] . '/documents/album1', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3854,7 +3860,7 @@ trait DatabasesBase $this->assertEquals($permissions, $album['body']['$permissions']); $this->assertEquals($permissions, $album['body']['artist']['$permissions']); - $artist = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$artists['body']['$id'].'/documents/'.$album['body']['artist']['$id'], array_merge([ + $artist = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $artists['body']['$id'] . '/documents/' . $album['body']['artist']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3882,10 +3888,10 @@ trait DatabasesBase $databaseId = $data['databaseId']; // Create sports collection - $sports = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $sports = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Sports', @@ -3897,10 +3903,10 @@ trait DatabasesBase ]); // Create sport name attribute - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$sports['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $sports['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'name', 'size' => 255, @@ -3908,10 +3914,10 @@ trait DatabasesBase ]); // Create player collection - $players = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $players = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Players', @@ -3923,10 +3929,10 @@ trait DatabasesBase ]); // Create player name attribute - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$players['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $players['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'name', 'size' => 255, @@ -3934,10 +3940,10 @@ trait DatabasesBase ]); // Create relationship - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$sports['body']['$id'].'/attributes/relationship', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $sports['body']['$id'] . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $players['body']['$id'], 'type' => Database::RELATION_MANY_TO_MANY, @@ -3965,7 +3971,7 @@ trait DatabasesBase ]; // Create sport - $sport = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$sports['body']['$id'].'/documents', array_merge([ + $sport = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $sports['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3981,7 +3987,7 @@ trait DatabasesBase [ '$id' => 'player2', 'name' => 'Player 2', - ], + ] ], ], ]); @@ -3995,7 +4001,7 @@ trait DatabasesBase $this->assertEquals($permissions, $sport['body']['players'][0]['$permissions']); $this->assertEquals($permissions, $sport['body']['players'][1]['$permissions']); - $sport = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$sports['body']['$id'].'/documents/sport1', array_merge([ + $sport = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $sports['body']['$id'] . '/documents/sport1', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -4009,7 +4015,7 @@ trait DatabasesBase $this->assertEquals($permissions, $sport['body']['players'][0]['$permissions']); $this->assertEquals($permissions, $sport['body']['players'][1]['$permissions']); - $player = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$players['body']['$id'].'/documents/'.$sport['body']['players'][0]['$id'], array_merge([ + $player = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $players['body']['$id'] . '/documents/' . $sport['body']['players'][0]['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -4034,7 +4040,7 @@ trait DatabasesBase */ public function testValidateOperators(array $data): void { - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -4052,21 +4058,21 @@ trait DatabasesBase $this->assertEquals('Stevie Wonder', $response['body']['documents'][0]['fullName']); $this->assertEquals(2, count($response['body']['documents'][0]['libraries'])); - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ 'isNotNull("$id")', 'isNull("fullName")', - 'select(["fullName"])', + 'select(["fullName"])' ], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(2, count($response['body']['documents'])); $this->assertEquals(null, $response['body']['documents'][0]['fullName']); - $this->assertArrayNotHasKey('libraries', $response['body']['documents'][0]); + $this->assertArrayNotHasKey("libraries", $response['body']['documents'][0]); } /** @@ -4074,20 +4080,20 @@ trait DatabasesBase */ public function testSelectsQueries(array $data): void { - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ 'equal("fullName", "Stevie Wonder")', - 'select(["fullName"])', + 'select(["fullName"])' ], ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertArrayNotHasKey('libraries', $response['body']['documents'][0]); - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -4099,12 +4105,12 @@ trait DatabasesBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertArrayHasKey('libraries', $document); - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$data['databaseId'].'/collections/'.$data['personCollection'].'/documents/'.$document['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents/' . $document['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ - 'select(["fullName", "$id"])', + 'select(["fullName", "$id"])' ], ]); @@ -4115,20 +4121,18 @@ trait DatabasesBase /** * @depends testCreateDatabase - * - * @param array $data + * @param array $data * @return void - * * @throws \Exception */ public function testUpdateWithExistingRelationships(array $data): void { $databaseId = $data['databaseId']; - $collection1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Collection1', @@ -4139,10 +4143,10 @@ trait DatabasesBase ], ]); - $collection2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Collection2', @@ -4156,42 +4160,42 @@ trait DatabasesBase $collection1 = $collection1['body']['$id']; $collection2 = $collection2['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1.'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'name', 'size' => '49', 'required' => true, ]); - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection2.'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2 . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'name', 'size' => '49', 'required' => true, ]); - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1.'/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $collection2, 'type' => Database::RELATION_ONE_TO_MANY, 'twoWay' => true, - 'key' => 'collection2', + 'key' => 'collection2' ]); sleep(1); - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1.'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ @@ -4204,9 +4208,9 @@ trait DatabasesBase ], ]); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1.'/documents/'.$document['body']['$id'], array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents/' . $document['body']['$id'], array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ 'data' => [ 'name' => 'Document 1 Updated', diff --git a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php index 947b0ed7fe..17059adf88 100644 --- a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php +++ b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php @@ -2,9 +2,9 @@ namespace Tests\E2E\Services\Databases; -use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Client; use Tests\E2E\Scopes\SideConsole; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -32,7 +32,7 @@ class DatabasesConsoleClientTest extends Scope /** * Test for SUCCESS */ - $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -53,7 +53,7 @@ class DatabasesConsoleClientTest extends Scope /** * Test When database is disabled but can still create collections */ - $database = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId, array_merge([ + $database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -63,7 +63,7 @@ class DatabasesConsoleClientTest extends Scope $this->assertFalse($database['body']['enabled']); - $tvShows = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $tvShows = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -86,8 +86,7 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection - * - * @param array $data + * @param array $data */ public function testListCollection(array $data) { @@ -96,10 +95,10 @@ class DatabasesConsoleClientTest extends Scope */ $databaseId = $data['databaseId']; - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], $this->getHeaders())); $this->assertEquals(200, $collections['headers']['status-code']); @@ -108,8 +107,7 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection - * - * @param array $data + * @param array $data */ public function testGetCollection(array $data) { @@ -119,7 +117,7 @@ class DatabasesConsoleClientTest extends Scope /** * Test When database is disabled but can still call get collection */ - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$moviesCollectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $moviesCollectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -132,8 +130,7 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection - * - * @param array $data + * @param array $data */ public function testUpdateCollection(array $data) { @@ -143,12 +140,12 @@ class DatabasesConsoleClientTest extends Scope /** * Test When database is disabled but can still call update collection */ - $collection = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$moviesCollectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $moviesCollectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'name' => 'Movies Updated', - 'enabled' => false, + 'enabled' => false ]); $this->assertEquals(200, $collection['headers']['status-code']); @@ -159,8 +156,7 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection - * - * @param array $data + * @param array $data */ public function testDeleteCollection(array $data) { @@ -170,13 +166,13 @@ class DatabasesConsoleClientTest extends Scope /** * Test When database is disabled but can still call Delete collection */ - $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$tvShowsId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $tvShowsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEquals($response['body'], ''); + $this->assertEquals($response['body'], ""); } /** @@ -188,11 +184,12 @@ class DatabasesConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/usage', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '32h', + 'range' => '32h' ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -200,11 +197,12 @@ class DatabasesConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/usage', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '24h', + 'range' => '24h' ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -214,6 +212,7 @@ class DatabasesConsoleClientTest extends Scope $this->assertIsArray($response['body']['collectionsTotal']); } + /** * @depends testCreateCollection */ @@ -223,20 +222,21 @@ class DatabasesConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/usage', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '32h', + 'range' => '32h' ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/randomCollectionId/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/randomCollectionId/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '24h', + 'range' => '24h' ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -244,11 +244,11 @@ class DatabasesConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '24h', + 'range' => '24h' ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(count($response['body']), 2); @@ -265,7 +265,7 @@ class DatabasesConsoleClientTest extends Scope /** * Test for SUCCESS */ - $logs = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -274,11 +274,11 @@ class DatabasesConsoleClientTest extends Scope $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'limit' => 1, + 'limit' => 1 ]); $this->assertEquals(200, $logs['headers']['status-code']); @@ -286,23 +286,23 @@ class DatabasesConsoleClientTest extends Scope $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'offset' => 1, + 'offset' => 1 ]); $this->assertEquals(200, $logs['headers']['status-code']); $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['moviesId'].'/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'offset' => 1, - 'limit' => 1, + 'limit' => 1 ]); $this->assertEquals(200, $logs['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php index b5abaebfad..743df9e53a 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Databases; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -21,22 +21,23 @@ class DatabasesCustomClientTest extends Scope /** * Test for SUCCESS */ + $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'databaseId' => ID::unique(), - 'name' => 'Test Database', + 'name' => 'Test Database' ]); $databaseId = $database['body']['$id']; // Collection aliases write to create, update, delete - $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Movies', @@ -52,10 +53,10 @@ class DatabasesCustomClientTest extends Scope $this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']); $this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']); - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/attributes/string', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'title', 'size' => 256, @@ -67,7 +68,7 @@ class DatabasesCustomClientTest extends Scope $this->assertEquals(202, $response['headers']['status-code']); // Document aliases write to update, delete - $document1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents', array_merge([ + $document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -77,7 +78,7 @@ class DatabasesCustomClientTest extends Scope ], 'permissions' => [ Permission::write(Role::user($this->getUser()['$id'])), - ], + ] ]); $this->assertNotContains(Permission::create(Role::user($this->getUser()['$id'])), $document1['body']['$permissions']); @@ -89,7 +90,7 @@ class DatabasesCustomClientTest extends Scope */ // Document does not allow create permission - $document2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents', array_merge([ + $document2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -99,7 +100,7 @@ class DatabasesCustomClientTest extends Scope ], 'permissions' => [ Permission::create(Role::user($this->getUser()['$id'])), - ], + ] ]); $this->assertEquals(400, $document2['headers']['status-code']); @@ -113,7 +114,7 @@ class DatabasesCustomClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); @@ -122,7 +123,7 @@ class DatabasesCustomClientTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::custom('permissionCheckDatabase'), 'name' => 'Test Database', @@ -132,10 +133,10 @@ class DatabasesCustomClientTest extends Scope $databaseId = $database['body']['$id']; // Create collection - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('permissionCheck'), 'name' => 'permissionCheck', @@ -145,10 +146,10 @@ class DatabasesCustomClientTest extends Scope $this->assertEquals(201, $response['headers']['status-code']); // Add attribute to collection - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/permissionCheck/attributes/string', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/permissionCheck/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'name', 'size' => 255, @@ -160,10 +161,10 @@ class DatabasesCustomClientTest extends Scope sleep(2); // Creating document by server, give read permission to our user + some other user - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/permissionCheck/documents', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/permissionCheck/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'documentId' => ID::custom('permissionCheckDocument'), 'data' => [ @@ -181,43 +182,44 @@ class DatabasesCustomClientTest extends Scope // Update document // This is the point of this test. We should be allowed to do this action, and it should not fail on permission check - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/permissionCheck/documents/permissionCheckDocument', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/permissionCheck/documents/permissionCheckDocument', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => [ 'name' => 'AppwriteExpert', - ], + ] ]); $this->assertEquals(200, $response['headers']['status-code']); // Get name of the document, should be the new one - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/permissionCheck/documents/permissionCheckDocument', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/permissionCheck/documents/permissionCheckDocument', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('AppwriteExpert', $response['body']['name']); + $this->assertEquals("AppwriteExpert", $response['body']['name']); // Cleanup to prevent collision with other tests // Delete collection - $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/permissionCheck', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/permissionCheck', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(204, $response['headers']['status-code']); + // Wait for database worker to finish deleting collection sleep(2); // Make sure collection has been deleted - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/permissionCheck', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/permissionCheck', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(404, $response['headers']['status-code']); @@ -226,22 +228,24 @@ class DatabasesCustomClientTest extends Scope public function testUpdateTwoWayRelationship(): void { + $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'databaseId' => ID::unique(), - 'name' => 'Test Database', + 'name' => 'Test Database' ]); $databaseId = $database['body']['$id']; + // Creating collection 1 - $collection1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'level1', @@ -251,14 +255,14 @@ class DatabasesCustomClientTest extends Scope Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); // Creating collection 2 - $collection2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'level2', @@ -268,41 +272,41 @@ class DatabasesCustomClientTest extends Scope Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); \sleep(2); // Creating two way relationship between collection 1 and collection 2 from collection 1 - $relation = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/attributes/relationship', array_merge([ + $relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $collection2['body']['$id'], 'type' => 'oneToMany', 'twoWay' => true, 'onDelete' => 'cascade', 'key' => $collection2['body']['$id'], - 'twoWayKey' => $collection1['body']['$id'], + 'twoWayKey' => $collection1['body']['$id'] ]); \sleep(3); // Update relation from collection 2 to on delete restrict - $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection2['body']['$id'].'/attributes/'.$collection1['body']['$id'].'/relationship', array_merge([ + $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/attributes/' . $collection1['body']['$id'] . '/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'onDelete' => 'restrict', ]); // Fetching attributes after updating relation to compare - $collection1Attributes = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'], [ + $collection1Attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]); $collection1RelationAttribute = $collection1Attributes['body']['attributes'][0]; @@ -319,7 +323,7 @@ class DatabasesCustomClientTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'databaseId' => ID::unique(), 'name' => ID::unique(), @@ -328,10 +332,10 @@ class DatabasesCustomClientTest extends Scope $databaseId = $database['body']['$id']; // Creating collection 1 - $collection1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('collection1'), 'name' => ID::custom('collection1'), @@ -340,27 +344,27 @@ class DatabasesCustomClientTest extends Scope Permission::create(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ], + ] ]); // Creating collection 2 - $collection2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('collection2'), 'name' => ID::custom('collection2'), 'documentSecurity' => false, 'permissions' => [ Permission::read(Role::user($userId)), - ], + ] ]); - $collection3 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('collection3'), 'name' => ID::custom('collection3'), @@ -369,26 +373,26 @@ class DatabasesCustomClientTest extends Scope Permission::create(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ], + ] ]); - $collection4 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection4 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('collection4'), 'name' => ID::custom('collection4'), 'documentSecurity' => false, 'permissions' => [ Permission::read(Role::user($userId)), - ], + ] ]); - $collection5 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection5 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('collection5'), 'name' => ID::custom('collection5'), @@ -397,115 +401,115 @@ class DatabasesCustomClientTest extends Scope Permission::create(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ], + ] ]); // Creating one to one relationship from collection 1 to colletion 2 - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $collection2['body']['$id'], 'type' => 'oneToOne', 'twoWay' => false, 'onDelete' => 'setNull', - 'key' => $collection2['body']['$id'], + 'key' => $collection2['body']['$id'] ]); // Creating one to one relationship from collection 2 to colletion 3 - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection2['body']['$id'].'/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $collection3['body']['$id'], 'type' => 'oneToOne', 'twoWay' => false, 'onDelete' => 'setNull', - 'key' => $collection3['body']['$id'], + 'key' => $collection3['body']['$id'] ]); // Creating one to one relationship from collection 3 to colletion 4 - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection3['body']['$id'].'/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection3['body']['$id'] . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $collection4['body']['$id'], 'type' => 'oneToOne', 'twoWay' => false, 'onDelete' => 'setNull', - 'key' => $collection4['body']['$id'], + 'key' => $collection4['body']['$id'] ]); // Creating one to one relationship from collection 4 to colletion 5 - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection4['body']['$id'].'/attributes/relationship', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection4['body']['$id'] . '/attributes/relationship', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'relatedCollectionId' => $collection5['body']['$id'], 'type' => 'oneToOne', 'twoWay' => false, 'onDelete' => 'setNull', - 'key' => $collection5['body']['$id'], + 'key' => $collection5['body']['$id'] ]); - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'key' => 'Title', + 'key' => "Title", 'size' => 100, 'required' => false, 'array' => false, 'default' => null, ]); - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection2['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'key' => 'Rating', + 'key' => "Rating", 'size' => 100, 'required' => false, 'array' => false, 'default' => null, ]); - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection3['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection3['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'key' => 'Rating', + 'key' => "Rating", 'size' => 100, 'required' => false, 'array' => false, 'default' => null, ]); - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection4['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection4['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'key' => 'Rating', + 'key' => "Rating", 'size' => 100, 'required' => false, 'array' => false, 'default' => null, ]); - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection5['body']['$id'].'/attributes/string', array_merge([ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection5['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'key' => 'Rating', + 'key' => "Rating", 'size' => 100, 'required' => false, 'array' => false, @@ -514,10 +518,10 @@ class DatabasesCustomClientTest extends Scope \sleep(2); // Creating parent document with a child reference to test the permissions - $parentDocument = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents', array_merge([ + $parentDocument = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'documentId' => ID::custom($collection1['body']['$id']), 'data' => [ @@ -533,17 +537,17 @@ class DatabasesCustomClientTest extends Scope 'Rating' => '10', $collection5['body']['$id'] => [ '$id' => ID::custom($collection5['body']['$id']), - 'Rating' => '10', - ], - ], - ], - ], - ], + 'Rating' => '10' + ] + ] + ] + ] + ] ]); $this->assertEquals(201, $parentDocument['headers']['status-code']); // This is the point of the test. We should not need any authorization permission to update the document with same data. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -561,21 +565,21 @@ class DatabasesCustomClientTest extends Scope 'Rating' => '10', $collection5['body']['$id'] => [ '$id' => $collection5['body']['$id'], - 'Rating' => '10', - ], - ], - ], - ], - ], + 'Rating' => '10' + ] + ] + ] + ] + ] ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($parentDocument['body'], $response['body']); // Giving update permission of collection 3 to user. - $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/collection3', array_merge([ + $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/collection3', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('collection3'), 'name' => ID::custom('collection3'), @@ -585,11 +589,11 @@ class DatabasesCustomClientTest extends Scope Permission::read(Role::user($userId)), Permission::update(Role::user($userId)), Permission::delete(Role::user($userId)), - ], + ] ]); // This is the point of this test. We should be allowed to do this action, and it should not fail on permission check - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -606,19 +610,19 @@ class DatabasesCustomClientTest extends Scope 'Rating' => '10', $collection5['body']['$id'] => [ '$id' => ID::custom($collection5['body']['$id']), - 'Rating' => '11', - ], - ], - ], - ], - ], + 'Rating' => '11' + ] + ] + ] + ] + ] ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(11, $response['body'][$collection2['body']['$id']]['collection3']['Rating']); // We should not be allowed to update the document as we do not have permission for collection 2. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -628,29 +632,29 @@ class DatabasesCustomClientTest extends Scope '$id' => ID::custom($collection2['body']['$id']), 'Rating' => '11', $collection3['body']['$id'] => null, - ], - ], + ] + ] ]); $this->assertEquals(401, $response['headers']['status-code']); // We should not be allowed to update the document as we do not have permission for collection 2. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection2['body']['$id'].'/documents/'.$collection2['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/documents/' . $collection2['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => [ 'Rating' => '11', - ], + ] ]); $this->assertEquals(401, $response['headers']['status-code']); // Removing update permission from collection 3. - $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/collection3', array_merge([ + $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/collection3', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('collection3'), 'name' => ID::custom('collection3'), @@ -659,14 +663,14 @@ class DatabasesCustomClientTest extends Scope Permission::create(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ], + ] ]); // Giving update permission to collection 2. - $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/collection2', array_merge([ + $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/collection2', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('collection2'), 'name' => ID::custom('collection2'), @@ -676,25 +680,25 @@ class DatabasesCustomClientTest extends Scope Permission::update(Role::user($userId)), Permission::read(Role::user($userId)), Permission::delete(Role::user($userId)), - ], + ] ]); // Creating collection 3 new document - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection3['body']['$id'].'/documents', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection3['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'documentId' => ID::custom('collection3Doc1'), 'data' => [ - 'Rating' => '20', - ], + 'Rating' => '20' + ] ]); $this->assertEquals(201, $response['headers']['status-code']); // We should be allowed to link a new document from collection 3 to collection 2. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -703,14 +707,15 @@ class DatabasesCustomClientTest extends Scope $collection2['body']['$id'] => [ '$id' => ID::custom($collection2['body']['$id']), $collection3['body']['$id'] => 'collection3Doc1', - ], - ], + ] + ] ]); $this->assertEquals(200, $response['headers']['status-code']); + // We should be allowed to link and create a new document from collection 3 to collection 2. - $response = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection1['body']['$id'].'/documents/'.$collection1['body']['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -719,10 +724,10 @@ class DatabasesCustomClientTest extends Scope $collection2['body']['$id'] => [ '$id' => ID::custom($collection2['body']['$id']), $collection3['body']['$id'] => [ - '$id' => ID::custom('collection3Doc2'), + '$id' => ID::custom('collection3Doc2') ], - ], - ], + ] + ] ]); $this->assertEquals(200, $response['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index 57b609c33a..648a4de800 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -3,10 +3,10 @@ namespace Tests\E2E\Services\Databases; use Appwrite\Extend\Exception as AppwriteException; -use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; +use Tests\E2E\Client; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -22,7 +22,7 @@ class DatabasesCustomServerTest extends Scope $test1 = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::custom('first'), 'name' => 'Test 1', @@ -34,7 +34,7 @@ class DatabasesCustomServerTest extends Scope $test2 = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::custom('second'), 'name' => 'Test 2', @@ -124,7 +124,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("'.$base['body']['databases'][0]['$id'].'")'], + 'queries' => ['cursorAfter("' . $base['body']['databases'][0]['$id'] . '")'], ]); $this->assertCount(1, $databases['body']['databases']); @@ -134,7 +134,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("'.$base['body']['databases'][1]['$id'].'")'], + 'queries' => ['cursorAfter("' . $base['body']['databases'][1]['$id'] . '")'], ]); $this->assertCount(0, $databases['body']['databases']); @@ -152,7 +152,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("'.$base['body']['databases'][1]['$id'].'")'], + 'queries' => ['cursorBefore("' . $base['body']['databases'][1]['$id'] . '")'], ]); $this->assertCount(1, $databases['body']['databases']); @@ -162,7 +162,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("'.$base['body']['databases'][0]['$id'].'")'], + 'queries' => ['cursorBefore("' . $base['body']['databases'][0]['$id'] . '")'], ]); $this->assertCount(0, $databases['body']['databases']); @@ -175,7 +175,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'first', + 'search' => 'first' ]); $this->assertEquals(1, $databases['body']['total']); @@ -185,7 +185,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Test', + 'search' => 'Test' ]); $this->assertEquals(2, $databases['body']['total']); @@ -196,7 +196,7 @@ class DatabasesCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Nonexistent', + 'search' => 'Nonexistent' ]); $this->assertEquals(0, $databases['body']['total']); @@ -217,14 +217,13 @@ class DatabasesCustomServerTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Test 1', 'databaseId' => ID::custom('first'), ]); $this->assertEquals(409, $response['headers']['status-code']); - return ['databaseId' => $test1['body']['$id']]; } @@ -237,17 +236,16 @@ class DatabasesCustomServerTest extends Scope /** * Test for SUCCESS */ - $database = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId, [ + $database = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]); $this->assertEquals(200, $database['headers']['status-code']); $this->assertEquals($databaseId, $database['body']['$id']); $this->assertEquals('Test 1', $database['body']['name']); $this->assertEquals(true, $database['body']['enabled']); - return ['databaseId' => $database['body']['$id']]; } @@ -258,10 +256,10 @@ class DatabasesCustomServerTest extends Scope { $databaseId = $data['databaseId']; - $database = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId, [ + $database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'name' => 'Test 1 Updated', 'enabled' => false, @@ -272,12 +270,12 @@ class DatabasesCustomServerTest extends Scope $this->assertFalse($database['body']['enabled']); // Now update the database without the passing the enabled parameter - $database = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId, [ + $database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ - 'name' => 'Test 1', + 'name' => 'Test 1' ]); $this->assertEquals(200, $database['headers']['status-code']); @@ -292,19 +290,19 @@ class DatabasesCustomServerTest extends Scope { $databaseId = $data['databaseId']; - $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEquals('', $response['body']); + $this->assertEquals("", $response['body']); // Try to get the collection and check if it has been deleted - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId, array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders())); $this->assertEquals(404, $response['headers']['status-code']); @@ -315,7 +313,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -328,10 +326,10 @@ class DatabasesCustomServerTest extends Scope /** * Test for SUCCESS */ - $test1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $test1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Test 1', 'collectionId' => ID::custom('first'), @@ -344,10 +342,10 @@ class DatabasesCustomServerTest extends Scope 'documentSecurity' => true, ]); - $test2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $test2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Test 2', 'collectionId' => ID::custom('second'), @@ -360,7 +358,7 @@ class DatabasesCustomServerTest extends Scope 'documentSecurity' => true, ]); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -373,41 +371,41 @@ class DatabasesCustomServerTest extends Scope $base = array_reverse($collections['body']['collections']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(1)'], + 'queries' => ['limit(1)'] ]); $this->assertEquals(200, $collections['headers']['status-code']); $this->assertCount(1, $collections['body']['collections']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(1)'], + 'queries' => ['offset(1)'] ]); $this->assertEquals(200, $collections['headers']['status-code']); $this->assertCount(1, $collections['body']['collections']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("enabled", true)'], + 'queries' => ['equal("enabled", true)'] ]); $this->assertEquals(200, $collections['headers']['status-code']); $this->assertCount(2, $collections['body']['collections']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("enabled", false)'], + 'queries' => ['equal("enabled", false)'] ]); $this->assertEquals(200, $collections['headers']['status-code']); @@ -416,7 +414,7 @@ class DatabasesCustomServerTest extends Scope /** * Test for Order */ - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -430,26 +428,26 @@ class DatabasesCustomServerTest extends Scope /** * Test for After */ - $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("'.$base['body']['collections'][0]['$id'].'")'], + 'queries' => ['cursorAfter("' . $base['body']['collections'][0]['$id'] . '")'], ]); $this->assertCount(1, $collections['body']['collections']); $this->assertEquals($base['body']['collections'][1]['$id'], $collections['body']['collections'][0]['$id']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("'.$base['body']['collections'][1]['$id'].'")'], + 'queries' => ['cursorAfter("' . $base['body']['collections'][1]['$id'] . '")'], ]); $this->assertCount(0, $collections['body']['collections']); @@ -458,26 +456,26 @@ class DatabasesCustomServerTest extends Scope /** * Test for Before */ - $base = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $base = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("'.$base['body']['collections'][1]['$id'].'")'], + 'queries' => ['cursorBefore("' . $base['body']['collections'][1]['$id'] . '")'], ]); $this->assertCount(1, $collections['body']['collections']); $this->assertEquals($base['body']['collections'][0]['$id'], $collections['body']['collections'][0]['$id']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("'.$base['body']['collections'][0]['$id'].'")'], + 'queries' => ['cursorBefore("' . $base['body']['collections'][0]['$id'] . '")'], ]); $this->assertCount(0, $collections['body']['collections']); @@ -486,32 +484,32 @@ class DatabasesCustomServerTest extends Scope /** * Test for Search */ - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'first', + 'search' => 'first' ]); $this->assertEquals(1, $collections['body']['total']); $this->assertEquals('first', $collections['body']['collections'][0]['$id']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Test', + 'search' => 'Test' ]); $this->assertEquals(2, $collections['body']['total']); $this->assertEquals('Test 1', $collections['body']['collections'][0]['name']); $this->assertEquals('Test 2', $collections['body']['collections'][1]['name']); - $collections = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Nonexistent', + 'search' => 'Nonexistent' ]); $this->assertEquals(0, $collections['body']['total']); @@ -519,7 +517,7 @@ class DatabasesCustomServerTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -529,10 +527,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); // This collection already exists - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Test 1', 'collectionId' => ID::custom('first'), @@ -546,7 +544,6 @@ class DatabasesCustomServerTest extends Scope ]); $this->assertEquals(409, $response['headers']['status-code']); - return [ 'databaseId' => $databaseId, 'collectionId' => $test1['body']['$id'], @@ -561,10 +558,10 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], $this->getHeaders())); $this->assertEquals(200, $collection['headers']['status-code']); @@ -581,13 +578,13 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $collection = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Test 1 Updated', - 'enabled' => false, + 'enabled' => false ]); $this->assertEquals(200, $collection['headers']['status-code']); @@ -597,10 +594,11 @@ class DatabasesCustomServerTest extends Scope } /** - * @depends testListCollections + * @depends testListCollections */ public function testCreateEncryptedAttribute(array $data): void { + $databaseId = $data['databaseId']; /** @@ -608,10 +606,10 @@ class DatabasesCustomServerTest extends Scope */ // Create collection - $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Encrypted Actors Data', @@ -630,22 +628,23 @@ class DatabasesCustomServerTest extends Scope /** * Test for creating encrypted attributes */ - $attributesPath = '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes'; - $firstName = $this->client->call(Client::METHOD_POST, $attributesPath.'/string', array_merge([ + $attributesPath = '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes'; + + $firstName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'firstName', 'size' => 256, 'required' => true, ]); - $lastName = $this->client->call(Client::METHOD_POST, $attributesPath.'/string', array_merge([ + $lastName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'lastName', 'size' => 256, @@ -653,6 +652,7 @@ class DatabasesCustomServerTest extends Scope 'encrypt' => true, ]); + /** * Check status of every attribute */ @@ -668,10 +668,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Creating document to ensure cache is purged on schema change - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'documentId' => ID::unique(), 'data' => [ @@ -686,10 +686,10 @@ class DatabasesCustomServerTest extends Scope ]); // Check document to ensure cache is purged on schema change - $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/documents/'.$document['body']['$id'], array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents/' . $document['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $document['headers']['status-code']); @@ -702,7 +702,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -716,10 +716,10 @@ class DatabasesCustomServerTest extends Scope */ // Create collection - $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -735,30 +735,30 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(201, $actors['headers']['status-code']); $this->assertEquals($actors['body']['name'], 'Actors'); - $firstName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes/string', array_merge([ + $firstName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'firstName', 'size' => 256, 'required' => true, ]); - $lastName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes/string', array_merge([ + $lastName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'lastName', 'size' => 256, 'required' => true, ]); - $unneeded = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes/string', array_merge([ + $unneeded = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'unneeded', 'size' => 256, @@ -769,16 +769,16 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Creating document to ensure cache is purged on schema change - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'documentId' => ID::unique(), 'data' => [ 'firstName' => 'lorem', 'lastName' => 'ipsum', - 'unneeded' => 'dolor', + 'unneeded' => 'dolor' ], 'permissions' => [ Permission::read(Role::any()), @@ -787,10 +787,10 @@ class DatabasesCustomServerTest extends Scope ], ]); - $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'key_lastName', 'type' => 'key', @@ -802,10 +802,10 @@ class DatabasesCustomServerTest extends Scope // Wait for database worker to finish creating index sleep(2); - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'], array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), []); $unneededId = $unneeded['body']['key']; @@ -820,10 +820,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals($collection['body']['indexes'][0]['key'], $index['body']['key']); // Delete attribute - $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/attributes/'.$unneededId, array_merge([ + $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actors ['body']['$id'] . '/attributes/' . $unneededId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(204, $attribute['headers']['status-code']); @@ -831,18 +831,18 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Check document to ensure cache is purged on schema change - $document = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'].'/documents/'.$document['body']['$id'], array_merge([ + $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents/' . $document['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertNotContains($unneededId, $document['body']); - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'], array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), []); $this->assertEquals(200, $collection['headers']['status-code']); @@ -854,7 +854,7 @@ class DatabasesCustomServerTest extends Scope return [ 'collectionId' => $actors['body']['$id'], 'key' => $index['body']['key'], - 'databaseId' => $databaseId, + 'databaseId' => $databaseId ]; } @@ -864,10 +864,10 @@ class DatabasesCustomServerTest extends Scope public function testDeleteIndex($data): array { $databaseId = $data['databaseId']; - $index = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/indexes/'.$data['key'], array_merge([ + $index = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/indexes/' . $data['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(204, $index['headers']['status-code']); @@ -875,10 +875,10 @@ class DatabasesCustomServerTest extends Scope // Wait for database worker to finish deleting index sleep(2); - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['collectionId'], array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['collectionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), []); $this->assertCount(0, $collection['body']['indexes']); @@ -892,20 +892,20 @@ class DatabasesCustomServerTest extends Scope public function testDeleteIndexOnDeleteAttribute($data) { $databaseId = $data['databaseId']; - $attribute1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/attributes/string', array_merge([ + $attribute1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'attribute1', 'size' => 16, 'required' => true, ]); - $attribute2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/attributes/string', array_merge([ + $attribute2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'attribute2', 'size' => 16, @@ -919,10 +919,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); - $index1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/indexes', array_merge([ + $index1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'index1', 'type' => 'key', @@ -930,10 +930,10 @@ class DatabasesCustomServerTest extends Scope 'orders' => ['ASC', 'ASC'], ]); - $index2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/indexes', array_merge([ + $index2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'index2', 'type' => 'key', @@ -948,10 +948,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Expected behavior: deleting attribute2 will cause index2 to be dropped, and index1 rebuilt with a single key - $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/attributes/'.$attribute2['body']['key'], array_merge([ + $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/attributes/' . $attribute2['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(204, $deleted['headers']['status-code']); @@ -959,10 +959,10 @@ class DatabasesCustomServerTest extends Scope // wait for database worker to complete sleep(2); - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$data['collectionId'], array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['collectionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -974,10 +974,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals($attribute1['body']['key'], $collection['body']['indexes'][0]['attributes'][0]); // Delete attribute - $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['collectionId'].'/attributes/'.$attribute1['body']['key'], array_merge([ + $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['collectionId'] . '/attributes/' . $attribute1['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(204, $deleted['headers']['status-code']); @@ -990,7 +990,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -999,10 +999,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals('invalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'TestCleanupDuplicateIndexOnDeleteAttribute', @@ -1020,20 +1020,20 @@ class DatabasesCustomServerTest extends Scope $collectionId = $collection['body']['$id']; - $attribute1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ + $attribute1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'attribute1', 'size' => 16, 'required' => true, ]); - $attribute2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ + $attribute2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'attribute2', 'size' => 16, @@ -1047,10 +1047,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); - $index1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ + $index1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'index1', 'type' => 'key', @@ -1058,10 +1058,10 @@ class DatabasesCustomServerTest extends Scope 'orders' => ['ASC', 'ASC'], ]); - $index2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ + $index2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'index2', 'type' => 'key', @@ -1076,10 +1076,10 @@ class DatabasesCustomServerTest extends Scope sleep(2); // Expected behavior: deleting attribute1 would cause index1 to be a duplicate of index2 and automatically removed - $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$attribute1['body']['key'], array_merge([ + $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $attribute1['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(204, $deleted['headers']['status-code']); @@ -1087,10 +1087,10 @@ class DatabasesCustomServerTest extends Scope // wait for database worker to complete sleep(2); - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -1102,10 +1102,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals($attribute2['body']['key'], $collection['body']['indexes'][0]['attributes'][0]); // Delete attribute - $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$attribute2['body']['key'], array_merge([ + $deleted = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $attribute2['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(204, $deleted['headers']['status-code']); @@ -1120,7 +1120,7 @@ class DatabasesCustomServerTest extends Scope $collectionId = $data['collectionId']; // Add Documents to the collection - $document1 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $document1 = $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()), [ @@ -1136,7 +1136,7 @@ class DatabasesCustomServerTest extends Scope ], ]); - $document2 = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([ + $document2 = $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()), [ @@ -1165,19 +1165,19 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals($document2['body']['lastName'], 'Jackson'); // Delete the actors collection - $response = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEquals($response['body'], ''); + $this->assertEquals($response['body'], ""); // Try to get the collection and check if it has been deleted - $response = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders())); $this->assertEquals(404, $response['headers']['status-code']); @@ -1242,7 +1242,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -1251,10 +1251,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals('invalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('attributeRowWidthLimit'), 'name' => 'attributeRowWidthLimit', @@ -1274,10 +1274,10 @@ class DatabasesCustomServerTest extends Scope // Add wide string attributes to approach row width limit for ($i = 0; $i < 15; $i++) { - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => "attribute{$i}", 'size' => 1024, @@ -1289,10 +1289,10 @@ class DatabasesCustomServerTest extends Scope sleep(5); - $tooWide = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ + $tooWide = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'tooWide', 'size' => 1024, @@ -1308,7 +1308,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'invalidDocumentDatabase', @@ -1317,10 +1317,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals('invalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('testLimitException'), 'name' => 'testLimitException', @@ -1341,10 +1341,10 @@ class DatabasesCustomServerTest extends Scope // add unique attributes for indexing for ($i = 0; $i < 64; $i++) { // $this->assertEquals(true, static::getDatabase()->createAttribute('indexLimit', "test{$i}", Database::VAR_STRING, 16, true)); - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => "attribute{$i}", 'size' => 64, @@ -1356,10 +1356,10 @@ class DatabasesCustomServerTest extends Scope sleep(10); - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -1370,7 +1370,7 @@ class DatabasesCustomServerTest extends Scope $this->assertCount(0, $collection['body']['indexes']); foreach ($collection['body']['attributes'] as $attribute) { - $this->assertEquals('available', $attribute['status'], 'attribute: '.$attribute['key']); + $this->assertEquals('available', $attribute['status'], 'attribute: ' . $attribute['key']); } // Test indexLimit = 64 @@ -1378,10 +1378,10 @@ class DatabasesCustomServerTest extends Scope // Add up to the limit, then check if the next index throws IndexLimitException for ($i = 0; $i < 59; $i++) { // $this->assertEquals(true, static::getDatabase()->createIndex('indexLimit', "index{$i}", Database::INDEX_KEY, ["test{$i}"], [16])); - $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => "key_attribute{$i}", 'type' => 'key', @@ -1394,10 +1394,10 @@ class DatabasesCustomServerTest extends Scope sleep(5); - $collection = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(200, $collection['headers']['status-code']); @@ -1407,10 +1407,10 @@ class DatabasesCustomServerTest extends Scope $this->assertCount(64, $collection['body']['attributes']); $this->assertCount(59, $collection['body']['indexes']); - $tooMany = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/indexes', array_merge([ + $tooMany = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'tooMany', 'type' => 'key', @@ -1420,10 +1420,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $tooMany['headers']['status-code']); $this->assertEquals('Index limit exceeded', $tooMany['body']['message']); - $collection = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $collection = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(204, $collection['headers']['status-code']); @@ -1434,7 +1434,7 @@ class DatabasesCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'updateAttributes', @@ -1442,13 +1442,13 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(201, $database['headers']['status-code']); $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::custom('updateAttributes'), - 'name' => 'updateAttributes', + 'name' => 'updateAttributes' ]); $this->assertEquals(201, $collection['headers']['status-code']); @@ -1458,14 +1458,14 @@ class DatabasesCustomServerTest extends Scope /** * Create String Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'string', 'size' => 1024, - 'required' => false, + 'required' => false ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1473,13 +1473,13 @@ class DatabasesCustomServerTest extends Scope /** * Create Email Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'email', - 'required' => false, + 'required' => false ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1487,13 +1487,13 @@ class DatabasesCustomServerTest extends Scope /** * Create IP Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'ip', - 'required' => false, + 'required' => false ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1501,13 +1501,13 @@ class DatabasesCustomServerTest extends Scope /** * Create URL Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'url', - 'required' => false, + 'required' => false ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1515,13 +1515,13 @@ class DatabasesCustomServerTest extends Scope /** * Create Integer Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'integer', - 'required' => false, + 'required' => false ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1529,50 +1529,50 @@ class DatabasesCustomServerTest extends Scope /** * Create Float Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'float', - 'required' => false, + 'required' => false ]); /** * Create Boolean Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'boolean', - 'required' => false, + 'required' => false ]); /** * Create Datetime Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'datetime', - 'required' => false, + 'required' => false ]); /** * Create Enum Attribute */ - $attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum', array_merge([ + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'enum', 'required' => false, - 'elements' => ['lorem', 'ipsum'], + 'elements' => ['lorem', 'ipsum'] ]); $this->assertEquals(202, $attribute['headers']['status-code']); @@ -1581,10 +1581,11 @@ class DatabasesCustomServerTest extends Scope return [ 'databaseId' => $databaseId, - 'collectionId' => $collectionId, + 'collectionId' => $collectionId ]; } + /** * @depends testAttributeUpdate */ @@ -1594,72 +1595,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'lorem', + 'default' => 'lorem' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertEquals('lorem', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('lorem', $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => null, + 'default' => null ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'ipsum', + 'default' => 'ipsum' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -1668,34 +1669,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => 'i am no boolean', - 'default' => 'dolor', + 'default' => 'dolor' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 123, + 'default' => 123 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, ]); @@ -1703,24 +1704,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'default' => 'ipsum', + 'default' => 'ipsum' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/string/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, - 'default' => 'ipsum', + 'default' => 'ipsum' ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -1736,72 +1737,73 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'torsten@appwrite.io', + 'default' => 'torsten@appwrite.io' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertEquals('torsten@appwrite.io', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('torsten@appwrite.io', $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ + + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => null, + 'default' => null ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'eldad@appwrite.io', + 'default' => 'eldad@appwrite.io' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -1810,34 +1812,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => 'no boolean', - 'default' => 'torsten@appwrite.io', + 'default' => 'torsten@appwrite.io' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'i am no email', + 'default' => 'i am no email' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, ]); @@ -1845,24 +1847,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'default' => 'ipsum', + 'default' => 'ipsum' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/email/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/email/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, - 'default' => 'torsten@appwrite.io', + 'default' => 'torsten@appwrite.io' ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -1878,72 +1880,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => '127.0.0.1', + 'default' => '127.0.0.1' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertEquals('127.0.0.1', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('127.0.0.1', $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => null, + 'default' => null ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => '192.168.0.1', + 'default' => '192.168.0.1' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -1952,34 +1954,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => 'no boolean', - 'default' => '127.0.0.1', + 'default' => '127.0.0.1' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'i am no ip', + 'default' => 'i am no ip' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, ]); @@ -1987,24 +1989,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'default' => '127.0.0.1', + 'default' => '127.0.0.1' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/ip/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/ip/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, - 'default' => '127.0.0.1', + 'default' => '127.0.0.1' ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2020,72 +2022,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'http://appwrite.io', + 'default' => 'http://appwrite.io' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertEquals('http://appwrite.io', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('http://appwrite.io', $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => null, + 'default' => null ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'https://appwrite.io', + 'default' => 'https://appwrite.io' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2094,34 +2096,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => 'no boolean', - 'default' => 'https://appwrite.io', + 'default' => 'https://appwrite.io' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'i am no url', + 'default' => 'i am no url' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, ]); @@ -2129,24 +2131,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'default' => 'https://appwrite.io', + 'default' => 'https://appwrite.io' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/url/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/url/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, - 'default' => 'https://appwrite.io', + 'default' => 'https://appwrite.io' ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2162,23 +2164,23 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 123, 'min' => 0, - 'max' => 1000, + 'max' => 1000 ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2186,36 +2188,36 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(0, $new['body']['min']); $this->assertEquals(1000, $new['body']['max']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals(123, $attribute['default']); $this->assertEquals(0, $attribute['min']); $this->assertEquals(1000, $attribute['max']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => null, 'min' => 0, - 'max' => 1000, + 'max' => 1000 ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2223,23 +2225,23 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(0, $new['body']['min']); $this->assertEquals(1000, $new['body']['max']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 456, 'min' => 100, - 'max' => 2000, + 'max' => 2000 ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2250,66 +2252,66 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => 'no boolean', 'default' => 123, 'min' => 0, - 'max' => 500, + 'max' => 500 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 'i am no integer', 'min' => 0, - 'max' => 500, + 'max' => 500 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 100, 'min' => 'i am no integer', - 'max' => 500, + 'max' => 500 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 100, 'min' => 0, - 'max' => 'i am no integer', + 'max' => 'i am no integer' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 100, @@ -2319,10 +2321,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 100, @@ -2332,10 +2334,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'min' => 0, @@ -2345,10 +2347,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'default' => 50, 'min' => 0, @@ -2358,57 +2360,58 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, 'default' => 50, 'min' => 0, - 'max' => 100, + 'max' => 100 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_DEFAULT_UNSUPPORTED, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 50, 'min' => 55, - 'max' => 100, + 'max' => 100 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 105, 'min' => 50, - 'max' => 100, + 'max' => 100 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/integer/'.$key, array_merge([ + + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 50, 'min' => 200, - 'max' => 100, + 'max' => 100 ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2424,23 +2427,23 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 123.456, 'min' => 0.0, - 'max' => 1000.0, + 'max' => 1000.0 ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2448,36 +2451,36 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(0, $new['body']['min']); $this->assertEquals(1000, $new['body']['max']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals(123.456, $attribute['default']); $this->assertEquals(0, $attribute['min']); $this->assertEquals(1000, $attribute['max']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => null, 'min' => 0.0, - 'max' => 1000.0, + 'max' => 1000.0 ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2485,23 +2488,23 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(0, $new['body']['min']); $this->assertEquals(1000, $new['body']['max']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 456.789, 'min' => 123.456, - 'max' => 2000.0, + 'max' => 2000.0 ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2512,66 +2515,66 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => 'no boolean', 'default' => 123.456, 'min' => 0.0, - 'max' => 1000.0, + 'max' => 1000.0 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 'i am no integer', 'min' => 0.0, - 'max' => 500.0, + 'max' => 500.0 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 123.456, 'min' => 'i am no integer', - 'max' => 500.0, + 'max' => 500.0 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 123.456, 'min' => 0.0, - 'max' => 'i am no integer', + 'max' => 'i am no integer' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 123.456, @@ -2581,10 +2584,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 123.456, @@ -2594,10 +2597,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'min' => 0.0, @@ -2607,10 +2610,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'default' => 123.456, 'min' => 0.0, @@ -2620,57 +2623,58 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, 'default' => 123.456, 'min' => 0.0, - 'max' => 100.0, + 'max' => 100.0 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_DEFAULT_UNSUPPORTED, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 123.456, 'min' => 200.0, - 'max' => 300.0, + 'max' => 300.0 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 123.456, 'min' => 0.0, - 'max' => 100.0, + 'max' => 100.0 ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/float/'.$key, array_merge([ + + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/float/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 50.0, 'min' => 200.0, - 'max' => 100.0, + 'max' => 100.0 ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2686,72 +2690,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => true, + 'default' => true ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertEquals(true, $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals(true, $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => null, + 'default' => null ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => false, + 'default' => false ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2760,34 +2764,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => 'no boolean', - 'default' => true, + 'default' => true ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'i am no boolean', + 'default' => 'i am no boolean' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, ]); @@ -2795,24 +2799,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'default' => false, + 'default' => false ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/boolean/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, - 'default' => true, + 'default' => true ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2828,72 +2832,72 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => '1975-06-12 14:12:55+02:00', + 'default' => '1975-06-12 14:12:55+02:00' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertEquals('1975-06-12 14:12:55+02:00', $new['body']['default']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('1975-06-12 14:12:55+02:00', $attribute['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => null, + 'default' => null ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); $this->assertNull($new['body']['default']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => '1965-06-12 14:12:55+02:00', + 'default' => '1965-06-12 14:12:55+02:00' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2902,34 +2906,34 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => 'no boolean', - 'default' => '1975-06-12 14:12:55+02:00', + 'default' => '1975-06-12 14:12:55+02:00' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, - 'default' => 'i am no datetime', + 'default' => 'i am no datetime' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, ]); @@ -2937,24 +2941,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'default' => '1975-06-12 14:12:55+02:00', + 'default' => '1975-06-12 14:12:55+02:00' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/datetime/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, - 'default' => '1975-06-12 14:12:55+02:00', + 'default' => '1975-06-12 14:12:55+02:00' ]); $this->assertEquals(400, $update['headers']['status-code']); @@ -2970,22 +2974,22 @@ class DatabasesCustomServerTest extends Scope $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'elements' => ['lorem', 'ipsum', 'dolor'], 'required' => false, - 'default' => 'lorem', + 'default' => 'lorem' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -2995,13 +2999,13 @@ class DatabasesCustomServerTest extends Scope $this->assertContains('ipsum', $new['body']['elements']); $this->assertContains('dolor', $new['body']['elements']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('lorem', $attribute['default']); @@ -3010,22 +3014,22 @@ class DatabasesCustomServerTest extends Scope $this->assertContains('ipsum', $attribute['elements']); $this->assertContains('dolor', $attribute['elements']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'elements' => ['lorem', 'ipsum', 'dolor'], 'required' => false, - 'default' => null, + 'default' => null ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -3035,22 +3039,22 @@ class DatabasesCustomServerTest extends Scope $this->assertContains('ipsum', $new['body']['elements']); $this->assertContains('dolor', $new['body']['elements']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'elements' => ['ipsum', 'dolor'], 'required' => false, - 'default' => 'dolor', + 'default' => 'dolor' ]); $this->assertEquals(200, $update['headers']['status-code']); - $new = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key, array_merge([ + $new = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertFalse($new['body']['required']); @@ -3062,36 +3066,36 @@ class DatabasesCustomServerTest extends Scope /** * Test against failure */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'elements' => [], 'required' => false, - 'default' => 'lorem', + 'default' => 'lorem' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'elements' => ['ipsum', 'dolor'], 'required' => false, - 'default' => 'lorem', + 'default' => 'lorem' ]); $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::ATTRIBUTE_VALUE_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => 'no boolean', 'default' => 'lorem', @@ -3101,10 +3105,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 123, @@ -3114,10 +3118,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 'lorem', @@ -3127,10 +3131,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => false, 'default' => 'lorem', @@ -3139,10 +3143,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, 'elements' => ['lorem', 'ipsum', 'dolor'], @@ -3151,10 +3155,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'default' => 'lorem', 'elements' => ['lorem', 'ipsum', 'dolor'], @@ -3163,10 +3167,10 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(400, $update['headers']['status-code']); $this->assertEquals(AppwriteException::GENERAL_ARGUMENT_INVALID, $update['body']['type']); - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/enum/'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/enum/' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'required' => true, 'default' => 'lorem', @@ -3188,51 +3192,51 @@ class DatabasesCustomServerTest extends Scope $attributes = [ 'string' => [ 'required' => false, - 'default' => 'ipsum', + 'default' => 'ipsum' ], 'email' => [ 'required' => false, - 'default' => 'eldad@appwrite.io', + 'default' => 'eldad@appwrite.io' ], 'ip' => [ 'required' => false, - 'default' => '127.0.0.1', + 'default' => '127.0.0.1' ], 'url' => [ 'required' => false, - 'default' => 'https://appwrite.io', + 'default' => 'https://appwrite.io' ], 'integer' => [ 'required' => false, 'default' => 5, 'min' => 0, - 'max' => 10, + 'max' => 10 ], 'float' => [ 'required' => false, 'default' => 5.5, 'min' => 0.0, - 'max' => 10.0, + 'max' => 10.0 ], 'datetime' => [ 'required' => false, - 'default' => '1975-06-12 14:12:55+02:00', + 'default' => '1975-06-12 14:12:55+02:00' ], 'enum' => [ 'elements' => ['lorem', 'ipsum', 'dolor'], 'required' => false, - 'default' => 'lorem', - ], + 'default' => 'lorem' + ] ]; foreach ($attributes as $key => $payload) { /** * Check if Database exists */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/i_dont_exist/collections/'.$collectionId.'/attributes/'.$key.'/unknown_'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/i_dont_exist/collections/' . $collectionId . '/attributes/' . $key . '/unknown_' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), $payload); $this->assertEquals(404, $update['headers']['status-code']); @@ -3241,10 +3245,10 @@ class DatabasesCustomServerTest extends Scope /** * Check if Collection exists */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/i_dont_exist/attributes/'.$key.'/unknown_'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/i_dont_exist/attributes/' . $key . '/unknown_' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), $payload); $this->assertEquals(404, $update['headers']['status-code']); @@ -3253,10 +3257,10 @@ class DatabasesCustomServerTest extends Scope /** * Check if Attribute exists */ - $update = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collectionId.'/attributes/'.$key.'/unknown_'.$key, array_merge([ + $update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/' . $key . '/unknown_' . $key, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), $payload); $this->assertEquals(404, $update['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php index 7f28097e70..b1d197f010 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Databases; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -22,7 +22,7 @@ class DatabasesPermissionsGuestTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'InvalidDocumentDatabase', @@ -31,7 +31,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals('InvalidDocumentDatabase', $database['body']['name']); $databaseId = $database['body']['$id']; - $publicMovies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ + $publicMovies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Movies', 'permissions' => [ @@ -41,7 +41,7 @@ class DatabasesPermissionsGuestTest extends Scope Permission::delete(Role::any()), ], ]); - $privateMovies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ + $privateMovies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Movies', 'permissions' => [], @@ -51,12 +51,12 @@ class DatabasesPermissionsGuestTest extends Scope $publicCollection = ['id' => $publicMovies['body']['$id']]; $privateCollection = ['id' => $privateMovies['body']['$id']]; - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$publicCollection['id'].'/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $publicCollection['id'] . '/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$privateCollection['id'].'/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $privateCollection['id'] . '/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, @@ -93,14 +93,14 @@ class DatabasesPermissionsGuestTest extends Scope $privateCollectionId = $data['privateCollectionId']; $databaseId = $data['databaseId']; - $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents', $this->getServerHeader(), [ + $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', ], 'permissions' => $permissions, ]); - $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents', $this->getServerHeader(), [ + $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', @@ -114,11 +114,11 @@ class DatabasesPermissionsGuestTest extends Scope $roles = Authorization::getRoles(); Authorization::cleanRoles(); - $publicDocuments = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents', [ + $publicDocuments = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); - $privateDocuments = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents', [ + $privateDocuments = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -148,20 +148,20 @@ class DatabasesPermissionsGuestTest extends Scope $roles = Authorization::getRoles(); Authorization::cleanRoles(); - $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents', [ + $publicResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', - ], + ] ]); $publicDocumentId = $publicResponse['body']['$id']; $this->assertEquals(201, $publicResponse['headers']['status-code']); - $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents', [ + $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -174,7 +174,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(401, $privateResponse['headers']['status-code']); // Create a document in private collection with API key so we can test that update and delete are also not allowed - $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents', $this->getServerHeader(), [ + $privateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', @@ -184,7 +184,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(201, $privateResponse['headers']['status-code']); $privateDocumentId = $privateResponse['body']['$id']; - $publicDocument = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents/'.$publicDocumentId, [ + $publicDocument = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents/' . $publicDocumentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -196,7 +196,7 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(200, $publicDocument['headers']['status-code']); $this->assertEquals('Thor: Ragnarok', $publicDocument['body']['title']); - $privateDocument = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents/'.$privateDocumentId, [ + $privateDocument = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents/' . $privateDocumentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -207,14 +207,14 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals(401, $privateDocument['headers']['status-code']); - $publicDocument = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$publicCollectionId.'/documents/'.$publicDocumentId, [ + $publicDocument = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $publicCollectionId . '/documents/' . $publicDocumentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(204, $publicDocument['headers']['status-code']); - $privateDocument = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$privateCollectionId.'/documents/'.$privateDocumentId, [ + $privateDocument = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $privateCollectionId . '/documents/' . $privateDocumentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -231,7 +231,7 @@ class DatabasesPermissionsGuestTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'GuestPermissionsWrite', @@ -240,18 +240,18 @@ class DatabasesPermissionsGuestTest extends Scope $this->assertEquals('GuestPermissionsWrite', $database['body']['name']); $databaseId = $database['body']['$id']; - $movies = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ + $movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Movies', 'permissions' => [ Permission::create(Role::any()), ], - 'documentSecurity' => true, + 'documentSecurity' => true ]); $moviesId = $movies['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, @@ -259,7 +259,7 @@ class DatabasesPermissionsGuestTest extends Scope sleep(1); - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$moviesId.'/documents', [ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -269,7 +269,7 @@ class DatabasesPermissionsGuestTest extends Scope ], 'permissions' => [ Permission::read(Role::any()), - ], + ] ]); $this->assertEquals(201, $document['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsMemberTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsMemberTest.php index 73393b7efa..860fb7fb12 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsMemberTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsMemberTest.php @@ -110,7 +110,6 @@ class DatabasesPermissionsMemberTest extends Scope * Data providers lose object state so explicitly pass [$users, $collections] to each iteration * * @return array - * * @throws \Exception */ public function testSetupDatabase(): array @@ -125,7 +124,7 @@ class DatabasesPermissionsMemberTest extends Scope $databaseId = $db['body']['$id']; - $public = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ + $public = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Movies', 'permissions' => [ @@ -139,14 +138,14 @@ class DatabasesPermissionsMemberTest extends Scope $this->assertEquals(201, $public['headers']['status-code']); $this->collections = ['public' => $public['body']['$id']]; - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$this->collections['public'].'/attributes/string', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $this->collections['public'] . '/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); $this->assertEquals(202, $response['headers']['status-code']); - $private = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ + $private = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Private Movies', 'permissions' => [ @@ -160,14 +159,14 @@ class DatabasesPermissionsMemberTest extends Scope $this->assertEquals(201, $private['headers']['status-code']); $this->collections['private'] = $private['body']['$id']; - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$this->collections['private'].'/attributes/string', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $this->collections['private'] . '/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); $this->assertEquals(202, $response['headers']['status-code']); - $doconly = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', $this->getServerHeader(), [ + $doconly = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [ 'collectionId' => ID::unique(), 'name' => 'Document Only Movies', 'permissions' => [], @@ -176,7 +175,7 @@ class DatabasesPermissionsMemberTest extends Scope $this->assertEquals(201, $private['headers']['status-code']); $this->collections['doconly'] = $doconly['body']['$id']; - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$this->collections['doconly'].'/attributes/string', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $this->collections['doconly'] . '/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, @@ -188,13 +187,12 @@ class DatabasesPermissionsMemberTest extends Scope return [ 'users' => $this->users, 'collections' => $this->collections, - 'databaseId' => $databaseId, + 'databaseId' => $databaseId ]; } /** * Data provider params are passed before test dependencies - * * @dataProvider permissionsProvider * @depends testSetupDatabase */ @@ -204,41 +202,41 @@ class DatabasesPermissionsMemberTest extends Scope $collections = $data['collections']; $databaseId = $data['databaseId']; - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collections['public'].'/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collections['public'] . '/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', ], - 'permissions' => $permissions, + 'permissions' => $permissions ]); $this->assertEquals(201, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collections['private'].'/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collections['private'] . '/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', ], - 'permissions' => $permissions, + 'permissions' => $permissions ]); $this->assertEquals(201, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collections['doconly'].'/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collections['doconly'] . '/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', ], - 'permissions' => $permissions, + 'permissions' => $permissions ]); $this->assertEquals(201, $response['headers']['status-code']); /** * Check "any" permission collection */ - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collections['public'].'/documents', [ + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collections['public'] . '/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users['user1']['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users['user1']['session'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -247,11 +245,11 @@ class DatabasesPermissionsMemberTest extends Scope /** * Check "users" permission collection */ - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collections['private'].'/documents', [ + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collections['private'] . '/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users['user1']['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users['user1']['session'], ]); $this->assertEquals(200, $documents['headers']['status-code']); @@ -260,11 +258,11 @@ class DatabasesPermissionsMemberTest extends Scope /** * Check "user:user1" document only permission collection */ - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collections['doconly'].'/documents', [ + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collections['doconly'] . '/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users['user1']['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users['user1']['session'], ]); $this->assertEquals(200, $documents['headers']['status-code']); diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsScope.php b/tests/e2e/Services/Databases/DatabasesPermissionsScope.php index a78153cf7d..181231adc5 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsScope.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsScope.php @@ -7,7 +7,6 @@ use Tests\E2E\Client; trait DatabasesPermissionsScope { public array $users = []; - public array $teams = []; public function createUser(string $id, string $email, string $password = 'test123!'): array @@ -19,7 +18,7 @@ trait DatabasesPermissionsScope ], [ 'userId' => $id, 'email' => $email, - 'password' => $password, + 'password' => $password ]); $this->assertEquals(201, $user['headers']['status-code']); @@ -33,7 +32,7 @@ trait DatabasesPermissionsScope 'password' => $password, ]); - $session = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $user = [ '$id' => $user['body']['$id'], @@ -54,7 +53,7 @@ trait DatabasesPermissionsScope { $team = $this->client->call(Client::METHOD_POST, '/teams', $this->getServerHeader(), [ 'teamId' => $id, - 'name' => $name, + 'name' => $name ]); $this->teams[$id] = $team['body']; @@ -63,16 +62,16 @@ trait DatabasesPermissionsScope public function addToTeam(string $user, string $team, array $roles = []): array { - $membership = $this->client->call(Client::METHOD_POST, '/teams/'.$team.'/memberships', $this->getServerHeader(), [ + $membership = $this->client->call(Client::METHOD_POST, '/teams/' . $team . '/memberships', $this->getServerHeader(), [ 'teamId' => $team, 'email' => $this->getCreatedUser($user)['email'], 'roles' => $roles, - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); return [ 'user' => $membership['body']['userId'], - 'membership' => $membership['body']['$id'], + 'membership' => $membership['body']['$id'] ]; } @@ -81,7 +80,7 @@ trait DatabasesPermissionsScope return [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]; } } diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php index e592902ab8..dcbf3e4bff 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Databases; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -17,7 +17,6 @@ class DatabasesPermissionsTeamTest extends Scope use DatabasesPermissionsScope; public array $collections = []; - public string $databaseId = 'testpermissiondb'; public function createTeams(): array @@ -45,7 +44,7 @@ class DatabasesPermissionsTeamTest extends Scope ]); $this->assertEquals(201, $db['headers']['status-code']); - $collection1 = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections', $this->getServerHeader(), [ + $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections', $this->getServerHeader(), [ 'collectionId' => ID::custom('collection1'), 'name' => 'Collection 1', 'permissions' => [ @@ -58,13 +57,13 @@ class DatabasesPermissionsTeamTest extends Scope $this->collections['collection1'] = $collection1['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$this->collections['collection1'].'/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $this->collections['collection1'] . '/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, ]); - $collection2 = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections', $this->getServerHeader(), [ + $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections', $this->getServerHeader(), [ 'collectionId' => ID::custom('collection2'), 'name' => 'Collection 2', 'permissions' => [ @@ -72,12 +71,12 @@ class DatabasesPermissionsTeamTest extends Scope Permission::create(Role::team($teams['team2']['$id'], 'owner')), Permission::update(Role::team($teams['team2']['$id'], 'owner')), Permission::delete(Role::team($teams['team2']['$id'], 'owner')), - ], + ] ]); $this->collections['collection2'] = $collection2['body']['$id']; - $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$this->collections['collection2'].'/attributes/string', $this->getServerHeader(), [ + $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $this->collections['collection2'] . '/attributes/string', $this->getServerHeader(), [ 'key' => 'title', 'size' => 256, 'required' => true, @@ -125,7 +124,6 @@ class DatabasesPermissionsTeamTest extends Scope * * Data providers lose object state * so explicitly pass $users to each iteration - * * @return array $users */ public function testSetupDatabase(): array @@ -142,7 +140,7 @@ class DatabasesPermissionsTeamTest extends Scope $this->createCollections($this->teams); - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$this->collections['collection1'].'/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $this->collections['collection1'] . '/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Lorem', @@ -150,7 +148,7 @@ class DatabasesPermissionsTeamTest extends Scope ]); $this->assertEquals(201, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$this->collections['collection2'].'/documents', $this->getServerHeader(), [ + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $this->collections['collection2'] . '/documents', $this->getServerHeader(), [ 'documentId' => ID::unique(), 'data' => [ 'title' => 'Ipsum', @@ -163,17 +161,16 @@ class DatabasesPermissionsTeamTest extends Scope /** * Data provider params are passed before test dependencies - * * @depends testSetupDatabase * @dataProvider readDocumentsProvider */ public function testReadDocuments($user, $collection, $success, $users) { - $documents = $this->client->call(Client::METHOD_GET, '/databases/'.$this->databaseId.'/collections/'.$collection.'/documents', [ + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $this->databaseId . '/collections/' . $collection . '/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users[$user]['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users[$user]['session'], ]); if ($success) { @@ -189,11 +186,11 @@ class DatabasesPermissionsTeamTest extends Scope */ public function testWriteDocuments($user, $collection, $success, $users) { - $documents = $this->client->call(Client::METHOD_POST, '/databases/'.$this->databaseId.'/collections/'.$collection.'/documents', [ + $documents = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/collections/' . $collection . '/documents', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$users[$user]['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users[$user]['session'], ], [ 'documentId' => ID::unique(), 'data' => [ diff --git a/tests/e2e/Services/Functions/FunctionsBase.php b/tests/e2e/Services/Functions/FunctionsBase.php index ad41ab7e47..c45ebbe068 100644 --- a/tests/e2e/Services/Functions/FunctionsBase.php +++ b/tests/e2e/Services/Functions/FunctionsBase.php @@ -8,12 +8,11 @@ use Utopia\CLI\Console; trait FunctionsBase { protected string $stdout = ''; - protected string $stderr = ''; protected function packageCode($folder) { - Console::execute('cd '.realpath(__DIR__.'/../../../resources/functions')."/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr); + Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr); } // /** diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php index fec65fd3b9..e28bdd233f 100644 --- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php @@ -2,9 +2,9 @@ namespace Tests\E2E\Services\Functions; -use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Client; use Tests\E2E\Scopes\SideConsole; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; @@ -41,13 +41,13 @@ class FunctionsConsoleClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test Failure', 'execute' => ['some-random-string'], - 'runtime' => 'php-8.0', + 'runtime' => 'php-8.0' ]); $this->assertEquals(400, $response['headers']['status-code']); return [ - 'functionId' => $function['body']['$id'], + 'functionId' => $function['body']['$id'] ]; } @@ -59,20 +59,21 @@ class FunctionsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/usage', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '232h', + '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'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '24h', + 'range' => '24h' ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -80,11 +81,12 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/usage', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '24h', + 'range' => '24h' ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -107,12 +109,13 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/variables', array_merge([ + + $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', + 'value' => 'TESTINGVALUE' ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -121,12 +124,13 @@ class FunctionsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/variables', array_merge([ + + $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', + 'value' => 'ANOTHER_TESTINGVALUE' ]); $this->assertEquals(409, $response['headers']['status-code']); @@ -134,28 +138,28 @@ class FunctionsConsoleClientTest extends Scope return array_merge( $data, [ - 'variableId' => $variableId, + 'variableId' => $variableId ] ); - $longKey = str_repeat('A', 256); - $response = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/variables', array_merge([ + $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', + '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([ + $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, + 'value' => $longValue ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -169,16 +173,17 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(1, count($response['body']['variables'])); + $this->assertEquals(1, sizeof($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']); + $this->assertEquals("APP_TEST", $response['body']['variables'][0]['key']); + $this->assertEquals("TESTINGVALUE", $response['body']['variables'][0]['value']); /** * Test for FAILURE @@ -195,19 +200,21 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('APP_TEST', $response['body']['key']); - $this->assertEquals('TESTINGVALUE', $response['body']['value']); + $this->assertEquals("APP_TEST", $response['body']['key']); + $this->assertEquals("TESTINGVALUE", $response['body']['value']); /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables/NON_EXISTING_VARIABLE', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/NON_EXISTING_VARIABLE', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -225,28 +232,29 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'key' => 'APP_TEST_UPDATE', - 'value' => 'TESTINGVALUEUPDATED', + 'value' => 'TESTINGVALUEUPDATED' ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('APP_TEST_UPDATE', $response['body']['key']); - $this->assertEquals('TESTINGVALUEUPDATED', $response['body']['value']); + $this->assertEquals("APP_TEST_UPDATE", $response['body']['key']); + $this->assertEquals("TESTINGVALUEUPDATED", $response['body']['value']); - $variable = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + $variable = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $variable['headers']['status-code']); - $this->assertEquals('APP_TEST_UPDATE', $variable['body']['key']); - $this->assertEquals('TESTINGVALUEUPDATED', $variable['body']['value']); + $this->assertEquals("APP_TEST_UPDATE", $variable['body']['key']); + $this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']); - $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -254,55 +262,56 @@ class FunctionsConsoleClientTest extends Scope ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('APP_TEST_UPDATE_2', $response['body']['key']); - $this->assertEquals('TESTINGVALUEUPDATED', $response['body']['value']); + $this->assertEquals("APP_TEST_UPDATE_2", $response['body']['key']); + $this->assertEquals("TESTINGVALUEUPDATED", $response['body']['value']); - $variable = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + $variable = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $variable['headers']['status-code']); - $this->assertEquals('APP_TEST_UPDATE_2', $variable['body']['key']); - $this->assertEquals('TESTINGVALUEUPDATED', $variable['body']['value']); + $this->assertEquals("APP_TEST_UPDATE_2", $variable['body']['key']); + $this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']); /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'value' => 'TESTINGVALUEUPDATED_2', + 'value' => 'TESTINGVALUEUPDATED_2' ]); $this->assertEquals(400, $response['headers']['status-code']); - $longKey = str_repeat('A', 256); - $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + $longKey = str_repeat("A", 256); + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'key' => $longKey, - 'value' => 'TESTINGVALUEUPDATED', + 'value' => 'TESTINGVALUEUPDATED' ]); $this->assertEquals(400, $response['headers']['status-code']); - $longValue = str_repeat('#', 8193); - $response = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + $longValue = str_repeat("#", 8193); + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'key' => 'APP_TEST_UPDATE', - 'value' => $longValue, + 'value' => $longValue ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -318,26 +327,28 @@ class FunctionsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'].'/variables/'.$data['variableId'], array_merge([ + + $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/variables', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(0, count($response['body']['variables'])); + $this->assertEquals(0, sizeof($response['body']['variables'])); $this->assertEquals(0, $response['body']['total']); /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'].'/variables/NON_EXISTING_VARIABLE', array_merge([ + + $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/variables/NON_EXISTING_VARIABLE', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php index b92308d348..713814e17f 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php @@ -65,7 +65,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/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'], @@ -74,7 +74,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/variables', [ + $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'], @@ -83,7 +83,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/variables', [ + $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'], @@ -97,17 +97,17 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $variable3['headers']['status-code']); $folder = 'php'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $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/' . $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, + 'activate' => true ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -117,7 +117,7 @@ class FunctionsCustomClientTest extends Scope // Wait for deployment to be built. sleep(20); - $function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$function['body']['$id'].'/deployments/'.$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'], @@ -125,7 +125,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(200, $function['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', [ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -134,7 +134,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(401, $execution['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', array_merge([ + $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()), [ @@ -144,7 +144,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(202, $execution['headers']['status-code']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$function['body']['$id'], [ + $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'], @@ -180,7 +180,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ + $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -189,7 +189,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ + $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -198,7 +198,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ + $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -212,17 +212,17 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $variable3['headers']['status-code']); $folder = 'php-fn'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', [ + $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional - 'activate' => true, + 'activate' => true ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -232,7 +232,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); - $function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, [ + $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -240,12 +240,12 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(200, $function['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true, + 'async' => true ]); $this->assertEquals(202, $execution['headers']['status-code']); @@ -254,7 +254,7 @@ class FunctionsCustomClientTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -277,7 +277,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals($projectId, $output['APPWRITE_FUNCTION_PROJECT_ID']); return [ - 'functionId' => $functionId, + 'functionId' => $functionId ]; } @@ -311,17 +311,17 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); $folder = 'php-fn'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', [ + $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional - 'activate' => true, + 'activate' => true ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -332,7 +332,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); // Why do we have to do this? - $function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, [ + $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -340,7 +340,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(200, $function['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', [ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], [ @@ -365,7 +365,7 @@ class FunctionsCustomClientTest extends Scope 'timeout' => 10, ]); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', [ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -386,19 +386,19 @@ class FunctionsCustomClientTest extends Scope $projectId = $this->getProject()['$id']; $apikey = $this->getProject()['apiKey']; - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true, + 'async' => true ]); $this->assertEquals(202, $execution['headers']['status-code']); sleep(20); - $base = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ + $base = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -409,71 +409,71 @@ class FunctionsCustomClientTest extends Scope $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', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => ['limit(1)'], + 'queries' => [ 'limit(1)' ] ]); $this->assertEquals(200, $executions['headers']['status-code']); $this->assertCount(1, $executions['body']['executions']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => ['offset(1)'], + 'queries' => [ 'offset(1)' ] ]); $this->assertEquals(200, $executions['headers']['status-code']); $this->assertCount(1, $executions['body']['executions']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => ['equal("status", ["completed"])'], + 'queries' => [ 'equal("status", ["completed"])' ] ]); $this->assertEquals(200, $executions['headers']['status-code']); $this->assertCount(2, $executions['body']['executions']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => ['equal("status", ["failed"])'], + 'queries' => [ 'equal("status", ["failed"])' ] ]); $this->assertEquals(200, $executions['headers']['status-code']); $this->assertCount(0, $executions['body']['executions']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => ['cursorAfter("'.$base['body']['executions'][0]['$id'].'")'], + 'queries' => [ 'cursorAfter("' . $base['body']['executions'][0]['$id'] . '")' ], ]); $this->assertCount(1, $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', [ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ - 'queries' => ['cursorBefore("'.$base['body']['executions'][1]['$id'].'")'], + 'queries' => [ 'cursorBefore("' . $base['body']['executions'][1]['$id'] . '")' ], ]); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$functionId, [ + $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'], @@ -487,6 +487,7 @@ class FunctionsCustomClientTest extends Scope /** * Test for SUCCESS */ + $projectId = $this->getProject()['$id']; $apikey = $this->getProject()['apiKey']; @@ -507,7 +508,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ + $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -516,7 +517,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ + $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -525,7 +526,7 @@ class FunctionsCustomClientTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', [ + $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -539,17 +540,17 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $variable3['headers']['status-code']); $folder = 'php-fn'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', [ + $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ], [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional - 'activate' => true, + 'activate' => true ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -559,7 +560,7 @@ class FunctionsCustomClientTest extends Scope // Wait for deployment to be built. sleep(20); - $function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, [ + $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, @@ -567,7 +568,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(200, $function['headers']['status-code']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ @@ -595,7 +596,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEmpty($execution['body']['stderr']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$functionId, [ + $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'], diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 6ad1e578cb..ab931f14e4 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -8,6 +8,7 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -55,7 +56,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(10, $response1['body']['timeout']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -63,7 +64,7 @@ class FunctionsCustomServerTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ + $variable2 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -71,7 +72,7 @@ class FunctionsCustomServerTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ + $variable3 = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -108,7 +109,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => $data['functionId'], + 'search' => $data['functionId'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -119,7 +120,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(1)'], + 'queries' => [ 'limit(1)' ] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -129,7 +130,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(1)'], + 'queries' => [ 'offset(1)' ] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -139,7 +140,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("enabled", true)'], + 'queries' => [ 'equal("enabled", true)' ] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -149,7 +150,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("enabled", false)'], + 'queries' => [ 'equal("enabled", false)' ] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -159,7 +160,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Test', + 'search' => 'Test' ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -170,7 +171,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'php-8.0', + 'search' => 'php-8.0' ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -197,7 +198,7 @@ class FunctionsCustomServerTest extends Scope $this->assertNotEmpty($response['body']['$id']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$response['body']['$id'].'/variables', array_merge([ + $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()), [ @@ -205,7 +206,7 @@ class FunctionsCustomServerTest extends Scope 'value' => 'funcValue1', ]); - $variable2 = $this->client->call(Client::METHOD_POST, '/functions/'.$response['body']['$id'].'/variables', array_merge([ + $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()), [ @@ -213,7 +214,7 @@ class FunctionsCustomServerTest extends Scope 'value' => 'funcValue2', ]); - $variable3 = $this->client->call(Client::METHOD_POST, '/functions/'.$response['body']['$id'].'/variables', array_merge([ + $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()), [ @@ -241,7 +242,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("'.$functions['body']['functions'][0]['$id'].'")'], + 'queries' => [ 'cursorAfter("' . $functions['body']['functions'][0]['$id'] . '")' ], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -252,7 +253,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("'.$functions['body']['functions'][1]['$id'].'")'], + 'queries' => [ 'cursorBefore("' . $functions['body']['functions'][1]['$id'] . '")' ], ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -266,7 +267,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("unknown")'], + 'queries' => [ 'cursorAfter("unknown")' ], ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -282,7 +283,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'], array_merge([ + $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -311,7 +312,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $response1 = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'], array_merge([ + $response1 = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -354,16 +355,16 @@ class FunctionsCustomServerTest extends Scope * Test for SUCCESS */ $folder = 'php'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/deployments', array_merge([ + $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()), [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), - 'activate' => true, + 'activate' => true ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -387,30 +388,31 @@ class FunctionsCustomServerTest extends Scope /** * Test for Large Code File SUCCESS */ + $folder = 'php-large'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); $chunkSize = 5 * 1024 * 1024; - $handle = @fopen($code, 'rb'); + $handle = @fopen($code, "rb"); $mimeType = 'application/x-gzip'; $counter = 0; $size = filesize($code); $headers = [ 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ]; $id = ''; - while (! feof($handle)) { - $curlFile = new \CURLFile('data://'.$mimeType.';base64,'.base64_encode(@fread($handle, $chunkSize)), $mimeType, 'php-large-fx.tar.gz'); - $headers['content-range'] = 'bytes '.($counter * $chunkSize).'-'.min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1).'/'.$size; - if (! empty($id)) { + while (!feof($handle)) { + $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'php-large-fx.tar.gz'); + $headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size; + 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/' . $data['functionId'] . '/deployments', array_merge($headers, $this->getHeaders()), [ 'entrypoint' => 'index.php', 'code' => $curlFile, - 'activate' => true, + 'activate' => true ]); $counter++; $id = $largeTag['body']['$id']; @@ -434,7 +436,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/functions/'.$data['functionId'].'/deployments/'.$data['deploymentId'], array_merge([ + $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'], ], $this->getHeaders()), []); @@ -461,7 +463,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([ + $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())); @@ -474,11 +476,11 @@ class FunctionsCustomServerTest extends Scope /** * Test search queries */ - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([ + $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'], + 'search' => $data['functionId'] ])); $this->assertEquals($function['headers']['status-code'], 200); @@ -487,51 +489,51 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(2, $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([ + $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()), [ - 'queries' => ['limit(1)'], + 'queries' => [ 'limit(1)' ] ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertCount(1, $function['body']['deployments']); - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([ + $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()), [ - 'queries' => ['offset(1)'], + 'queries' => [ 'offset(1)' ] ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertCount(1, $function['body']['deployments']); - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([ + $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()), [ - 'queries' => ['equal("entrypoint", "index.php")'], + 'queries' => [ 'equal("entrypoint", "index.php")' ] ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertCount(2, $function['body']['deployments']); - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([ + $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()), [ - 'queries' => ['equal("entrypoint", "index.js")'], + 'queries' => [ 'equal("entrypoint", "index.js")' ] ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertCount(0, $function['body']['deployments']); - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([ + $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', + 'search' => 'Test' ])); $this->assertEquals($function['headers']['status-code'], 200); @@ -540,11 +542,11 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(2, $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([ + $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', + 'search' => 'php-8.0' ])); $this->assertEquals($function['headers']['status-code'], 200); @@ -564,7 +566,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments/'.$data['deploymentId'], array_merge([ + $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())); @@ -578,7 +580,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for FAILURE */ - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments/x', array_merge([ + $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())); @@ -596,7 +598,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/executions', array_merge([ + $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()), [ @@ -618,7 +620,7 @@ class FunctionsCustomServerTest extends Scope sleep(10); - $execution = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions/'.$executionId, array_merge([ + $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/' . $executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -642,6 +644,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for FAILURE */ + sleep(20); return array_merge($data, ['executionId' => $executionId]); @@ -655,7 +658,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([ + $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())); @@ -666,31 +669,31 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(1, $function['body']['executions']); $this->assertEquals($function['body']['executions'][0]['$id'], $data['executionId']); - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([ + $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()), [ - 'queries' => ['limit(1)'], + 'queries' => [ 'limit(1)' ] ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']['executions']); - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([ + $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()), [ - 'queries' => ['offset(1)'], + 'queries' => [ 'offset(1)' ] ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(0, $response['body']['executions']); - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([ + $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()), [ - 'queries' => ['equal("trigger", "http")'], + 'queries' => [ 'equal("trigger", "http")' ] ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -699,7 +702,8 @@ class FunctionsCustomServerTest extends Scope /** * Test search queries */ - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([ + + $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()), [ @@ -712,7 +716,7 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(1, $response['body']['executions']); $this->assertEquals($data['functionId'], $response['body']['executions'][0]['functionId']); - $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([ + $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()), [ @@ -737,7 +741,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/executions', array_merge([ + $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()), [ @@ -765,7 +769,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions/'.$data['executionId'], array_merge([ + $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())); @@ -776,7 +780,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for FAILURE */ - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions/x', array_merge([ + $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())); @@ -794,7 +798,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'].'/deployments/'.$data['deploymentId'], array_merge([ + $function = $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())); @@ -802,7 +806,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(204, $function['headers']['status-code']); $this->assertEmpty($function['body']); - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments/'.$data['deploymentId'], array_merge([ + $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())); @@ -824,7 +828,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'], array_merge([ + $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -832,7 +836,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(204, $function['headers']['status-code']); $this->assertEmpty($function['body']); - $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'], array_merge([ + $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -852,7 +856,7 @@ class FunctionsCustomServerTest extends Scope $entrypoint = 'index.php'; $timeout = 2; $folder = 'timeout'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ @@ -860,7 +864,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test '.$name, + 'name' => 'Test ' . $name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -870,7 +874,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([ + $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()), [ @@ -884,7 +888,7 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(40); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -897,7 +901,7 @@ class FunctionsCustomServerTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -916,7 +920,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals($executions['body']['executions'][0]['stderr'], 'An internal curl error has occurred within the executor! Error Msg: Operation timed out'); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$functionId, [ + $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'], @@ -934,7 +938,7 @@ class FunctionsCustomServerTest extends Scope $entrypoint = 'index.php'; $timeout = 2; $folder = 'php-fn'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ @@ -942,7 +946,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test '.$name, + 'name' => 'Test ' . $name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -952,13 +956,13 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([ + $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)), - 'activate' => true, + 'activate' => true ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -967,19 +971,19 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(20); - $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, array_merge([ + $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([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true, + 'async' => true ]); $executionId = $execution['body']['$id'] ?? ''; @@ -990,7 +994,7 @@ class FunctionsCustomServerTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1000,7 +1004,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $executions['headers']['status-code']); $this->assertEquals('completed', $executions['body']['status']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']); + $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); $this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); @@ -1013,7 +1017,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); $this->assertStringContainsString('Amazing Function Log', $executions['body']['stdout']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1027,7 +1031,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$functionId, [ + $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'], @@ -1036,11 +1040,12 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } + public function testCreateCustomNodeExecution() { $name = 'node-18.0'; $folder = 'node'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); $entrypoint = 'index.js'; @@ -1051,7 +1056,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test '.$name, + 'name' => 'Test ' . $name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -1062,7 +1067,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); // Create variable - $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1072,7 +1077,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $variable['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([ + $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()), [ @@ -1087,12 +1092,12 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(20); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true, + 'async' => true ]); $executionId = $execution['body']['$id'] ?? ''; @@ -1103,7 +1108,7 @@ class FunctionsCustomServerTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1113,7 +1118,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $executions['headers']['status-code']); $this->assertEquals('completed', $executions['body']['status']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']); + $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); $this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); @@ -1125,7 +1130,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1139,7 +1144,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$functionId, [ + $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'], @@ -1152,7 +1157,7 @@ class FunctionsCustomServerTest extends Scope { $name = 'python-3.9'; $folder = 'python'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); $entrypoint = 'main.py'; @@ -1163,7 +1168,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test '.$name, + 'name' => 'Test ' . $name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -1174,7 +1179,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1184,7 +1189,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $variable['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([ + $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()), [ @@ -1199,12 +1204,12 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(60); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true, + 'async' => true ]); $executionId = $execution['body']['$id'] ?? ''; @@ -1215,7 +1220,7 @@ class FunctionsCustomServerTest extends Scope sleep(60); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1225,7 +1230,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $executions['headers']['status-code']); $this->assertEquals('completed', $executions['body']['status']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']); + $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); $this->assertEquals('Python', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); @@ -1238,7 +1243,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1252,7 +1257,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$functionId, [ + $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'], @@ -1378,7 +1383,7 @@ class FunctionsCustomServerTest extends Scope { $name = 'ruby-3.1'; $folder = 'ruby'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); $entrypoint = 'main.rb'; @@ -1389,7 +1394,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'functionId' => ID::unique(), - 'name' => 'Test '.$name, + 'name' => 'Test ' . $name, 'runtime' => $name, 'events' => [], 'timeout' => $timeout, @@ -1400,7 +1405,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); /** Create Variables */ - $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1410,7 +1415,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $variable['headers']['status-code']); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([ + $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()), [ @@ -1425,12 +1430,12 @@ class FunctionsCustomServerTest extends Scope // Allow build step to run sleep(60); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => 'foobar', - 'async' => true, + 'async' => true ]); $executionId = $execution['body']['$id'] ?? ''; @@ -1441,7 +1446,7 @@ class FunctionsCustomServerTest extends Scope sleep(20); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1451,7 +1456,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $executions['headers']['status-code']); $this->assertEquals('completed', $executions['body']['status']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']); + $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); $this->assertEquals('Ruby', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); @@ -1463,7 +1468,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([ + $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1477,7 +1482,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$functionId, [ + $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'], diff --git a/tests/e2e/Services/GraphQL/AbuseTest.php b/tests/e2e/Services/GraphQL/AbuseTest.php index 163f695811..48ee64d141 100644 --- a/tests/e2e/Services/GraphQL/AbuseTest.php +++ b/tests/e2e/Services/GraphQL/AbuseTest.php @@ -92,7 +92,7 @@ class AbuseTest extends Scope $max = App::getEnv('_APP_GRAPHQL_MAX_QUERY_COMPLEXITY', 250); - $this->assertEquals('Max query complexity should be '.$max.' but got 259.', $response['body']['errors'][0]['message']); + $this->assertEquals('Max query complexity should be ' . $max . ' but got 259.', $response['body']['errors'][0]['message']); } public function testTooManyQueriesBlocked() @@ -122,7 +122,7 @@ class AbuseTest extends Scope 'variables' => [ 'databaseId' => 'actors', 'name' => 'AbuseDatabase', - ], + ] ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -145,7 +145,7 @@ class AbuseTest extends Scope Permission::read(Role::any()), Permission::write(Role::any()), ], - ], + ] ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -165,7 +165,7 @@ class AbuseTest extends Scope 'key' => 'name', 'size' => 256, 'required' => true, - ], + ] ]; $this->client->call(Client::METHOD_POST, '/graphql', [ diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index c77773cba9..7fd70b5015 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -18,7 +18,7 @@ class AccountTest extends Scope { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_ACCOUNT); - $email = 'test'.\rand().'@test.com'; + $email = 'test' . \rand() . '@test.com'; $graphQLPayload = [ 'query' => $query, 'variables' => [ @@ -51,7 +51,7 @@ class AccountTest extends Scope 'variables' => [ 'email' => $this->getUser()['email'], 'password' => 'password', - ], + ] ]; $session = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -63,7 +63,7 @@ class AccountTest extends Scope $this->assertIsArray($session['body']['data']); $this->assertIsArray($session['body']['data']['accountCreateEmailSession']); - $cookie = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $cookie = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $this->assertNotEmpty($cookie); } @@ -71,13 +71,13 @@ class AccountTest extends Scope { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_MAGIC_URL); - $email = 'test'.\rand().'@test.com'; + $email = 'test' . \rand() . '@test.com'; $graphQLPayload = [ 'query' => $query, 'variables' => [ 'userId' => ID::unique(), 'email' => $email, - ], + ] ]; $session = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -99,7 +99,7 @@ class AccountTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'url' => 'http://localhost/verification', + 'url' => 'http://localhost/verification' ], ]; @@ -117,9 +117,7 @@ class AccountTest extends Scope /** * @depends testUpdateAccountPhone - * * @return array - * * @throws \Exception */ public function testCreatePhoneVerification(): array @@ -276,7 +274,7 @@ class AccountTest extends Scope 'query' => $query, 'variables' => [ 'sessionId' => 'current', - ], + ] ]; $session = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -319,8 +317,8 @@ class AccountTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'name' => 'Tester Updated', - ], + 'name' => 'Tester Updated' + ] ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -345,7 +343,7 @@ class AccountTest extends Scope 'variables' => [ 'email' => 'newemail@appwrite.io', 'password' => 'password', - ], + ] ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -370,7 +368,7 @@ class AccountTest extends Scope 'variables' => [ 'oldPassword' => 'password', 'password' => 'password', - ], + ] ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -394,7 +392,7 @@ class AccountTest extends Scope 'variables' => [ 'phone' => '+123456789', 'password' => 'password', - ], + ] ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -442,9 +440,9 @@ class AccountTest extends Scope 'query' => $query, 'variables' => [ 'prefs' => [ - 'key' => 'value', - ], - ], + 'key' => 'value' + ] + ] ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -465,7 +463,7 @@ class AccountTest extends Scope $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$DELETE_ACCOUNT_SESSIONS); $graphQLPayload = [ - 'query' => $query, + 'query' => $query ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -490,7 +488,7 @@ class AccountTest extends Scope 'query' => $query, 'variables' => [ 'sessionId' => 'current', - ], + ] ]; $account = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/AuthTest.php b/tests/e2e/Services/GraphQL/AuthTest.php index 63177ee3bc..c331fb8437 100644 --- a/tests/e2e/Services/GraphQL/AuthTest.php +++ b/tests/e2e/Services/GraphQL/AuthTest.php @@ -7,8 +7,8 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; -use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Helpers\Permission; class AuthTest extends Scope { @@ -17,15 +17,12 @@ class AuthTest extends Scope use Base; private array $account1; - private array $account2; private string $token1; - private string $token2; private array $database; - private array $collection; public function setUp(): void @@ -35,8 +32,8 @@ class AuthTest extends Scope $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_ACCOUNT); - $email1 = 'test'.\rand().'@test.com'; - $email2 = 'test'.\rand().'@test.com'; + $email1 = 'test' . \rand() . '@test.com'; + $email2 = 'test' . \rand() . '@test.com'; // Create account 1 $graphQLPayload = [ @@ -69,7 +66,7 @@ class AuthTest extends Scope 'variables' => [ 'email' => $email1, 'password' => 'password', - ], + ] ]; $session1 = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', @@ -77,8 +74,8 @@ class AuthTest extends Scope ], $graphQLPayload); $this->token1 = $this->client->parseCookie( - (string) $session1['headers']['set-cookie'] - )['a_session_'.$projectId]; + (string)$session1['headers']['set-cookie'] + )['a_session_' . $projectId]; // Create session 2 $graphQLPayload['variables']['email'] = $email2; @@ -89,8 +86,8 @@ class AuthTest extends Scope ], $graphQLPayload); $this->token2 = $this->client->parseCookie( - (string) $session2['headers']['set-cookie'] - )['a_session_'.$projectId]; + (string)$session2['headers']['set-cookie'] + )['a_session_' . $projectId]; // Create database $query = $this->getQuery(self::$CREATE_DATABASE); @@ -99,7 +96,7 @@ class AuthTest extends Scope 'variables' => [ 'databaseId' => ID::unique(), 'name' => 'Actors', - ], + ] ]; $this->database = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', @@ -118,9 +115,9 @@ class AuthTest extends Scope 'name' => 'Actors', 'documentSecurity' => true, 'permissions' => [ - Permission::create(Role::user($userId)), - ], - ], + Permission::create(Role::user($userId)) + ] + ] ]; $this->collection = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', @@ -138,7 +135,7 @@ class AuthTest extends Scope 'key' => 'name', 'size' => 256, 'required' => true, - ], + ] ]; $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', @@ -169,13 +166,13 @@ class AuthTest extends Scope Permission::read(Role::user($userId)), Permission::update(Role::user($userId)), Permission::delete(Role::user($userId)), - ], - ], + ] + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$this->token1, + 'cookie' => 'a_session_' . $projectId . '=' . $this->token1, ], $gqlPayload); // Try to read as account 1 @@ -186,12 +183,12 @@ class AuthTest extends Scope 'databaseId' => $this->database['body']['data']['databasesCreate']['_id'], 'collectionId' => $this->collection['body']['data']['databasesCreateCollection']['_id'], 'documentId' => $document['body']['data']['databasesCreateDocument']['_id'], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$this->token1, + 'cookie' => 'a_session_' . $projectId . '=' . $this->token1, ], $gqlPayload); $this->assertIsArray($document['body']['data']['databasesGetDocument']); @@ -201,7 +198,7 @@ class AuthTest extends Scope $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$this->token2, + 'cookie' => 'a_session_' . $projectId . '=' . $this->token2, ], $gqlPayload); $this->assertArrayHasKey('errors', $document['body']); @@ -229,12 +226,12 @@ class AuthTest extends Scope Permission::update(Role::user($userId)), Permission::delete(Role::user($userId)), ], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$this->token1, + 'cookie' => 'a_session_' . $projectId . '=' . $this->token1, ], $gqlPayload); // Try to delete as account 1 @@ -245,12 +242,12 @@ class AuthTest extends Scope 'databaseId' => $this->database['body']['data']['databasesCreate']['_id'], 'collectionId' => $this->collection['body']['data']['databasesCreateCollection']['_id'], 'documentId' => $document['body']['data']['databasesCreateDocument']['_id'], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$this->token1, + 'cookie' => 'a_session_' . $projectId . '=' . $this->token1, ], $gqlPayload); $this->assertIsNotArray($document['body']); diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 8f16222f1e..67d09bb4ac 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -6,342 +6,195 @@ trait Base { // Databases public static string $CREATE_DATABASE = 'create_database'; - public static string $GET_DATABASES = 'get_databases'; - public static string $GET_DATABASE = 'get_database'; - public static string $UPDATE_DATABASE = 'update_database'; - public static string $DELETE_DATABASE = 'delete_database'; - // Collections public static string $CREATE_COLLECTION = 'create_collection'; - public static string $GET_COLLECTION = 'get_collection'; - public static string $GET_COLLECTIONS = 'list_collections'; - public static string $UPDATE_COLLECTION = 'update_collection'; - public static string $DELETE_COLLECTION = 'delete_collection'; - // Attributes public static string $CREATE_STRING_ATTRIBUTE = 'create_string_attribute'; - public static string $CREATE_INTEGER_ATTRIBUTE = 'create_integer_attribute'; - public static string $CREATE_FLOAT_ATTRIBUTE = 'create_float_attribute'; - public static string $CREATE_BOOLEAN_ATTRIBUTE = 'create_boolean_attribute'; - public static string $CREATE_URL_ATTRIBUTE = 'create_url_attribute'; - public static string $CREATE_EMAIL_ATTRIBUTE = 'create_email_attribute'; - public static string $CREATE_IP_ATTRIBUTE = 'create_ip_attribute'; - public static string $CREATE_ENUM_ATTRIBUTE = 'create_enum_attribute'; - public static string $CREATE_DATETIME_ATTRIBUTE = 'create_datetime_attribute'; public static string $CREATE_RELATIONSHIP_ATTRIBUTE = 'create_relationship_attribute'; - public static string $UPDATE_STRING_ATTRIBUTE = 'update_string_attribute'; - public static string $UPDATE_INTEGER_ATTRIBUTE = 'update_integer_attribute'; - public static string $UPDATE_FLOAT_ATTRIBUTE = 'update_float_attribute'; - public static string $UPDATE_BOOLEAN_ATTRIBUTE = 'update_boolean_attribute'; - public static string $UPDATE_URL_ATTRIBUTE = 'update_url_attribute'; - public static string $UPDATE_EMAIL_ATTRIBUTE = 'update_email_attribute'; - public static string $UPDATE_IP_ATTRIBUTE = 'update_ip_attribute'; - public static string $UPDATE_ENUM_ATTRIBUTE = 'update_enum_attribute'; - public static string $UPDATE_DATETIME_ATTRIBUTE = 'update_datetime_attribute'; public static string $UPDATE_RELATIONSHIP_ATTRIBUTE = 'update_relationship_attribute'; - public static string $GET_ATTRIBUTES = 'get_attributes'; - public static string $GET_ATTRIBUTE = 'get_attribute'; - public static string $DELETE_ATTRIBUTE = 'delete_attribute'; - // Indexes public static string $CREATE_INDEX = 'create_index'; - public static string $GET_INDEXES = 'get_indexes'; - public static string $GET_INDEX = 'get_index'; - public static string $DELETE_INDEX = 'delete_index'; - // Documents public static string $CREATE_DOCUMENT = 'create_document_rest'; - public static string $GET_DOCUMENTS = 'list_documents'; - public static string $GET_DOCUMENT = 'get_document'; - public static string $UPDATE_DOCUMENT = 'update_document'; - public static string $DELETE_DOCUMENT = 'delete_document'; // Custom Entities public static string $CREATE_CUSTOM_ENTITY = 'create_custom_entity'; - public static string $GET_CUSTOM_ENTITIES = 'get_custom_entities'; - public static string $GET_CUSTOM_ENTITY = 'get_custom_entity'; - public static string $UPDATE_CUSTOM_ENTITY = 'update_custom_entity'; - public static string $DELETE_CUSTOM_ENTITY = 'delete_custom_entity'; // Account public static string $CREATE_ACCOUNT = 'create_account'; - public static string $CREATE_ACCOUNT_SESSION = 'create_account_session'; - public static string $CREATE_ANONYMOUS_SESSION = 'create_anonymous_session'; - public static string $CREATE_ACCOUNT_JWT = 'create_account_jwt'; - public static string $CREATE_MAGIC_URL = 'create_magic_url'; - public static string $CREATE_PASSWORD_RECOVERY = 'create_password_recovery'; - public static string $CREATE_EMAIL_VERIFICATION = 'create_email_verification'; - public static string $CREATE_PHONE_VERIFICATION = 'create_phone_verification'; - public static string $GET_ACCOUNT = 'get_account'; - public static string $GET_ACCOUNT_SESSION = 'get_account_session'; - public static string $GET_ACCOUNT_SESSIONS = 'get_account_sessions'; - public static string $GET_ACCOUNT_PREFS = 'get_account_preferences'; - public static string $GET_ACCOUNT_LOGS = 'get_account_logs'; - public static string $UPDATE_ACCOUNT_NAME = 'update_account_name'; - public static string $UPDATE_ACCOUNT_EMAIL = 'update_account_email'; - public static string $UPDATE_ACCOUNT_PASSWORD = 'update_account_password'; - public static string $UPDATE_ACCOUNT_PREFS = 'update_account_prefs'; - public static string $UPDATE_ACCOUNT_PHONE = 'update_account_phone'; - public static string $UPDATE_ACCOUNT_STATUS = 'update_account_status'; - public static string $UPDATE_MAGIC_URL = 'confirm_magic_url'; - public static string $UPDATE_PASSWORD_RECOVERY = 'confirm_password_recovery'; - public static string $UPDATE_EMAIL_VERIFICATION = 'confirm_email_verification'; - public static string $UPDATE_PHONE_VERIFICATION = 'confirm_phone_verification'; - public static string $DELETE_ACCOUNT_SESSION = 'delete_account_session'; - public static string $DELETE_ACCOUNT_SESSIONS = 'delete_account_sessions'; // Users public static string $CREATE_USER = 'create_user'; - public static string $GET_USER = 'get_user'; - public static string $GET_USERS = 'list_user'; - public static string $GET_USER_PREFERENCES = 'get_user_preferences'; - public static string $GET_USER_SESSIONS = 'get_user_sessions'; - public static string $GET_USER_MEMBERSHIPS = 'get_user_memberships'; - public static string $GET_USER_LOGS = 'get_user_logs'; - public static string $UPDATE_USER_STATUS = 'update_user_status'; - public static string $UPDATE_USER_NAME = 'update_user_name'; - public static string $UPDATE_USER_EMAIL = 'update_user_email'; - public static string $UPDATE_USER_EMAIL_VERIFICATION = 'update_email_verification'; - public static string $UPDATE_USER_PHONE_VERIFICATION = 'update_phone_verification'; - public static string $UPDATE_USER_PASSWORD = 'update_user_password'; - public static string $UPDATE_USER_PHONE = 'update_user_phone'; - public static string $UPDATE_USER_PREFS = 'update_user_prefs'; - public static string $DELETE_USER_SESSIONS = 'delete_user_sessions'; - public static string $DELETE_USER_SESSION = 'delete_user_session'; - public static string $DELETE_USER = 'delete_user'; // Teams public static string $GET_TEAM = 'get_team'; - public static string $GET_TEAM_PREFERENCES = 'get_team_preferences'; - public static string $GET_TEAMS = 'list_teams'; - public static string $CREATE_TEAM = 'create_team'; - public static string $UPDATE_TEAM_NAME = 'update_team_name'; - public static string $UPDATE_TEAM_PREFERENCES = 'update_team_preferences'; public static string $DELETE_TEAM = 'delete_team'; - public static string $GET_TEAM_MEMBERSHIP = 'get_team_membership'; - public static string $GET_TEAM_MEMBERSHIPS = 'list_team_memberships'; - public static string $CREATE_TEAM_MEMBERSHIP = 'create_team_membership'; - public static string $UPDATE_TEAM_MEMBERSHIP = 'update_team_membership'; - public static string $UPDATE_TEAM_MEMBERSHIP_STATUS = 'update_membership_status'; - public static string $DELETE_TEAM_MEMBERSHIP = 'delete_team_membership'; // Functions public static string $CREATE_FUNCTION = 'create_function'; - public static string $GET_FUNCTIONS = 'list_functions'; - public static string $GET_FUNCTION = 'get_function'; - public static string $GET_RUNTIMES = 'list_runtimes'; - public static string $UPDATE_FUNCTION = 'update_function'; - public static string $DELETE_FUNCTION = 'delete_function'; - // Variables public static string $CREATE_VARIABLE = 'create_variable'; - public static string $GET_VARIABLES = 'list_variables'; - public static string $GET_VARIABLE = 'get_variable'; - public static string $UPDATE_VARIABLE = 'update_variable'; - public static string $DELETE_VARIABLE = 'delete_variable'; //Deployments public static string $CREATE_DEPLOYMENT = 'create_deployment'; - public static string $GET_DEPLOYMENTS = 'list_deployments'; - public static string $GET_DEPLOYMENT = 'get_deployment'; - public static string $UPDATE_DEPLOYMENT = 'update_deployment'; - public static string $DELETE_DEPLOYMENT = 'delete_deployment'; - // Executions public static string $GET_EXECUTIONS = 'list_executions'; - public static string $GET_EXECUTION = 'get_execution'; - public static string $CREATE_EXECUTION = 'create_execution'; - public static string $DELETE_EXECUTION = 'delete_execution'; - public static string $RETRY_BUILD = 'retry_build'; // Buckets public static string $CREATE_BUCKET = 'create_bucket'; - public static string $GET_BUCKETS = 'list_buckets'; - public static string $GET_BUCKET = 'get_bucket'; - public static string $UPDATE_BUCKET = 'update_bucket'; - public static string $DELETE_BUCKET = 'delete_bucket'; - // Files public static string $CREATE_FILE = 'create_file'; - public static string $GET_FILES = 'list_files'; - public static string $GET_FILE = 'get_file'; - public static string $GET_FILE_PREVIEW = 'get_file_preview'; - public static string $GET_FILE_DOWNLOAD = 'get_file_download'; - public static string $GET_FILE_VIEW = 'get_file_view'; - public static string $UPDATE_FILE = 'update_file'; - public static string $DELETE_FILE = 'delete_file'; // Health public static string $GET_HTTP_HEALTH = 'get_http_health'; - public static string $GET_DB_HEALTH = 'get_db_health'; - public static string $GET_CACHE_HEALTH = 'get_cache_health'; - public static string $GET_TIME_HEALTH = 'get_time_health'; - public static string $GET_WEBHOOKS_QUEUE_HEALTH = 'get_webhooks_queue_health'; - public static string $GET_LOGS_QUEUE_HEALTH = 'get_logs_queue_health'; - public static string $GET_CERTIFICATES_QUEUE_HEALTH = 'get_certificates_queue_health'; - public static string $GET_FUNCTION_QUEUE_HEALTH = 'get_functions_queue_health'; - public static string $GET_LOCAL_STORAGE_HEALTH = 'get_local_storage_health'; - public static string $GET_ANITVIRUS_HEALTH = 'get_antivirus_health'; // Localization public static string $GET_LOCALE = 'get_locale'; - public static string $LIST_COUNTRIES = 'list_countries'; - public static string $LIST_EU_COUNTRIES = 'list_eu_countries'; - public static string $LIST_COUNTRY_PHONE_CODES = 'list_country_phone_codes'; - public static string $LIST_CONTINENTS = 'list_continents'; - public static string $LIST_CURRENCIES = 'list_currencies'; - public static string $LIST_LANGUAGES = 'list_languages'; // Avatars public static string $GET_CREDIT_CARD_ICON = 'get_credit_card_icon'; - public static string $GET_BROWSER_ICON = 'get_browser_icon'; - public static string $GET_COUNTRY_FLAG = 'get_country_flag'; - public static string $GET_IMAGE_FROM_URL = 'get_image_from_url'; - public static string $GET_FAVICON = 'get_favicon'; - public static string $GET_QRCODE = 'get_qrcode'; - public static string $GET_USER_INITIALS = 'get_user_initials'; // Complex queries @@ -745,13 +598,13 @@ trait Base ...attributeProperties } } - }'.PHP_EOL.self::$FRAGMENT_ATTRIBUTES; + }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; case self::$GET_ATTRIBUTE: return 'query getAttribute($databaseId: String!, $collectionId: String!, $key: String!) { databasesGetAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key) { ...attributeProperties } - }'.PHP_EOL.self::$FRAGMENT_ATTRIBUTES; + }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; case self::$DELETE_ATTRIBUTE: return 'mutation deleteAttribute($databaseId: String!, $collectionId: String!, $key: String!) { databasesDeleteAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key) { @@ -875,7 +728,7 @@ trait Base ...options } } - }'.PHP_EOL.self::$FRAGMENT_HASH_OPTIONS; + }' . PHP_EOL . self::$FRAGMENT_HASH_OPTIONS; case self::$GET_USER_PREFERENCES: return 'query getUserPreferences($userId : String!) { usersGetPrefs(userId : $userId) { @@ -2070,7 +1923,7 @@ trait Base data } } - }'.PHP_EOL.self::$FRAGMENT_ATTRIBUTES; + }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; } throw new \InvalidArgumentException('Invalid query type'); diff --git a/tests/e2e/Services/GraphQL/BatchTest.php b/tests/e2e/Services/GraphQL/BatchTest.php index a6f1da2908..7082d23677 100644 --- a/tests/e2e/Services/GraphQL/BatchTest.php +++ b/tests/e2e/Services/GraphQL/BatchTest.php @@ -63,7 +63,7 @@ class BatchTest extends Scope public function testArrayBatchedMutations() { $projectId = $this->getProject()['$id']; - $email = 'tester'.\uniqid().'@example.com'; + $email = 'tester' . \uniqid() . '@example.com'; $graphQLPayload = [[ 'query' => 'mutation CreateAccount($userId: String!, $email: String!, $password: String!, $name: String) { accountCreate(userId: $userId, email: $email, password: $password, name: $name) { @@ -77,17 +77,17 @@ class BatchTest extends Scope 'name' => 'Tester 1', ], ], - [ - 'query' => 'mutation CreateTeam($teamId: String! $name: String!) { + [ + 'query' => 'mutation CreateTeam($teamId: String! $name: String!) { teamsCreate(teamId: $teamId, name: $name) { name } }', - 'variables' => [ - 'teamId' => ID::unique(), - 'name' => 'Team 1', - ], - ], ]; + 'variables' => [ + 'teamId' => ID::unique(), + 'name' => 'Team 1', + ], + ]]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -107,8 +107,8 @@ class BatchTest extends Scope public function testArrayBatchedMutationsOfSameType() { $projectId = $this->getProject()['$id']; - $email1 = 'tester'.\uniqid().'@example.com'; - $email2 = 'tester'.\uniqid().'@example.com'; + $email1 = 'tester' . \uniqid() . '@example.com'; + $email2 = 'tester' . \uniqid() . '@example.com'; $query = 'mutation CreateAccount($userId: String!, $email: String!, $password: String!, $name: String) { accountCreate(userId: $userId, email: $email, password: $password, name: $name) { _id @@ -152,7 +152,7 @@ class BatchTest extends Scope public function testArrayBatchedMixed() { $projectId = $this->getProject()['$id']; - $email = 'tester'.\uniqid().'@example.com'; + $email = 'tester' . \uniqid() . '@example.com'; $graphQLPayload = [ ['query' => 'query { localeListCountries { total countries { code } } }'], ['query' => 'query { localeListContinents { total continents { code } } }'], @@ -167,7 +167,7 @@ class BatchTest extends Scope 'email' => $email, 'password' => 'password', 'name' => 'Tester 1', - ], + ] ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -192,7 +192,7 @@ class BatchTest extends Scope public function testArrayBatchedMixedOfSameType() { $projectId = $this->getProject()['$id']; - $email = 'tester'.\uniqid().'@example.com'; + $email = 'tester' . \uniqid() . '@example.com'; $query = 'query { localeListCountries { total countries { code } } }'; $graphQLPayload = [ ['query' => $query], @@ -208,7 +208,7 @@ class BatchTest extends Scope 'email' => $email, 'password' => 'password', 'name' => 'Tester 1', - ], + ] ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -281,7 +281,7 @@ class BatchTest extends Scope public function testQueryBatchedMutations() { $projectId = $this->getProject()['$id']; - $email = 'tester'.\uniqid().'@example.com'; + $email = 'tester' . \uniqid() . '@example.com'; $graphQLPayload = [ 'query' => 'mutation CreateAndLogin($userId: String!, $email: String!, $password: String!, $name: String) { accountCreate(userId: $userId, email: $email, password: $password, name: $name) { @@ -304,6 +304,7 @@ class BatchTest extends Scope 'x-appwrite-project' => $projectId, ], $this->getHeaders()), $graphQLPayload); + $this->assertIsArray($response['body']['data']); $this->assertArrayNotHasKey('errors', $response['body']); $this->assertArrayHasKey('accountCreate', $response['body']['data']); @@ -314,8 +315,8 @@ class BatchTest extends Scope public function testQueryBatchedMutationsOfSameType() { $projectId = $this->getProject()['$id']; - $email1 = 'tester'.\uniqid().'@example.com'; - $email2 = 'tester'.\uniqid().'@example.com'; + $email1 = 'tester' . \uniqid() . '@example.com'; + $email2 = 'tester' . \uniqid() . '@example.com'; $graphQLPayload = [ 'query' => 'mutation CreateAndLogin($email1: String!, $email2: String!, $password: String!, $name1: String, $name2: String) { accountCreate(userId: "unique()", email: $email1, password: $password, name: $name1) { @@ -346,8 +347,8 @@ class BatchTest extends Scope public function testQueryBatchedMutationsOfSameTypeWithAlias() { $projectId = $this->getProject()['$id']; - $email1 = 'tester'.\uniqid().'@example.com'; - $email2 = 'tester'.\uniqid().'@example.com'; + $email1 = 'tester' . \uniqid() . '@example.com'; + $email2 = 'tester' . \uniqid() . '@example.com'; $graphQLPayload = [ 'query' => 'mutation CreateAndLogin($email1: String!, $email2: String!, $password: String!, $name1: String, $name2: String) { account1: accountCreate(userId: "unique()", email: $email1, password: $password, name: $name1) { diff --git a/tests/e2e/Services/GraphQL/ContentTypeTest.php b/tests/e2e/Services/GraphQL/ContentTypeTest.php index 5ab950d893..da885a2a83 100644 --- a/tests/e2e/Services/GraphQL/ContentTypeTest.php +++ b/tests/e2e/Services/GraphQL/ContentTypeTest.php @@ -115,7 +115,7 @@ class ContentTypeTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -138,12 +138,12 @@ class ContentTypeTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]), 'map' => \json_encode([ - 'file' => ['variables.file'], + 'file' => ["variables.file"] ]), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/DatabaseClientTest.php b/tests/e2e/Services/GraphQL/DatabaseClientTest.php index ae3b908330..3853a3fc17 100644 --- a/tests/e2e/Services/GraphQL/DatabaseClientTest.php +++ b/tests/e2e/Services/GraphQL/DatabaseClientTest.php @@ -25,7 +25,7 @@ class DatabaseClientTest extends Scope 'variables' => [ 'databaseId' => ID::unique(), 'name' => 'Actors', - ], + ] ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -62,7 +62,7 @@ class DatabaseClientTest extends Scope Permission::update(Role::users()), Permission::delete(Role::users()), ], - ], + ] ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -97,7 +97,7 @@ class DatabaseClientTest extends Scope 'key' => 'name', 'size' => 256, 'required' => true, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -129,7 +129,7 @@ class DatabaseClientTest extends Scope 'min' => 18, 'max' => 150, 'required' => true, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -170,7 +170,7 @@ class DatabaseClientTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -193,7 +193,6 @@ class DatabaseClientTest extends Scope /** * @depends testCreateCollection - * * @throws \Exception */ public function testGetDocuments($data): void @@ -205,7 +204,7 @@ class DatabaseClientTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ], + ] ]; $documents = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -220,7 +219,6 @@ class DatabaseClientTest extends Scope /** * @depends testCreateDocument - * * @throws \Exception */ public function testGetDocument($data): void @@ -233,7 +231,7 @@ class DatabaseClientTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'documentId' => $data['document']['_id'], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -248,7 +246,6 @@ class DatabaseClientTest extends Scope /** * @depends testCreateDocument - * * @throws \Exception */ public function testUpdateDocument($data): void @@ -264,7 +261,7 @@ class DatabaseClientTest extends Scope 'data' => [ 'name' => 'New Document Name', ], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -282,7 +279,6 @@ class DatabaseClientTest extends Scope /** * @depends testCreateDocument - * * @throws \Exception */ public function testDeleteDocument($data): void @@ -295,7 +291,7 @@ class DatabaseClientTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'documentId' => $data['document']['_id'], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ diff --git a/tests/e2e/Services/GraphQL/DatabaseServerTest.php b/tests/e2e/Services/GraphQL/DatabaseServerTest.php index f17159c174..87006a1bea 100644 --- a/tests/e2e/Services/GraphQL/DatabaseServerTest.php +++ b/tests/e2e/Services/GraphQL/DatabaseServerTest.php @@ -27,7 +27,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => 'actors', 'name' => 'Actors', - ], + ] ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -63,7 +63,7 @@ class DatabaseServerTest extends Scope Permission::update(Role::users()), Permission::delete(Role::users()), ], - ], + ] ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -89,7 +89,7 @@ class DatabaseServerTest extends Scope Permission::update(Role::users()), Permission::delete(Role::users()), ], - ], + ] ]; $collection2 = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -111,7 +111,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testCreateStringAttribute($data): array @@ -126,7 +125,7 @@ class DatabaseServerTest extends Scope 'key' => 'name', 'size' => 256, 'required' => true, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -143,7 +142,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateStringAttribute - * * @throws Exception */ public function testUpdateStringAttribute($data): array @@ -161,7 +159,7 @@ class DatabaseServerTest extends Scope 'key' => 'name', 'required' => false, 'default' => 'Default Value', - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -180,7 +178,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testCreateIntegerAttribute($data): array @@ -196,7 +193,7 @@ class DatabaseServerTest extends Scope 'min' => 18, 'max' => 150, 'required' => true, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -213,7 +210,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateIntegerAttribute - * * @throws Exception */ public function testUpdateIntegerAttribute($data): array @@ -232,8 +228,8 @@ class DatabaseServerTest extends Scope 'required' => false, 'min' => 12, 'max' => 160, - 'default' => 50, - ], + 'default' => 50 + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -254,7 +250,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testCreateBooleanAttribute($data): array @@ -268,7 +263,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'alive', 'required' => true, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -285,7 +280,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateBooleanAttribute - * * @throws Exception */ public function testUpdateBooleanAttribute($data): array @@ -302,8 +296,8 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'alive', 'required' => false, - 'default' => true, - ], + 'default' => true + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -322,7 +316,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testCreateFloatAttribute($data): array @@ -339,7 +332,7 @@ class DatabaseServerTest extends Scope 'max' => 999999.99, 'default' => 1000.0, 'required' => false, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -356,7 +349,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateFloatAttribute - * * @throws Exception */ public function testUpdateFloatAttribute($data): array @@ -375,8 +367,8 @@ class DatabaseServerTest extends Scope 'required' => false, 'min' => 100.0, 'max' => 1000000.0, - 'default' => 2500.0, - ], + 'default' => 2500.0 + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -397,7 +389,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testCreateEmailAttribute($data): array @@ -411,7 +402,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'email', 'required' => true, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -428,7 +419,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateEmailAttribute - * * @throws Exception */ public function testUpdateEmailAttribute($data): array @@ -446,7 +436,7 @@ class DatabaseServerTest extends Scope 'key' => 'email', 'required' => false, 'default' => 'torsten@appwrite.io', - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -465,7 +455,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testCreateEnumAttribute($data): array @@ -484,7 +473,7 @@ class DatabaseServerTest extends Scope 'guest', ], 'required' => true, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -499,9 +488,9 @@ class DatabaseServerTest extends Scope return $data; } + /** * @depends testCreateEnumAttribute - * * @throws Exception */ public function testUpdateEnumAttribute($data): array @@ -521,10 +510,10 @@ class DatabaseServerTest extends Scope 'elements' => [ 'crew', 'tech', - 'actor', + 'actor' ], - 'default' => 'tech', - ], + 'default' => 'tech' + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -545,7 +534,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testCreateDatetimeAttribute($data): array @@ -559,7 +547,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'dob', 'required' => true, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -576,7 +564,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDatetimeAttribute - * * @throws Exception */ public function testUpdateDatetimeAttribute($data): array @@ -593,8 +580,8 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'dob', 'required' => false, - 'default' => '2000-01-01T00:00:00Z', - ], + 'default' => '2000-01-01T00:00:00Z' + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -627,8 +614,8 @@ class DatabaseServerTest extends Scope 'type' => Database::RELATION_ONE_TO_MANY, 'twoWay' => true, 'key' => 'actors', - 'twoWayKey' => 'movie', - ], + 'twoWayKey' => 'movie' + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -659,7 +646,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection2']['_id'], 'key' => 'actors', 'onDelete' => Database::RELATION_MUTATE_CASCADE, - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -676,7 +663,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testCreateIPAttribute($data): array @@ -691,7 +677,7 @@ class DatabaseServerTest extends Scope 'key' => 'ip', 'required' => false, 'default' => '::1', - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -708,7 +694,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateIPAttribute - * * @throws Exception */ public function testUpdateIPAttribute($data): array @@ -725,8 +710,8 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'ip', 'required' => false, - 'default' => '127.0.0.1', - ], + 'default' => '127.0.0.1' + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -745,7 +730,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testCreateURLAttribute($data): array @@ -760,7 +744,7 @@ class DatabaseServerTest extends Scope 'key' => 'url', 'required' => false, 'default' => 'https://appwrite.io', - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -777,7 +761,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateURLAttribute - * * @throws Exception */ public function testUpdateURLAttribute($data): void @@ -794,8 +777,8 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'key' => 'url', 'required' => false, - 'default' => 'https://cloud.appwrite.io', - ], + 'default' => 'https://cloud.appwrite.io' + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -813,7 +796,6 @@ class DatabaseServerTest extends Scope /** * @depends testUpdateStringAttribute * @depends testUpdateIntegerAttribute - * * @throws Exception */ public function testCreateIndex($data): array @@ -831,7 +813,7 @@ class DatabaseServerTest extends Scope 'name', 'age', ], - ], + ] ]; $index = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -855,7 +837,6 @@ class DatabaseServerTest extends Scope * @depends testUpdateIntegerAttribute * @depends testUpdateBooleanAttribute * @depends testUpdateEnumAttribute - * * @throws Exception */ public function testCreateDocument($data): array @@ -882,7 +863,7 @@ class DatabaseServerTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -963,7 +944,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDatabase - * * @throws Exception */ public function testGetDatabase($database): void @@ -974,7 +954,7 @@ class DatabaseServerTest extends Scope 'query' => $query, 'variables' => [ 'databaseId' => $database['_id'], - ], + ] ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -989,7 +969,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testGetCollections($data): void @@ -1000,7 +979,7 @@ class DatabaseServerTest extends Scope 'query' => $query, 'variables' => [ 'databaseId' => $data['database']['_id'], - ], + ] ]; $collections = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1015,7 +994,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testGetCollection($data): void @@ -1027,7 +1005,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ], + ] ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1043,7 +1021,6 @@ class DatabaseServerTest extends Scope /** * @depends testUpdateStringAttribute * @depends testUpdateIntegerAttribute - * * @throws Exception */ public function testGetAttributes($data): void @@ -1055,7 +1032,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ], + ] ]; $attributes = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1070,7 +1047,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testGetAttribute($data): void @@ -1083,7 +1059,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'key' => 'name', - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1098,7 +1074,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateIndex - * * @throws Exception */ public function testGetIndexes($data): void @@ -1110,7 +1085,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ], + ] ]; $indices = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1125,7 +1100,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateIndex - * * @throws Exception */ public function testGetIndex($data): void @@ -1138,7 +1112,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'key' => $data['index']['key'], - ], + ] ]; $index = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1153,7 +1127,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testGetDocuments($data): void @@ -1165,7 +1138,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ], + ] ]; $documents = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1180,7 +1153,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDocument - * * @throws Exception */ public function testGetDocument($data): void @@ -1193,7 +1165,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'documentId' => $data['document']['_id'], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1255,7 +1227,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDatabase - * * @throws Exception */ public function testUpdateDatabase($database) @@ -1267,7 +1238,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $database['_id'], 'name' => 'New Database Name', - ], + ] ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1282,7 +1253,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testUpdateCollection($data) @@ -1296,7 +1266,7 @@ class DatabaseServerTest extends Scope 'collectionId' => $data['collection']['_id'], 'name' => 'New Collection Name', 'documentSecurity' => false, - ], + ] ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1311,7 +1281,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDocument - * * @throws Exception */ public function testUpdateDocument($data): void @@ -1327,7 +1296,7 @@ class DatabaseServerTest extends Scope 'data' => [ 'name' => 'New Document Name', ], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1372,7 +1341,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDocument - * * @throws Exception */ public function testDeleteDocument($data): void @@ -1385,7 +1353,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'documentId' => $data['document']['_id'], - ], + ] ]; $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1423,7 +1391,6 @@ class DatabaseServerTest extends Scope /** * @depends testUpdateStringAttribute - * * @throws Exception */ public function testDeleteAttribute($data): void @@ -1436,7 +1403,7 @@ class DatabaseServerTest extends Scope 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], 'key' => 'name', - ], + ] ]; $attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1450,7 +1417,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateCollection - * * @throws Exception */ public function testDeleteCollection($data) @@ -1462,7 +1428,7 @@ class DatabaseServerTest extends Scope 'variables' => [ 'databaseId' => $data['database']['_id'], 'collectionId' => $data['collection']['_id'], - ], + ] ]; $collection = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ @@ -1476,7 +1442,6 @@ class DatabaseServerTest extends Scope /** * @depends testCreateDatabase - * * @throws Exception */ public function testDeleteDatabase($database) @@ -1487,7 +1452,7 @@ class DatabaseServerTest extends Scope 'query' => $query, 'variables' => [ 'databaseId' => $database['_id'], - ], + ] ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ diff --git a/tests/e2e/Services/GraphQL/FunctionsClientTest.php b/tests/e2e/Services/GraphQL/FunctionsClientTest.php index 97cbfa9206..d5b50250d4 100644 --- a/tests/e2e/Services/GraphQL/FunctionsClientTest.php +++ b/tests/e2e/Services/GraphQL/FunctionsClientTest.php @@ -27,7 +27,7 @@ class FunctionsClientTest extends Scope 'name' => 'Test Function', 'runtime' => 'php-8.0', 'execute' => [Role::any()->toString()], - ], + ] ]; $function = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -36,6 +36,7 @@ class FunctionsClientTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'], ], $gqlPayload); + $this->assertIsArray($function['body']['data']); $this->assertArrayNotHasKey('errors', $function['body']); @@ -56,7 +57,7 @@ class FunctionsClientTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $functionId, - ], + ] ]; $variables = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -73,17 +74,15 @@ class FunctionsClientTest extends Scope /** * @depends testCreateFunction - * * @param $function * @return array - * * @throws \Exception */ public function testCreateDeployment($function): array { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_DEPLOYMENT); - $code = realpath(__DIR__.'/../../../resources/functions').'/php/code.tar.gz'; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/php/code.tar.gz"; $gqlPayload = [ 'operations' => \json_encode([ 'query' => $query, @@ -92,10 +91,10 @@ class FunctionsClientTest extends Scope 'entrypoint' => 'index.php', 'activate' => true, 'code' => null, - ], + ] ]), 'map' => \json_encode([ - 'code' => ['variables.code'], + 'code' => ["variables.code"] ]), 'code' => new CURLFile($code, 'application/gzip', 'code.tar.gz'), ]; @@ -117,11 +116,9 @@ class FunctionsClientTest extends Scope /** * @depends testCreateFunction * @depends testCreateDeployment - * * @param $function * @param $deployment * @return array - * * @throws \Exception */ public function testCreateExecution($function, $deployment): array @@ -132,7 +129,7 @@ class FunctionsClientTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ], + ] ]; $execution = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -142,16 +139,13 @@ class FunctionsClientTest extends Scope $this->assertIsArray($execution['body']['data']); $this->assertArrayNotHasKey('errors', $execution['body']); - return $execution['body']['data']['functionsCreateExecution']; } /** * @depends testCreateFunction - * * @param $function * @return array - * * @throws \Exception */ public function testGetExecutions($function): array @@ -162,7 +156,7 @@ class FunctionsClientTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ], + ] ]; $executions = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -181,11 +175,9 @@ class FunctionsClientTest extends Scope /** * @depends testCreateFunction * @depends testCreateExecution - * * @param $function * @param $execution * @return array - * * @throws \Exception */ public function testGetExecution($function, $execution): array @@ -197,7 +189,7 @@ class FunctionsClientTest extends Scope 'variables' => [ 'functionId' => $function['_id'], 'executionId' => $execution['_id'], - ], + ] ]; $execution = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/FunctionsServerTest.php b/tests/e2e/Services/GraphQL/FunctionsServerTest.php index 2771505ba7..75aa0d5d04 100644 --- a/tests/e2e/Services/GraphQL/FunctionsServerTest.php +++ b/tests/e2e/Services/GraphQL/FunctionsServerTest.php @@ -27,7 +27,7 @@ class FunctionsServerTest extends Scope 'name' => 'Test Function', 'runtime' => 'php-8.0', 'execute' => [Role::any()->toString()], - ], + ] ]; $function = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -55,7 +55,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $functionId, - ], + ] ]; $variables = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -72,17 +72,15 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction - * * @param $function * @return array - * * @throws \Exception */ public function testCreateDeployment($function): array { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_DEPLOYMENT); - $code = realpath(__DIR__.'/../../../resources/functions').'/php/code.tar.gz'; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/php/code.tar.gz"; $gqlPayload = [ 'operations' => \json_encode([ 'query' => $query, @@ -91,10 +89,10 @@ class FunctionsServerTest extends Scope 'entrypoint' => 'index.php', 'activate' => true, 'code' => null, - ], + ] ]), 'map' => \json_encode([ - 'code' => ['variables.code'], + 'code' => ["variables.code"] ]), 'code' => new CURLFile($code, 'application/gzip', 'code.tar.gz'), ]; @@ -115,10 +113,8 @@ class FunctionsServerTest extends Scope /** * * @depends testCreateFunction * @depends testCreateDeployment - * * @param $function * @return array - * * @throws \Exception */ public function testCreateExecution($function): array @@ -129,7 +125,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ], + ] ]; $execution = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -146,11 +142,9 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testGetDeployment - * * @param $function * @param $deployment * @return array - * * @throws \Exception */ public function testCreateRetryBuild($function, $deployment): void @@ -163,7 +157,7 @@ class FunctionsServerTest extends Scope 'functionId' => $function['_id'], 'deploymentId' => $deployment['_id'], 'buildId' => $deployment['buildId'], - ], + ] ]; $retryBuild = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -172,7 +166,7 @@ class FunctionsServerTest extends Scope ], $this->getHeaders()), $gqlPayload); $this->assertIsArray($retryBuild['body']['errors']); - $this->assertEquals('Build not failed', $retryBuild['body']['errors'][0]['message']); + $this->assertEquals("Build not failed", $retryBuild['body']['errors'][0]['message']); } public function testGetFunctions(): array @@ -198,10 +192,8 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction - * * @param $function * @return array - * * @throws \Exception */ public function testGetFunction($function): array @@ -212,7 +204,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ], + ] ]; $function = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -251,10 +243,8 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction - * * @param $function * @return array - * * @throws \Exception */ public function testGetDeployments($function) @@ -265,7 +255,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ], + ] ]; $deployments = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -284,10 +274,8 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testCreateDeployment - * * @param $function * @return array - * * @throws \Exception */ public function testGetDeployment($function, $deployment) @@ -299,7 +287,7 @@ class FunctionsServerTest extends Scope 'variables' => [ 'functionId' => $function['_id'], 'deploymentId' => $deployment['_id'], - ], + ] ]; $deployment = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -317,10 +305,8 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction - * * @param $function * @return array - * * @throws \Exception */ public function testGetExecutions($function): array @@ -331,7 +317,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ], + ] ]; $executions = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -350,11 +336,9 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testCreateExecution - * * @param $function * @param $execution * @return array - * * @throws \Exception */ public function testGetExecution($function, $execution): array @@ -366,7 +350,7 @@ class FunctionsServerTest extends Scope 'variables' => [ 'functionId' => $function['_id'], 'executionId' => $execution['_id'], - ], + ] ]; $execution = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -384,10 +368,8 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction - * * @param $function * @return array - * * @throws \Exception */ public function testUpdateFunction($function): array @@ -404,7 +386,7 @@ class FunctionsServerTest extends Scope 'name' => 'John Doe', 'age' => 42, ], - ], + ] ]; $function = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -423,10 +405,8 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testCreateDeployment - * * @param $function * @param $deployment - * * @throws \Exception */ public function testDeleteDeployment($function, $deployment): void @@ -438,7 +418,7 @@ class FunctionsServerTest extends Scope 'variables' => [ 'functionId' => $function['_id'], 'deploymentId' => $deployment['_id'], - ], + ] ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -453,9 +433,7 @@ class FunctionsServerTest extends Scope /** * @depends testCreateFunction * @depends testDeleteDeployment - * * @param $function - * * @throws \Exception */ public function testDeleteFunction($function): void @@ -466,7 +444,7 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - ], + ] ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/LocalizationTest.php b/tests/e2e/Services/GraphQL/LocalizationTest.php index 2fe76a6f06..38200911c8 100644 --- a/tests/e2e/Services/GraphQL/LocalizationTest.php +++ b/tests/e2e/Services/GraphQL/LocalizationTest.php @@ -18,7 +18,7 @@ class LocalizationTest extends Scope $projectId = $this->getProject()['$id']; $query = \urlencode($this->getQuery(self::$GET_LOCALE)); - $locale = $this->client->call(Client::METHOD_GET, '/graphql?query='.$query, \array_merge([ + $locale = $this->client->call(Client::METHOD_GET, '/graphql?query=' . $query, \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders())); diff --git a/tests/e2e/Services/GraphQL/ScopeTest.php b/tests/e2e/Services/GraphQL/ScopeTest.php index 44122887da..a8b5b7cea4 100644 --- a/tests/e2e/Services/GraphQL/ScopeTest.php +++ b/tests/e2e/Services/GraphQL/ScopeTest.php @@ -5,6 +5,7 @@ namespace Tests\E2E\Services\GraphQL; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\SideClient; use Tests\E2E\Scopes\SideServer; use Utopia\Database\Helpers\ID; @@ -24,7 +25,7 @@ class ScopeTest extends Scope 'variables' => [ 'databaseId' => ID::unique(), 'name' => 'Actors', - ], + ] ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -48,7 +49,7 @@ class ScopeTest extends Scope 'variables' => [ 'databaseId' => ID::unique(), 'name' => 'Actors', - ], + ] ]; $database = $this->client->call(Client::METHOD_POST, '/graphql', [ diff --git a/tests/e2e/Services/GraphQL/StorageClientTest.php b/tests/e2e/Services/GraphQL/StorageClientTest.php index 90cfaef7d5..9896598c2d 100644 --- a/tests/e2e/Services/GraphQL/StorageClientTest.php +++ b/tests/e2e/Services/GraphQL/StorageClientTest.php @@ -33,7 +33,7 @@ class StorageClientTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -70,12 +70,12 @@ class StorageClientTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]), 'map' => \json_encode([ - '0' => ['variables.file'], + '0' => ["variables.file"] ]), - '0' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + '0' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -91,10 +91,8 @@ class StorageClientTest extends Scope /** * @depends testCreateBucket - * * @param $bucket * @return array - * * @throws \Exception */ public function testGetFiles($bucket): array @@ -105,7 +103,7 @@ class StorageClientTest extends Scope 'query' => $query, 'variables' => [ 'bucketId' => $bucket['_id'], - ], + ] ]; $files = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -124,11 +122,9 @@ class StorageClientTest extends Scope /** * @depends testCreateBucket * @depends testCreateFile - * * @param $bucket * @param $file * @return array - * * @throws \Exception */ public function testGetFile($bucket, $file) @@ -140,7 +136,7 @@ class StorageClientTest extends Scope 'variables' => [ 'bucketId' => $bucket['_id'], 'fileId' => $file['_id'], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -156,10 +152,8 @@ class StorageClientTest extends Scope /** * @depends testCreateFile - * * @param $file * @return array - * * @throws \Exception */ public function testGetFilePreview($file) @@ -173,7 +167,7 @@ class StorageClientTest extends Scope 'fileId' => $file['_id'], 'width' => 100, 'height' => 100, - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -188,10 +182,8 @@ class StorageClientTest extends Scope /** * @depends testCreateFile - * * @param $file * @return array - * * @throws \Exception */ public function testGetFileDownload($file) @@ -203,7 +195,7 @@ class StorageClientTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -216,10 +208,8 @@ class StorageClientTest extends Scope /** * @depends testCreateFile - * * @param $file * @return array - * * @throws \Exception */ public function testGetFileView($file): void @@ -231,7 +221,7 @@ class StorageClientTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -244,10 +234,8 @@ class StorageClientTest extends Scope /** * @depends testCreateFile - * * @param $file * @return array - * * @throws \Exception */ public function testUpdateFile($file): array @@ -264,7 +252,7 @@ class StorageClientTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -282,9 +270,7 @@ class StorageClientTest extends Scope /** * @depends testCreateFile - * * @param $file - * * @throws \Exception */ public function testDeleteFile($file): void @@ -296,7 +282,7 @@ class StorageClientTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/StorageServerTest.php b/tests/e2e/Services/GraphQL/StorageServerTest.php index c4c12e400c..7fea895b1c 100644 --- a/tests/e2e/Services/GraphQL/StorageServerTest.php +++ b/tests/e2e/Services/GraphQL/StorageServerTest.php @@ -33,7 +33,7 @@ class StorageServerTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -69,12 +69,12 @@ class StorageServerTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]), 'map' => \json_encode([ - 'file' => ['variables.file'], + 'file' => ["variables.file"] ]), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -84,7 +84,6 @@ class StorageServerTest extends Scope $this->assertIsArray($file['body']['data']); $this->assertArrayNotHasKey('errors', $file['body']); - return $file['body']['data']['storageCreateFile']; } @@ -111,10 +110,8 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket - * * @param $bucket * @return array - * * @throws \Exception */ public function testGetBucket($bucket): array @@ -125,7 +122,7 @@ class StorageServerTest extends Scope 'query' => $query, 'variables' => [ 'bucketId' => $bucket['_id'], - ], + ] ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -143,10 +140,8 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket - * * @param $bucket * @return array - * * @throws \Exception */ public function testGetFiles($bucket): array @@ -157,7 +152,7 @@ class StorageServerTest extends Scope 'query' => $query, 'variables' => [ 'bucketId' => $bucket['_id'], - ], + ] ]; $files = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -176,11 +171,9 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket * @depends testCreateFile - * * @param $bucket * @param $file * @return array - * * @throws \Exception */ public function testGetFile($bucket, $file) @@ -192,7 +185,7 @@ class StorageServerTest extends Scope 'variables' => [ 'bucketId' => $bucket['_id'], 'fileId' => $file['_id'], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -208,10 +201,8 @@ class StorageServerTest extends Scope /** * @depends testCreateFile - * * @param $file * @return array - * * @throws \Exception */ public function testGetFilePreview($file) @@ -225,7 +216,7 @@ class StorageServerTest extends Scope 'fileId' => $file['_id'], 'width' => 100, 'height' => 100, - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -240,10 +231,8 @@ class StorageServerTest extends Scope /** * @depends testCreateFile - * * @param $file * @return array - * * @throws \Exception */ public function testGetFileDownload($file) @@ -255,7 +244,7 @@ class StorageServerTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -268,10 +257,8 @@ class StorageServerTest extends Scope /** * @depends testCreateFile - * * @param $file * @return array - * * @throws \Exception */ public function testGetFileView($file): void @@ -283,7 +270,7 @@ class StorageServerTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -296,10 +283,8 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket - * * @param $bucket * @return array - * * @throws \Exception */ public function testUpdateBucket($bucket): array @@ -312,7 +297,7 @@ class StorageServerTest extends Scope 'bucketId' => $bucket['_id'], 'name' => 'Actors Updated', 'fileSecurity' => false, - ], + ] ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -330,10 +315,8 @@ class StorageServerTest extends Scope /** * @depends testCreateFile - * * @param $file * @return array - * * @throws \Exception */ public function testUpdateFile($file): array @@ -350,7 +333,7 @@ class StorageServerTest extends Scope Permission::update(Role::any()), Permission::delete(Role::any()), ], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -368,9 +351,7 @@ class StorageServerTest extends Scope /** * @depends testCreateFile - * * @param $file - * * @throws \Exception */ public function testDeleteFile($file): void @@ -382,7 +363,7 @@ class StorageServerTest extends Scope 'variables' => [ 'bucketId' => $file['bucketId'], 'fileId' => $file['_id'], - ], + ] ]; $file = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -396,10 +377,8 @@ class StorageServerTest extends Scope /** * @depends testCreateBucket - * * @param $bucket * @return array - * * @throws \Exception */ public function testDeleteBucket($bucket): void @@ -410,7 +389,7 @@ class StorageServerTest extends Scope 'query' => $query, 'variables' => [ 'bucketId' => $bucket['_id'], - ], + ] ]; $bucket = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/TeamsServerTest.php b/tests/e2e/Services/GraphQL/TeamsServerTest.php index a8d8f64ac6..33c7847113 100644 --- a/tests/e2e/Services/GraphQL/TeamsServerTest.php +++ b/tests/e2e/Services/GraphQL/TeamsServerTest.php @@ -125,10 +125,10 @@ class TeamsServerTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'teamId' => $team['_id'], + 'teamId' => $team['_id'], 'prefs' => [ - 'key' => 'value', - ], + 'key' => 'value' + ] ], ]; @@ -156,7 +156,7 @@ class TeamsServerTest extends Scope 'query' => $query, 'variables' => [ 'teamId' => $team['_id'], - ], + ] ]; $prefs = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/GraphQL/UsersTest.php b/tests/e2e/Services/GraphQL/UsersTest.php index e965fc5899..9bd503df0f 100644 --- a/tests/e2e/Services/GraphQL/UsersTest.php +++ b/tests/e2e/Services/GraphQL/UsersTest.php @@ -7,6 +7,7 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; use Utopia\Database\Helpers\ID; +use Utopia\Database\Query; class UsersTest extends Scope { @@ -26,7 +27,7 @@ class UsersTest extends Scope 'email' => $email, 'password' => 'password', 'name' => 'Project User', - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -55,7 +56,7 @@ class UsersTest extends Scope 'limit(100)', 'offset(0)', ], - ], + ] ]; $users = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -77,7 +78,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -99,7 +100,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -120,7 +121,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -141,7 +142,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -162,7 +163,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -184,7 +185,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'status' => true, - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -207,7 +208,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'emailVerification' => true, - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -229,7 +230,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'phoneVerification' => true, - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -252,7 +253,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'name' => 'Updated Name', - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -274,7 +275,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - 'email' => 'newemail@appwrite.io', + 'email' => 'newemail@appwrite.io' ], ]; @@ -297,7 +298,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - 'password' => 'newpassword', + 'password' => 'newpassword' ], ]; @@ -319,7 +320,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - 'number' => '+123456789', + 'number' => '+123456789' ], ]; @@ -343,8 +344,8 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'prefs' => [ - 'key' => 'value', - ], + 'key' => 'value' + ] ], ]; @@ -367,7 +368,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -391,7 +392,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $this->getUser()['$id'], 'sessionId' => $this->getUser()['sessionId'], - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -414,7 +415,7 @@ class UsersTest extends Scope 'query' => $query, 'variables' => [ 'userId' => $this->getUser()['$id'], - ], + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/Health/HealthBase.php b/tests/e2e/Services/Health/HealthBase.php index 545cbc893f..cbd0f97668 100644 --- a/tests/e2e/Services/Health/HealthBase.php +++ b/tests/e2e/Services/Health/HealthBase.php @@ -2,6 +2,8 @@ namespace Tests\E2E\Services\Health; +use Tests\E2E\Client; + trait HealthBase { } diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php index 23b9833c96..96c9bde5c7 100644 --- a/tests/e2e/Services/Health/HealthCustomServerTest.php +++ b/tests/e2e/Services/Health/HealthCustomServerTest.php @@ -3,8 +3,9 @@ namespace Tests\E2E\Services\Health; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\SideClient; use Tests\E2E\Scopes\SideServer; class HealthCustomServerTest extends Scope diff --git a/tests/e2e/Services/Locale/LocaleBase.php b/tests/e2e/Services/Locale/LocaleBase.php index 38d6a61fd5..17b5c66d67 100644 --- a/tests/e2e/Services/Locale/LocaleBase.php +++ b/tests/e2e/Services/Locale/LocaleBase.php @@ -100,6 +100,7 @@ trait LocaleBase $this->assertEquals($response['body']['countries'][0]['name'], 'Alemania'); $this->assertEquals($response['body']['countries'][0]['code'], 'DE'); + /** * Test for FAILURE */ @@ -161,6 +162,7 @@ trait LocaleBase $this->assertEquals($response['body']['continents'][0]['code'], 'NA'); $this->assertEquals($response['body']['continents'][0]['name'], 'América del Norte'); + /** * Test for FAILURE */ @@ -225,9 +227,9 @@ trait LocaleBase /** * Test for SUCCESS */ - $languages = require 'app/config/locale/codes.php'; - $defaultCountries = require 'app/config/locale/countries.php'; - $defaultContinents = require 'app/config/locale/continents.php'; + $languages = require('app/config/locale/codes.php'); + $defaultCountries = require('app/config/locale/countries.php'); + $defaultContinents = require('app/config/locale/continents.php'); foreach ($languages as $lang) { $response = $this->client->call(Client::METHOD_GET, '/locale/countries', [ @@ -236,12 +238,12 @@ trait LocaleBase 'x-appwrite-locale' => $lang['code'], ]); - if (! \is_array($response['body']['countries'])) { - throw new Exception('Failed to iterate locale: '.$lang); + if (!\is_array($response['body']['countries'])) { + throw new Exception('Failed to iterate locale: ' . $lang); } foreach ($response['body']['countries'] as $i => $code) { - $this->assertContains($code['code'], $defaultCountries, $code['code'].' country should be removed from '.$lang['code']); + $this->assertContains($code['code'], $defaultCountries, $code['code'] . ' country should be removed from ' . $lang['code']); } $this->assertEquals($response['headers']['status-code'], 200); @@ -254,7 +256,7 @@ trait LocaleBase ]); foreach ($response['body']['continents'] as $i => $code) { - $this->assertContains($code['code'], $defaultContinents, $code['code'].' continent should be removed from '.$lang['code']); + $this->assertContains($code['code'], $defaultContinents, $code['code'] . ' continent should be removed from ' . $lang['code']); } $this->assertEquals($response['headers']['status-code'], 200); diff --git a/tests/e2e/Services/Locale/LocaleConsoleClientTest.php b/tests/e2e/Services/Locale/LocaleConsoleClientTest.php index c72e554df7..29b3150fed 100644 --- a/tests/e2e/Services/Locale/LocaleConsoleClientTest.php +++ b/tests/e2e/Services/Locale/LocaleConsoleClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Locale; -use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\SideClient; class LocaleConsoleClientTest extends Scope diff --git a/tests/e2e/Services/Locale/LocaleCustomClientTest.php b/tests/e2e/Services/Locale/LocaleCustomClientTest.php index 6d6108dec1..b28584280e 100644 --- a/tests/e2e/Services/Locale/LocaleCustomClientTest.php +++ b/tests/e2e/Services/Locale/LocaleCustomClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Locale; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; class LocaleCustomClientTest extends Scope diff --git a/tests/e2e/Services/Locale/LocaleCustomServerTest.php b/tests/e2e/Services/Locale/LocaleCustomServerTest.php index 1513f9b342..62d4e76802 100644 --- a/tests/e2e/Services/Locale/LocaleCustomServerTest.php +++ b/tests/e2e/Services/Locale/LocaleCustomServerTest.php @@ -2,6 +2,7 @@ namespace Tests\E2E\Services\Locale; +use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; diff --git a/tests/e2e/Services/Messaging/MessagingServerTest.php b/tests/e2e/Services/Messaging/MessagingServerTest.php index 8f477173eb..9bc9f93caf 100644 --- a/tests/e2e/Services/Messaging/MessagingServerTest.php +++ b/tests/e2e/Services/Messaging/MessagingServerTest.php @@ -65,7 +65,7 @@ class MessagingServerTest extends Scope $providers = []; foreach (\array_keys($providersParams) as $key) { - $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/'.$key, [ + $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/' . $key, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -132,7 +132,7 @@ class MessagingServerTest extends Scope ], ]; foreach (\array_keys($providersParams) as $index => $key) { - $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/'.$providers[$index]['$id'].'/'.$key, [ + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/' . $providers[$index]['$id'] . '/' . $key, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -164,7 +164,7 @@ class MessagingServerTest extends Scope */ public function testGetProvider(array $providers) { - $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/'.$providers[0]['$id'], [ + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -179,7 +179,7 @@ class MessagingServerTest extends Scope public function testDeleteProvider(array $providers) { foreach ($providers as $provider) { - $response = $this->client->call(Client::METHOD_DELETE, '/messaging/providers/'.$provider['$id'], [ + $response = $this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $provider['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -187,4 +187,5 @@ class MessagingServerTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } } + } diff --git a/tests/e2e/Services/Projects/ProjectsBase.php b/tests/e2e/Services/Projects/ProjectsBase.php index 53d9626252..a9ccd73900 100644 --- a/tests/e2e/Services/Projects/ProjectsBase.php +++ b/tests/e2e/Services/Projects/ProjectsBase.php @@ -2,6 +2,8 @@ namespace Tests\E2E\Services\Projects; +use Tests\E2E\Client; + trait ProjectsBase { } diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 5006ab224a..31c8c72a14 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -4,10 +4,10 @@ namespace Tests\E2E\Services\Projects; use Appwrite\Auth\Auth; use Appwrite\Extend\Exception; -use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\SideClient; +use Tests\E2E\Client; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; @@ -84,7 +84,7 @@ class ProjectsConsoleClientTest extends Scope 'projectId' => ID::unique(), 'name' => '', 'teamId' => $team['body']['$id'], - 'region' => 'default', + 'region' => 'default' ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -95,14 +95,14 @@ class ProjectsConsoleClientTest extends Scope ], $this->getHeaders()), [ 'projectId' => ID::unique(), 'name' => 'Project Test', - 'region' => 'default', + 'region' => 'default' ]); $this->assertEquals(400, $response['headers']['status-code']); return [ 'projectId' => $projectId, - 'teamId' => $team['body']['$id'], + 'teamId' => $team['body']['$id'] ]; } @@ -124,7 +124,7 @@ class ProjectsConsoleClientTest extends Scope 'projectId' => $projectId, 'name' => 'Project Duplicate', 'teamId' => $teamId, - 'region' => 'default', + 'region' => 'default' ]); $this->assertEquals(409, $response['headers']['status-code']); @@ -187,7 +187,7 @@ class ProjectsConsoleClientTest extends Scope $projectId = $response['body']['$id']; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$projectId.'/team', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $projectId . '/team', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -211,6 +211,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ + $response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -228,7 +229,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders(), [ - 'search' => $id, + 'search' => $id ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -241,7 +242,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders(), [ - 'search' => 'Project Test', + 'search' => 'Project Test' ])); $this->assertEquals($response['headers']['status-code'], 200); @@ -272,7 +273,7 @@ class ProjectsConsoleClientTest extends Scope 'projectId' => ID::unique(), 'name' => 'Project Test 2', 'teamId' => $team['body']['$id'], - 'region' => 'default', + 'region' => 'default' ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -287,7 +288,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("teamId", "'.$team['body']['$id'].'")'], + 'queries' => [ 'equal("teamId", "' . $team['body']['$id'] . '")' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -299,7 +300,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(1)'], + 'queries' => [ 'limit(1)' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -311,7 +312,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(3)'], + 'queries' => [ 'offset(3)' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -323,7 +324,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("name", "Project Test 2")'], + 'queries' => [ 'equal("name", "Project Test 2")' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -335,7 +336,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['orderDesc("")'], + 'queries' => [ 'orderDesc("")' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -359,7 +360,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("'.$response['body']['projects'][0]['$id'].'")'], + 'queries' => [ 'cursorAfter("' . $response['body']['projects'][0]['$id'] . '")' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -371,7 +372,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("'.$response['body']['projects'][0]['$id'].'")'], + 'queries' => [ 'cursorBefore("' . $response['body']['projects'][0]['$id'] . '")' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -386,7 +387,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("unknown")'], + 'queries' => [ 'cursorAfter("unknown")' ], ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -404,7 +405,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -417,6 +418,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ + $response = $this->client->call(Client::METHOD_GET, '/projects/empty', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -465,6 +467,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ + $response = $this->client->call(Client::METHOD_GET, '/projects/empty', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -492,7 +495,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -512,6 +515,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ + $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -532,7 +536,7 @@ class ProjectsConsoleClientTest extends Scope public function testUpdateProjectSMTP($data): array { $id = $data['projectId']; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/smtp', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/smtp', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -554,7 +558,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('', $response['body']['smtpSecure']); /** Test Reading Project */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -569,7 +573,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('', $response['body']['smtpSecure']); /** Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/smtp', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/smtp', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -580,7 +584,6 @@ class ProjectsConsoleClientTest extends Scope 'username' => 'user', 'password' => 'password', ]); - return $data; } @@ -592,7 +595,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId']; /** Get Default Email Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/templates/email/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/email/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -606,7 +609,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertMatchesRegularExpression('//', $response['body']['message']); /** Update Email template */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/templates/email/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/templates/email/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -625,7 +628,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('Please verify your email {{url}}', $response['body']['message']); /** Get Updated Email Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/templates/email/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/email/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -639,7 +642,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('Please verify your email {{url}}', $response['body']['message']); /** Get Default SMS Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/templates/sms/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -650,7 +653,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('{{token}}', $response['body']['message']); /** Update SMS template */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/templates/sms/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -663,7 +666,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('Please verify your email {{token}}', $response['body']['message']); /** Get Updated SMS Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/templates/sms/verification/en-us', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -682,7 +685,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId']; // Check defaults - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', ], $this->getHeaders())); @@ -693,7 +696,8 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/duration', array_merge([ + + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/duration', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -716,7 +720,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'userId' => 'unique()', - 'email' => 'test'.rand(0, 9999).'@example.com', + 'email' => 'test' . rand(0, 9999) . '@example.com', 'password' => 'password', 'name' => 'Test User', ]); @@ -773,7 +777,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(401, $response['headers']['status-code']); // Return project back to normal - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/duration', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/duration', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -784,7 +788,7 @@ class ProjectsConsoleClientTest extends Scope $projectId = $response['body']['$id']; // Check project is back to normal - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$projectId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $projectId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', ], $this->getHeaders())); @@ -801,26 +805,27 @@ class ProjectsConsoleClientTest extends Scope public function testUpdateProjectOAuth($data): array { $id = $data['projectId'] ?? ''; - $providers = require 'app/config/authProviders.php'; + $providers = require('app/config/authProviders.php'); /** * Test for SUCCESS */ + foreach ($providers as $key => $provider) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'provider' => $key, - 'appId' => 'AppId-'.ucfirst($key), - 'secret' => 'Secret-'.ucfirst($key), + 'appId' => 'AppId-' . ucfirst($key), + 'secret' => 'Secret-' . ucfirst($key), ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); } - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -833,8 +838,8 @@ class ProjectsConsoleClientTest extends Scope $asserted = false; foreach ($response['body']['providers'] as $responseProvider) { if ($responseProvider['key'] === $key) { - $this->assertEquals('AppId-'.ucfirst($key), $responseProvider['appId']); - $this->assertEquals('Secret-'.ucfirst($key), $responseProvider['secret']); + $this->assertEquals('AppId-' . ucfirst($key), $responseProvider['appId']); + $this->assertEquals('Secret-' . ucfirst($key), $responseProvider['secret']); $this->assertFalse($responseProvider['enabled']); $asserted = true; break; @@ -847,12 +852,12 @@ class ProjectsConsoleClientTest extends Scope // Enable providers $i = 0; foreach ($providers as $key => $provider) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/oauth2', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'provider' => $key, - 'enabled' => $i === 0 ? false : true, // On first provider, test enabled=false + 'enabled' => $i === 0 ? false : true // On first provider, test enabled=false ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -861,7 +866,7 @@ class ProjectsConsoleClientTest extends Scope $i++; } - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -890,7 +895,8 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/oauth2', array_merge([ + + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -910,9 +916,9 @@ class ProjectsConsoleClientTest extends Scope public function testUpdateProjectAuthStatus($data): array { $id = $data['projectId'] ?? ''; - $auth = require 'app/config/auth.php'; + $auth = require('app/config/auth.php'); - $originalEmail = uniqid().'user@localhost.test'; + $originalEmail = uniqid() . 'user@localhost.test'; $originalPassword = 'password'; $originalName = 'User Name'; @@ -936,13 +942,13 @@ class ProjectsConsoleClientTest extends Scope 'password' => $originalPassword, ]); - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$id]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $id]; /** * Test for SUCCESS */ foreach ($auth as $index => $method) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/'.$index, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/' . $index, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -952,17 +958,17 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(false, $response['body']['auth'.ucfirst($method['key'])]); + $this->assertEquals(false, $response['body']['auth' . ucfirst($method['key'])]); } - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -985,25 +991,25 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/teams', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'cookie' => 'a_session_'.$id.'='.$session, + 'cookie' => 'a_session_' . $id . '=' . $session, ]), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal', + 'name' => 'Arsenal' ]); $this->assertEquals(201, $response['headers']['status-code']); $teamUid = $response['body']['$id']; - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'cookie' => 'a_session_'.$id.'='.$session, + 'cookie' => 'a_session_' . $id . '=' . $session, ]), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals($response['headers']['status-code'], 501); @@ -1011,7 +1017,7 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/account/jwt', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'cookie' => 'a_session_'.$id.'='.$session, + 'cookie' => 'a_session_' . $id . '=' . $session, ])); $this->assertEquals($response['headers']['status-code'], 501); @@ -1038,7 +1044,7 @@ class ProjectsConsoleClientTest extends Scope // Cleanup foreach ($auth as $index => $method) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/'.$index, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/' . $index, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1059,7 +1065,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/limit', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/limit', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1069,7 +1075,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -1087,7 +1093,7 @@ class ProjectsConsoleClientTest extends Scope 'name' => $name, ]); - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ 'origin' => 'http://localhost', @@ -1105,7 +1111,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/limit', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/limit', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1115,7 +1121,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ 'origin' => 'http://localhost', @@ -1143,7 +1149,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for failure */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/max-sessions', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/max-sessions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1155,7 +1161,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/max-sessions', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/max-sessions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1166,7 +1172,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertNotEmpty($response['body']['$id']); $this->assertEquals(1, $response['body']['authSessionsLimit']); - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -1198,6 +1204,7 @@ class ProjectsConsoleClientTest extends Scope 'password' => $password, ]); + $this->assertEquals(201, $response['headers']['status-code']); $sessionId1 = $response['body']['$id']; @@ -1213,6 +1220,7 @@ class ProjectsConsoleClientTest extends Scope 'password' => $password, ]); + $this->assertEquals(201, $response['headers']['status-code']); $sessionCookie = $response['headers']['set-cookie']; $sessionId2 = $response['body']['$id']; @@ -1239,7 +1247,7 @@ class ProjectsConsoleClientTest extends Scope /** * Reset Limit */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/max-sessions', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/max-sessions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1249,6 +1257,7 @@ class ProjectsConsoleClientTest extends Scope return $data; } + /** * @depends testUpdateProjectAuthLimit */ @@ -1259,7 +1268,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for Failure */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-history', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1268,10 +1277,11 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); + /** * Test for Success */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-history', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1281,7 +1291,8 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['authPasswordHistory']); - $email = uniqid().'user@localhost.test'; + + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -1313,13 +1324,13 @@ class ProjectsConsoleClientTest extends Scope 'password' => $password, ]); $this->assertEquals(201, $session['headers']['status-code']); - $session = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$id]; + $session = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $id]; $response = $this->client->call(Client::METHOD_PATCH, '/account/password', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'cookie' => 'a_session_'.$id.'='.$session, + 'cookie' => 'a_session_' . $id . '=' . $session, ]), [ 'oldPassword' => $password, 'password' => $password, @@ -1333,16 +1344,17 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]); - $response = $this->client->call(Client::METHOD_PATCH, '/users/'.$userId.'/password', $headers, [ + $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $userId . '/password', $headers, [ 'password' => $password, ]); $this->assertEquals(400, $response['headers']['status-code']); - /** + + /** * Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-history', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1351,7 +1363,6 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(0, $response['body']['authPasswordHistory']); - return $data; } @@ -1378,7 +1389,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]), [ 'userId' => ID::unique(), - 'email' => uniqid().'user@localhost.test', + 'email' => uniqid() . 'user@localhost.test', 'password' => $password, 'name' => $name, ]); @@ -1394,7 +1405,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-mode' => 'admin', ]), [ 'userId' => ID::unique(), - 'email' => uniqid().'user@localhost.test', + 'email' => uniqid() . 'user@localhost.test', 'password' => 'password', 'name' => 'Cristiano Ronaldo', ]); @@ -1403,7 +1414,7 @@ class ProjectsConsoleClientTest extends Scope /** * Enable Disctionary */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-dictionary', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-dictionary', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1422,7 +1433,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]), [ 'userId' => ID::unique(), - 'email' => uniqid().'user@localhost.test', + 'email' => uniqid() . 'user@localhost.test', 'password' => $password, 'name' => $name, ]); @@ -1438,7 +1449,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-mode' => 'admin', ]), [ 'userId' => ID::unique(), - 'email' => uniqid().'user@localhost.test', + 'email' => uniqid() . 'user@localhost.test', 'password' => 'password', 'name' => 'Cristiano Ronaldo', ]); @@ -1450,16 +1461,17 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]); - $response = $this->client->call(Client::METHOD_PATCH, '/users/'.$userId.'/password', $headers, [ + $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $userId . '/password', $headers, [ 'password' => $password, ]); $this->assertEquals(400, $response['headers']['status-code']); - /** + + /** * Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-history', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1472,7 +1484,7 @@ class ProjectsConsoleClientTest extends Scope /** * Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/password-dictionary', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-dictionary', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1495,7 +1507,7 @@ class ProjectsConsoleClientTest extends Scope /** * Enable Disallowing of Personal Data */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/personal-data', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/personal-data', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1508,7 +1520,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for failure */ - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'username'; $userId = ID::unique(); @@ -1521,7 +1533,7 @@ class ProjectsConsoleClientTest extends Scope 'email' => $email, 'password' => $email, 'name' => $name, - 'userId' => $userId, + 'userId' => $userId ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -1536,7 +1548,7 @@ class ProjectsConsoleClientTest extends Scope 'email' => $email, 'password' => $name, 'name' => $name, - 'userId' => $userId, + 'userId' => $userId ]); $phone = '+123456789'; @@ -1549,7 +1561,7 @@ class ProjectsConsoleClientTest extends Scope 'password' => $phone, 'name' => $name, 'userId' => $userId, - 'phone' => $phone, + 'phone' => $phone ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -1557,7 +1569,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(Exception::USER_PASSWORD_PERSONAL_DATA, $response['body']['type']); /** Test for success */ - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'username'; $userId = ID::unique(); @@ -1569,12 +1581,12 @@ class ProjectsConsoleClientTest extends Scope 'email' => $email, 'password' => $password, 'name' => $name, - 'userId' => $userId, + 'userId' => $userId ]); $this->assertEquals(201, $response['headers']['status-code']); - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $userId = ID::unique(); $response = $this->client->call(Client::METHOD_POST, '/users', array_merge($this->getHeaders(), [ 'content-type' => 'application/json', @@ -1585,15 +1597,16 @@ class ProjectsConsoleClientTest extends Scope 'password' => $password, 'name' => $name, 'userId' => $userId, - 'phone' => $phone, + 'phone' => $phone ]); $this->assertEquals(201, $response['headers']['status-code']); + /** * Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/personal-data', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/personal-data', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1604,12 +1617,13 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(false, $response['body']['authPersonalDataCheck']); } + public function testUpdateProjectServiceStatusAdmin(): array { $team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), [ 'teamId' => ID::unique(), 'name' => 'Project Test', @@ -1620,34 +1634,34 @@ class ProjectsConsoleClientTest extends Scope $project = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), [ 'projectId' => ID::unique(), 'name' => 'Project Test', 'teamId' => $team['body']['$id'], - 'region' => 'default', + 'region' => 'default' ]); $this->assertEquals(201, $project['headers']['status-code']); $this->assertNotEmpty($project['body']['$id']); $id = $project['body']['$id']; - $services = require 'app/config/services.php'; + $services = require('app/config/services.php'); /** * Test for Disabled */ foreach ($services as $service) { - if (! $service['optional']) { + if (!$service['optional']) { continue; } $key = $service['key'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), [ 'service' => $key, 'status' => false, @@ -1656,39 +1670,40 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(false, $response['body']['serviceStatusFor'.ucfirst($key)]); + $this->assertEquals(false, $response['body']['serviceStatusFor' . ucfirst($key)]); } /** * Admin request must succeed */ + $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', // 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $id, - 'cookie' => 'a_session_console='.$this->getRoot()['session'], - 'x-appwrite-mode' => 'admin', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'x-appwrite-mode' => 'admin' ])); $this->assertEquals(200, $response['headers']['status-code']); foreach ($services as $service) { - if (! $service['optional']) { + if (!$service['optional']) { continue; } $key = $service['key'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service/', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1705,22 +1720,22 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId']; - $services = require 'app/config/services.php'; + $services = require('app/config/services.php'); /** * Test for Disabled */ foreach ($services as $service) { - if (! $service['optional']) { + if (!$service['optional']) { continue; } $key = $service['key'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), [ 'service' => $key, 'status' => false, @@ -1729,15 +1744,15 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(false, $response['body']['serviceStatusFor'.ucfirst($key)]); + $this->assertEquals(false, $response['body']['serviceStatusFor' . ucfirst($key)]); } /** @@ -1756,7 +1771,7 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $id, ]), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal', + 'name' => 'Arsenal' ]); $this->assertEquals(503, $response['headers']['status-code']); @@ -1764,7 +1779,7 @@ class ProjectsConsoleClientTest extends Scope // Cleanup foreach ($services as $service) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service/', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1779,22 +1794,22 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId']; - $services = require 'app/config/services.php'; + $services = require('app/config/services.php'); /** * Test for Disabled */ foreach ($services as $service) { - if (! $service['optional']) { + if (!$service['optional']) { continue; } $key = $service['key'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), [ 'service' => $key, 'status' => false, @@ -1803,22 +1818,22 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(false, $response['body']['serviceStatusFor'.ucfirst($key)]); + $this->assertEquals(false, $response['body']['serviceStatusFor' . ucfirst($key)]); } // Create API Key - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), [ 'name' => 'Key Test', 'scopes' => ['functions.read', 'teams.write'], @@ -1836,7 +1851,7 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $id, 'x-appwrite-key' => $keySecret, - 'x-sdk-name' => 'python', + 'x-sdk-name' => 'python' ])); $this->assertEquals(200, $response['headers']['status-code']); @@ -1845,19 +1860,19 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $id, 'x-appwrite-key' => $keySecret, - 'x-sdk-name' => 'php', + 'x-sdk-name' => 'php' ]), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal', + 'name' => 'Arsenal' ]); $this->assertEquals(201, $response['headers']['status-code']); /** Check that the API key has been updated */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), []); $this->assertEquals(200, $response['headers']['status-code']); @@ -1870,16 +1885,16 @@ class ProjectsConsoleClientTest extends Scope // Cleanup - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/keys/'.$keyId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/keys/' . $keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ]), []); $this->assertEquals(204, $response['headers']['status-code']); foreach ($services as $service) { - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service/', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1896,7 +1911,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1923,7 +1938,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1937,7 +1952,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1958,7 +1973,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -1981,7 +1996,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $webhookId = $data['webhookId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -1999,7 +2014,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/error', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2017,7 +2032,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $webhookId = $data['webhookId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2041,7 +2056,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('', $response['body']['httpUser']); $this->assertEquals('', $response['body']['httpPass']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2063,7 +2078,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2075,7 +2090,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2087,7 +2102,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2110,7 +2125,7 @@ class ProjectsConsoleClientTest extends Scope $webhookId = $data['webhookId'] ?? ''; $signatureKey = $data['signatureKey'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/webhooks/'.$webhookId.'/signature', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/webhooks/' . $webhookId . '/signature', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -2128,7 +2143,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $webhookId = $data['webhookId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2136,7 +2151,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2146,7 +2161,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/error', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2165,7 +2180,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2186,13 +2201,13 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, [ 'keyId' => $response['body']['$id'], - 'secret' => $response['body']['secret'], + 'secret' => $response['body']['secret'] ]); /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2205,6 +2220,7 @@ class ProjectsConsoleClientTest extends Scope return $data; } + /** * @depends testCreateProjectKey */ @@ -2212,11 +2228,12 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); @@ -2227,6 +2244,7 @@ class ProjectsConsoleClientTest extends Scope return $data; } + /** * @depends testCreateProjectKey */ @@ -2235,10 +2253,10 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $keyId = $data['keyId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $keyId, + 'x-appwrite-key' => $keyId ], $this->getHeaders()), []); $this->assertEquals(200, $response['headers']['status-code']); @@ -2257,7 +2275,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/error', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2277,7 +2295,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2289,7 +2307,7 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/health', [ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'x-appwrite-key' => $response['body']['secret'], + 'x-appwrite-key' => $response['body']['secret'] ], []); $this->assertEquals(200, $response['headers']['status-code']); @@ -2297,7 +2315,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2309,7 +2327,7 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/health', [ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'x-appwrite-key' => $response['body']['secret'], + 'x-appwrite-key' => $response['body']['secret'] ], []); $this->assertEquals(200, $response['headers']['status-code']); @@ -2317,7 +2335,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2329,12 +2347,13 @@ class ProjectsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/health', [ 'content-type' => 'application/json', 'x-appwrite-project' => $id, - 'x-appwrite-key' => $response['body']['secret'], + 'x-appwrite-key' => $response['body']['secret'] ], []); $this->assertEquals(401, $response['headers']['status-code']); } + /** * @depends testCreateProjectKey */ @@ -2343,7 +2362,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $keyId = $data['keyId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/keys/'.$keyId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/keys/' . $keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2365,7 +2384,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertArrayHasKey('accessedAt', $response['body']); $this->assertEmpty($response['body']['accessedAt']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2386,7 +2405,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/keys/'.$keyId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/keys/' . $keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2407,7 +2426,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $keyId = $data['keyId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/keys/'.$keyId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/keys/' . $keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2415,7 +2434,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2425,7 +2444,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/keys/error', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/keys/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2444,7 +2463,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2463,7 +2482,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformWebId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2482,7 +2501,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformFultteriOSId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2501,7 +2520,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformFultterAndroidId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2520,7 +2539,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformFultterWebId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2539,7 +2558,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformAppleIosId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2558,7 +2577,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformAppleMacOsId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2577,7 +2596,7 @@ class ProjectsConsoleClientTest extends Scope $data = array_merge($data, ['platformAppleWatchOsId' => $response['body']['$id']]); - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2599,7 +2618,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2622,7 +2641,7 @@ class ProjectsConsoleClientTest extends Scope sleep(1); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2646,7 +2665,7 @@ class ProjectsConsoleClientTest extends Scope $platformWebId = $data['platformWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2662,7 +2681,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultteriOSId = $data['platformFultteriOSId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2678,7 +2697,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterAndroidId = $data['platformFultterAndroidId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2694,7 +2713,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterWebId = $data['platformFultterWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterWebId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2710,7 +2729,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleIosId = $data['platformAppleIosId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2726,7 +2745,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleMacOsId = $data['platformAppleMacOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2742,7 +2761,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleWatchOsId = $data['platformAppleWatchOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2758,7 +2777,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleTvOsId = $data['platformAppleTvOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2775,7 +2794,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/error', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2794,7 +2813,7 @@ class ProjectsConsoleClientTest extends Scope $platformWebId = $data['platformWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2813,7 +2832,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultteriOSId = $data['platformFultteriOSId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2832,7 +2851,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterAndroidId = $data['platformFultterAndroidId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2851,7 +2870,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterWebId = $data['platformFultterWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformFultterWebId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformFultterWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2870,7 +2889,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleIosId = $data['platformAppleIosId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2889,7 +2908,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleMacOsId = $data['platformAppleMacOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2908,7 +2927,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleWatchOsId = $data['platformAppleWatchOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2927,7 +2946,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleTvOsId = $data['platformAppleTvOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2947,7 +2966,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/error', array_merge([ + $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -2969,7 +2988,7 @@ class ProjectsConsoleClientTest extends Scope $platformWebId = $data['platformWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2977,7 +2996,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2986,7 +3005,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultteriOSId = $data['platformFultteriOSId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -2994,7 +3013,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3003,7 +3022,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterAndroidId = $data['platformFultterAndroidId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3011,7 +3030,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3020,7 +3039,7 @@ class ProjectsConsoleClientTest extends Scope $platformFultterWebId = $data['platformFultterWebId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformFultterWebId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformFultterWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3028,7 +3047,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterWebId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterWebId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3037,7 +3056,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleIosId = $data['platformAppleIosId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3045,7 +3064,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3054,7 +3073,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleMacOsId = $data['platformAppleMacOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3062,7 +3081,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3071,7 +3090,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleWatchOsId = $data['platformAppleWatchOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3079,7 +3098,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3088,7 +3107,7 @@ class ProjectsConsoleClientTest extends Scope $platformAppleTvOsId = $data['platformAppleTvOsId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3096,7 +3115,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3106,7 +3125,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/error', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3125,7 +3144,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/domains', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/domains', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3145,7 +3164,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -3154,13 +3173,13 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'type' => 'web', 'name' => 'Too Long Hostname', - 'hostname' => \str_repeat('bestdomain', 25).'.com', // 250 + 4 chars total (exactly above limit) + 'hostname' => \str_repeat("bestdomain", 25) . '.com' // 250 + 4 chars total (exactly above limit) ]); return $data; @@ -3173,7 +3192,7 @@ class ProjectsConsoleClientTest extends Scope { $id = $data['projectId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3196,7 +3215,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $domainId = $data['domainId'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains/'.$domainId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/' . $domainId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3213,7 +3232,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains/error', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3231,7 +3250,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $domainId = $data['domainId'] ?? ''; - $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/domains/'.$domainId.'/verification', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/domains/' . $domainId . '/verification', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3253,7 +3272,7 @@ class ProjectsConsoleClientTest extends Scope $id = $data['projectId'] ?? ''; $domainId = $data['domainId'] ?? ''; - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/domains/'.$domainId, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/domains/' . $domainId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3261,7 +3280,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains/'.$domainId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/' . $domainId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3271,7 +3290,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/domains/error', array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/domains/error', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -3307,7 +3326,7 @@ class ProjectsConsoleClientTest extends Scope 'projectId' => ID::unique(), 'name' => 'Amazing Project', 'teamId' => $teamId, - 'region' => 'default', + 'region' => 'default' ]); $this->assertEquals(201, $project['headers']['status-code']); @@ -3318,14 +3337,14 @@ class ProjectsConsoleClientTest extends Scope $projectId = $project['body']['$id']; // Ensure I can get both team and project - $team = $this->client->call(Client::METHOD_GET, '/teams/'.$teamId, array_merge([ + $team = $this->client->call(Client::METHOD_GET, '/teams/' . $teamId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $team['headers']['status-code']); - $project = $this->client->call(Client::METHOD_GET, '/projects/'.$projectId, array_merge([ + $project = $this->client->call(Client::METHOD_GET, '/projects/' . $projectId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3333,7 +3352,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $project['headers']['status-code']); // Delete Project - $project = $this->client->call(Client::METHOD_DELETE, '/projects/'.$projectId, array_merge([ + $project = $this->client->call(Client::METHOD_DELETE, '/projects/' . $projectId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -3341,14 +3360,14 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $project['headers']['status-code']); // Ensure I can get team but not a project - $team = $this->client->call(Client::METHOD_GET, '/teams/'.$teamId, array_merge([ + $team = $this->client->call(Client::METHOD_GET, '/teams/' . $teamId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $team['headers']['status-code']); - $project = $this->client->call(Client::METHOD_GET, '/projects/'.$projectId, array_merge([ + $project = $this->client->call(Client::METHOD_GET, '/projects/' . $projectId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/e2e/Services/Projects/ProjectsCustomClientTest.php b/tests/e2e/Services/Projects/ProjectsCustomClientTest.php index 25140309af..9dfd48ce50 100644 --- a/tests/e2e/Services/Projects/ProjectsCustomClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsCustomClientTest.php @@ -2,9 +2,10 @@ namespace Tests\E2E\Services\Projects; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; +use Tests\E2E\Client; class ProjectsCustomClientTest extends Scope { diff --git a/tests/e2e/Services/Projects/ProjectsCustomServerTest.php b/tests/e2e/Services/Projects/ProjectsCustomServerTest.php index 436d1df611..1c5b48f146 100644 --- a/tests/e2e/Services/Projects/ProjectsCustomServerTest.php +++ b/tests/e2e/Services/Projects/ProjectsCustomServerTest.php @@ -5,6 +5,7 @@ namespace Tests\E2E\Services\Projects; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; +use Tests\E2E\Client; class ProjectsCustomServerTest extends Scope { diff --git a/tests/e2e/Services/Realtime/RealtimeBase.php b/tests/e2e/Services/Realtime/RealtimeBase.php index baf27e78ea..62bb7f5d3b 100644 --- a/tests/e2e/Services/Realtime/RealtimeBase.php +++ b/tests/e2e/Services/Realtime/RealtimeBase.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Realtime; -use WebSocket\Client as WebSocketClient; use WebSocket\ConnectionException; +use WebSocket\Client as WebSocketClient; trait RealtimeBase { @@ -14,15 +14,15 @@ trait RealtimeBase } $headers = array_merge([ - 'Origin' => 'appwrite.test', + 'Origin' => 'appwrite.test' ], $headers); $query = [ 'project' => $projectId, - 'channels' => $channels, + 'channels' => $channels ]; - return new WebSocketClient('ws://appwrite-traefik/v1/realtime?'.http_build_query($query), [ + return new WebSocketClient('ws://appwrite-traefik/v1/realtime?' . http_build_query($query), [ 'headers' => $headers, 'timeout' => 30, ]); @@ -57,8 +57,8 @@ trait RealtimeBase { $client = new WebSocketClient('ws://appwrite-traefik/v1/realtime?project=123', [ 'headers' => [ - 'Origin' => 'appwrite.test', - ], + 'Origin' => 'appwrite.test' + ] ]); $payload = json_decode($client->receive(), true); diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php index 363da4d611..3ef258885c 100644 --- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php @@ -4,8 +4,8 @@ namespace Tests\E2E\Services\Realtime; use CURLFile; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideConsole; use Tests\E2E\Services\Functions\FunctionsBase; use Utopia\Database\Helpers\ID; @@ -29,7 +29,7 @@ class RealtimeConsoleClientTest extends Scope * Test for SUCCESS */ $client = $this->getWebsocket(['account'], [ - 'origin' => 'http://localhost', + 'origin' => 'http://localhost' ]); $response = json_decode($client->receive(), true); @@ -43,8 +43,8 @@ class RealtimeConsoleClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', 'data' => [ - 'session' => $session, - ], + 'session' => $session + ] ])); $response = json_decode($client->receive(), true); @@ -64,8 +64,8 @@ class RealtimeConsoleClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', 'data' => [ - 'session' => 'invalid_session', - ], + 'session' => 'invalid_session' + ] ])); $response = json_decode($client->receive(), true); @@ -79,7 +79,7 @@ class RealtimeConsoleClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', - 'data' => [], + 'data' => [] ])); $response = json_decode($client->receive(), true); @@ -94,8 +94,8 @@ class RealtimeConsoleClientTest extends Scope $client->send(\json_encode([ 'type' => 'unknown', 'data' => [ - 'session' => 'invalid_session', - ], + 'session' => 'invalid_session' + ] ])); $response = json_decode($client->receive(), true); @@ -120,6 +120,7 @@ class RealtimeConsoleClientTest extends Scope $this->assertEquals(1003, $response['data']['code']); $this->assertEquals('Message format is not valid.', $response['data']['message']); + $client->close(); } @@ -130,7 +131,7 @@ class RealtimeConsoleClientTest extends Scope $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -158,7 +159,7 @@ class RealtimeConsoleClientTest extends Scope /** * Test Attributes */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -174,7 +175,7 @@ class RealtimeConsoleClientTest extends Scope $actorsId = $actors['body']['$id']; - $name = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ + $name = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -206,7 +207,7 @@ class RealtimeConsoleClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.attributes.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains('databases.*', $response['data']['events']); + $this->assertContains("databases.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals('processing', $response['data']['payload']['status']); @@ -226,7 +227,7 @@ class RealtimeConsoleClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.attributes.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains('databases.*', $response['data']['events']); + $this->assertContains("databases.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals('available', $response['data']['payload']['status']); @@ -247,7 +248,7 @@ class RealtimeConsoleClientTest extends Scope $databaseId = $data['databaseId']; $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -263,7 +264,7 @@ class RealtimeConsoleClientTest extends Scope /** * Test Indexes */ - $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -329,7 +330,7 @@ class RealtimeConsoleClientTest extends Scope $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -345,7 +346,7 @@ class RealtimeConsoleClientTest extends Scope /** * Test Delete Index */ - $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actorsId.'/indexes/key_name', array_merge([ + $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actorsId . '/indexes/key_name', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -385,7 +386,7 @@ class RealtimeConsoleClientTest extends Scope $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -401,7 +402,7 @@ class RealtimeConsoleClientTest extends Scope /** * Test Delete Attribute */ - $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['actorsId'].'/attributes/name', array_merge([ + $attribute = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/attributes/name', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -442,18 +443,19 @@ class RealtimeConsoleClientTest extends Scope 'users.*.delete', ], 'schedule' => '0 0 1 1 *', - 'timeout' => 10, + 'timeout' => 10 ]); $functionId = $response1['body']['$id'] ?? ''; $this->assertEquals(201, $response1['headers']['status-code']); + $projectId = 'console'; $client = $this->getWebsocket(['console'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_console='.$this->getRoot()['session'], + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], ], $projectId); $response = json_decode($client->receive(), true); @@ -469,17 +471,18 @@ class RealtimeConsoleClientTest extends Scope /** * Test Create Deployment */ + $folder = 'php'; - $code = realpath(__DIR__.'/../../../resources/functions')."/$folder/code.tar.gz"; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); - $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([ + $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' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), - 'activate' => true, + 'activate' => true ]); $deploymentId = $deployment['body']['$id'] ?? ''; diff --git a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php index 456bb7d333..4f880338a4 100644 --- a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php @@ -4,8 +4,8 @@ namespace Tests\E2E\Services\Realtime; use CURLFile; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; use Utopia\CLI\Console; use Utopia\Database\Helpers\ID; @@ -25,9 +25,9 @@ class RealtimeCustomClientTest extends Scope $userId = $user['$id'] ?? ''; $session = $user['session'] ?? ''; - $headers = [ + $headers = [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session ]; $client = $this->getWebsocket(['documents'], $headers); @@ -54,7 +54,7 @@ class RealtimeCustomClientTest extends Scope $this->assertNotEmpty($response['data']['user']); $this->assertCount(2, $response['data']['channels']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertEquals($userId, $response['data']['user']['$id']); $client->close(); @@ -70,7 +70,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(3, $response['data']['channels']); $this->assertContains('documents', $response['data']['channels']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertEquals($userId, $response['data']['user']['$id']); $client->close(); @@ -96,7 +96,7 @@ class RealtimeCustomClientTest extends Scope $this->assertNotEmpty($response['data']['user']); $this->assertCount(10, $response['data']['channels']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains('files', $response['data']['channels']); $this->assertContains('files.1', $response['data']['channels']); $this->assertContains('collections', $response['data']['channels']); @@ -120,7 +120,7 @@ class RealtimeCustomClientTest extends Scope * Test for SUCCESS */ $client = $this->getWebsocket(['account'], [ - 'origin' => 'http://localhost', + 'origin' => 'http://localhost' ]); $response = json_decode($client->receive(), true); @@ -134,8 +134,8 @@ class RealtimeCustomClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', 'data' => [ - 'session' => $session, - ], + 'session' => $session + ] ])); $response = json_decode($client->receive(), true); @@ -155,8 +155,8 @@ class RealtimeCustomClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', 'data' => [ - 'session' => 'invalid_session', - ], + 'session' => 'invalid_session' + ] ])); $response = json_decode($client->receive(), true); @@ -170,7 +170,7 @@ class RealtimeCustomClientTest extends Scope $client->send(\json_encode([ 'type' => 'authentication', - 'data' => [], + 'data' => [] ])); $response = json_decode($client->receive(), true); @@ -185,8 +185,8 @@ class RealtimeCustomClientTest extends Scope $client->send(\json_encode([ 'type' => 'unknown', 'data' => [ - 'session' => 'invalid_session', - ], + 'session' => 'invalid_session' + ] ])); $response = json_decode($client->receive(), true); @@ -211,6 +211,7 @@ class RealtimeCustomClientTest extends Scope $this->assertEquals(1003, $response['data']['code']); $this->assertEquals('Message format is not valid.', $response['data']['message']); + $client->close(); } @@ -241,7 +242,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['account'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session ]); $response = json_decode($client->receive(), true); @@ -251,22 +252,22 @@ class RealtimeCustomClientTest extends Scope $this->assertNotEmpty($response['data']); $this->assertCount(2, $response['data']['channels']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertNotEmpty($response['data']['user']); $this->assertEquals($userId, $response['data']['user']['$id']); /** * Test Account Name Event */ - $name = 'Torsten Dittmann'; + $name = "Torsten Dittmann"; $this->client->call(Client::METHOD_PATCH, '/account/name', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session, ]), [ - 'name' => $name, + 'name' => $name ]); $response = json_decode($client->receive(), true); @@ -278,17 +279,18 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.update.name", $response['data']['events']); $this->assertContains("users.{$userId}.update", $response['data']['events']); $this->assertContains("users.{$userId}", $response['data']['events']); - $this->assertContains('users.*.update.name', $response['data']['events']); - $this->assertContains('users.*.update', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.update.name", $response['data']['events']); + $this->assertContains("users.*.update", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($name, $response['data']['payload']['name']); + /** * Test Account Password Event */ @@ -296,7 +298,7 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session, ]), [ 'password' => 'new-password', 'oldPassword' => 'password', @@ -311,13 +313,13 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.update.password", $response['data']['events']); $this->assertContains("users.{$userId}.update", $response['data']['events']); $this->assertContains("users.{$userId}", $response['data']['events']); - $this->assertContains('users.*.update.password', $response['data']['events']); - $this->assertContains('users.*.update', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.update.password", $response['data']['events']); + $this->assertContains("users.*.update", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($name, $response['data']['payload']['name']); @@ -329,7 +331,7 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session, ]), [ 'email' => 'torsten@appwrite.io', 'password' => 'new-password', @@ -344,13 +346,13 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.update.email", $response['data']['events']); $this->assertContains("users.{$userId}.update", $response['data']['events']); $this->assertContains("users.{$userId}", $response['data']['events']); - $this->assertContains('users.*.update.email', $response['data']['events']); - $this->assertContains('users.*.update', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.update.email", $response['data']['events']); + $this->assertContains("users.*.update", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals('torsten@appwrite.io', $response['data']['payload']['email']); @@ -361,7 +363,7 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session, ]), [ 'url' => 'http://localhost/verification', ]); @@ -375,7 +377,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.verification.{$verificationId}.create", $response['data']['events']); $this->assertContains("users.{$userId}.verification.{$verificationId}", $response['data']['events']); $this->assertContains("users.{$userId}.verification.*.create", $response['data']['events']); @@ -383,9 +385,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.verification.{$verificationId}.create", $response['data']['events']); $this->assertContains("users.*.verification.{$verificationId}", $response['data']['events']); - $this->assertContains('users.*.verification.*.create', $response['data']['events']); - $this->assertContains('users.*.verification.*', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.verification.*.create", $response['data']['events']); + $this->assertContains("users.*.verification.*", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $lastEmail = $this->getLastEmail(); $verification = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); @@ -397,7 +399,7 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session, ]), [ 'userId' => $userId, 'secret' => $verification, @@ -412,7 +414,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.verification.{$verificationId}.update", $response['data']['events']); $this->assertContains("users.{$userId}.verification.{$verificationId}", $response['data']['events']); $this->assertContains("users.{$userId}.verification.*.update", $response['data']['events']); @@ -420,9 +422,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.verification.{$verificationId}.update", $response['data']['events']); $this->assertContains("users.*.verification.{$verificationId}", $response['data']['events']); - $this->assertContains('users.*.verification.*.update', $response['data']['events']); - $this->assertContains('users.*.verification.*', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.verification.*.update", $response['data']['events']); + $this->assertContains("users.*.verification.*", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); /** * Test Acoount Prefs Update */ @@ -430,12 +432,12 @@ class RealtimeCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session, ]), [ 'prefs' => [ 'prefKey1' => 'prefValue1', 'prefKey2' => 'prefValue2', - ], + ] ]); $response = json_decode($client->receive(), true); @@ -447,13 +449,13 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.update.prefs", $response['data']['events']); $this->assertContains("users.{$userId}.update", $response['data']['events']); $this->assertContains("users.{$userId}", $response['data']['events']); - $this->assertContains('users.*.update.prefs', $response['data']['events']); - $this->assertContains('users.*.update', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.update.prefs", $response['data']['events']); + $this->assertContains("users.*.update", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $createSession = function () use ($projectId): array { @@ -466,10 +468,10 @@ class RealtimeCustomClientTest extends Scope 'password' => 'new-password', ]); - $sessionNew = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$projectId]; + $sessionNew = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $projectId]; $sessionNewId = $response['body']['$id']; - return ['session' => $sessionNew, 'sessionId' => $sessionNewId]; + return array("session" => $sessionNew, "sessionId" => $sessionNewId); }; /** @@ -488,7 +490,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}.create", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.*.create", $response['data']['events']); @@ -496,19 +498,19 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}.create", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}", $response['data']['events']); - $this->assertContains('users.*.sessions.*.create', $response['data']['events']); - $this->assertContains('users.*.sessions.*', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.sessions.*.create", $response['data']['events']); + $this->assertContains("users.*.sessions.*", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test Account Session Delete */ - $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionNewId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionNewId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, - 'cookie' => 'a_session_'.$projectId.'='.$sessionNew, + 'cookie' => 'a_session_' . $projectId . '=' . $sessionNew, ])); $response = json_decode($client->receive(), true); @@ -520,7 +522,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}.delete", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.*.delete", $response['data']['events']); @@ -528,20 +530,21 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}.delete", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}", $response['data']['events']); - $this->assertContains('users.*.sessions.*.delete', $response['data']['events']); - $this->assertContains('users.*.sessions.*', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.sessions.*.delete", $response['data']['events']); + $this->assertContains("users.*.sessions.*", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test User Account Session Delete */ + $sessionData = $createSession(); $sessionNew = $sessionData['session']; $sessionNewId = $sessionData['sessionId']; $client->receive(); // Receive the creation message and drop; this was tested earlier already - $this->client->call(Client::METHOD_DELETE, '/users/'.$userId.'/sessions/'.$sessionNewId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/users/' . $userId . '/sessions/' . $sessionNewId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, @@ -556,7 +559,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}.delete", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.{$sessionNewId}", $response['data']['events']); $this->assertContains("users.{$userId}.sessions.*.delete", $response['data']['events']); @@ -564,9 +567,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}.delete", $response['data']['events']); $this->assertContains("users.*.sessions.{$sessionNewId}", $response['data']['events']); - $this->assertContains('users.*.sessions.*.delete', $response['data']['events']); - $this->assertContains('users.*.sessions.*', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.sessions.*.delete", $response['data']['events']); + $this->assertContains("users.*.sessions.*", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** @@ -593,7 +596,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.recovery.{$recoveryId}.create", $response['data']['events']); $this->assertContains("users.{$userId}.recovery.{$recoveryId}", $response['data']['events']); $this->assertContains("users.{$userId}.recovery.*.create", $response['data']['events']); @@ -601,9 +604,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.recovery.{$recoveryId}.create", $response['data']['events']); $this->assertContains("users.*.recovery.{$recoveryId}", $response['data']['events']); - $this->assertContains('users.*.recovery.*.create', $response['data']['events']); - $this->assertContains('users.*.recovery.*', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.recovery.*.create", $response['data']['events']); + $this->assertContains("users.*.recovery.*", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $response = $this->client->call(Client::METHOD_PUT, '/account/recovery', array_merge([ @@ -626,7 +629,7 @@ class RealtimeCustomClientTest extends Scope $this->assertCount(2, $response['data']['channels']); $this->assertArrayHasKey('timestamp', $response['data']); $this->assertContains('account', $response['data']['channels']); - $this->assertContains('account.'.$userId, $response['data']['channels']); + $this->assertContains('account.' . $userId, $response['data']['channels']); $this->assertContains("users.{$userId}.recovery.{$recoveryId}.update", $response['data']['events']); $this->assertContains("users.{$userId}.recovery.{$recoveryId}", $response['data']['events']); $this->assertContains("users.{$userId}.recovery.*.update", $response['data']['events']); @@ -634,9 +637,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("users.{$userId}", $response['data']['events']); $this->assertContains("users.*.recovery.{$recoveryId}.update", $response['data']['events']); $this->assertContains("users.*.recovery.{$recoveryId}", $response['data']['events']); - $this->assertContains('users.*.recovery.*.update', $response['data']['events']); - $this->assertContains('users.*.recovery.*', $response['data']['events']); - $this->assertContains('users.*', $response['data']['events']); + $this->assertContains("users.*.recovery.*.update", $response['data']['events']); + $this->assertContains("users.*.recovery.*", $response['data']['events']); + $this->assertContains("users.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $client->close(); @@ -650,7 +653,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['documents', 'collections'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session ]); $response = json_decode($client->receive(), true); @@ -671,7 +674,7 @@ class RealtimeCustomClientTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'Actors DB', @@ -682,10 +685,10 @@ class RealtimeCustomClientTest extends Scope /** * Test Collection Create */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -697,10 +700,10 @@ class RealtimeCustomClientTest extends Scope $actorsId = $actors['body']['$id']; - $name = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ + $name = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'name', 'size' => 256, @@ -718,13 +721,13 @@ class RealtimeCustomClientTest extends Scope /** * Test Document Create */ - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Chris Evans', + 'name' => 'Chris Evans' ], 'permissions' => [ Permission::read(Role::any()), @@ -744,8 +747,8 @@ class RealtimeCustomClientTest extends Scope $this->assertArrayHasKey('timestamp', $response['data']); $this->assertCount(3, $response['data']['channels']); $this->assertContains('documents', $response['data']['channels']); - $this->assertContains('databases.'.$databaseId.'.collections.'.$actorsId.'.documents.'.$documentId, $response['data']['channels']); - $this->assertContains('databases.'.$databaseId.'.collections.'.$actorsId.'.documents', $response['data']['channels']); + $this->assertContains('databases.' . $databaseId . '.collections.' . $actorsId . '.documents.' . $documentId, $response['data']['channels']); + $this->assertContains('databases.' . $databaseId . '.collections.' . $actorsId . '.documents', $response['data']['channels']); $this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.{$documentId}.create", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.{$documentId}", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.*.create", $response['data']['events']); @@ -757,20 +760,20 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains('databases.*', $response['data']['events']); + $this->assertContains("databases.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Chris Evans'); /** * Test Document Update */ - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$documentId, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Chris Evans 2', + 'name' => 'Chris Evans 2' ], 'permissions' => [ Permission::read(Role::any()), @@ -801,7 +804,7 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains('databases.*', $response['data']['events']); + $this->assertContains("databases.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2'); @@ -809,13 +812,13 @@ class RealtimeCustomClientTest extends Scope /** * Test Document Delete */ - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Bradley Cooper', + 'name' => 'Bradley Cooper' ], 'permissions' => [ Permission::read(Role::any()), @@ -828,7 +831,7 @@ class RealtimeCustomClientTest extends Scope $documentId = $document['body']['$id']; - $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$documentId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -855,7 +858,7 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains('databases.*', $response['data']['events']); + $this->assertContains("databases.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper'); @@ -870,7 +873,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['documents', 'collections'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session ]); $response = json_decode($client->receive(), true); @@ -891,7 +894,7 @@ class RealtimeCustomClientTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'databaseId' => ID::unique(), 'name' => 'Actors DB', @@ -902,10 +905,10 @@ class RealtimeCustomClientTest extends Scope /** * Test Collection Create */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -914,15 +917,15 @@ class RealtimeCustomClientTest extends Scope Permission::create(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()), - ], + ] ]); $actorsId = $actors['body']['$id']; - $name = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ + $name = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'name', 'size' => 256, @@ -940,13 +943,13 @@ class RealtimeCustomClientTest extends Scope /** * Test Document Create */ - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Chris Evans', + 'name' => 'Chris Evans' ], 'permissions' => [], ]); @@ -975,19 +978,19 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains('databases.*', $response['data']['events']); + $this->assertContains("databases.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Chris Evans'); /** * Test Document Update */ - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$documentId, array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'data' => [ - 'name' => 'Chris Evans 2', + 'name' => 'Chris Evans 2' ], 'permissions' => [], ]); @@ -1014,7 +1017,7 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains('databases.*', $response['data']['events']); + $this->assertContains("databases.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2'); @@ -1022,13 +1025,13 @@ class RealtimeCustomClientTest extends Scope /** * Test Document Delete */ - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'documentId' => ID::unique(), 'data' => [ - 'name' => 'Bradley Cooper', + 'name' => 'Bradley Cooper' ], 'permissions' => [], ]); @@ -1037,7 +1040,7 @@ class RealtimeCustomClientTest extends Scope $client->receive(); - $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$documentId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1064,7 +1067,7 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("databases.{$databaseId}.collections.*.documents.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}.collections.*", $response['data']['events']); $this->assertContains("databases.{$databaseId}", $response['data']['events']); - $this->assertContains('databases.*', $response['data']['events']); + $this->assertContains("databases.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper'); @@ -1079,7 +1082,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['files'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session ]); $response = json_decode($client->receive(), true); @@ -1098,7 +1101,7 @@ class RealtimeCustomClientTest extends Scope $bucket1 = $this->client->call(Client::METHOD_POST, '/storage/buckets', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'bucketId' => ID::unique(), 'name' => 'Bucket 1', @@ -1107,7 +1110,7 @@ class RealtimeCustomClientTest extends Scope Permission::create(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()), - ], + ] ]); $bucketId = $bucket1['body']['$id']; @@ -1115,12 +1118,12 @@ class RealtimeCustomClientTest extends Scope /** * Test File Create */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -1148,9 +1151,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("buckets.{$bucketId}", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}.create", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}", $response['data']['events']); - $this->assertContains('buckets.*.files.*.create', $response['data']['events']); - $this->assertContains('buckets.*.files.*', $response['data']['events']); - $this->assertContains('buckets.*', $response['data']['events']); + $this->assertContains("buckets.*.files.*.create", $response['data']['events']); + $this->assertContains("buckets.*.files.*", $response['data']['events']); + $this->assertContains("buckets.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $fileId = $file['body']['$id']; @@ -1158,7 +1161,7 @@ class RealtimeCustomClientTest extends Scope /** * Test File Update */ - $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1187,15 +1190,15 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("buckets.{$bucketId}", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}.update", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}", $response['data']['events']); - $this->assertContains('buckets.*.files.*.update', $response['data']['events']); - $this->assertContains('buckets.*.files.*', $response['data']['events']); - $this->assertContains('buckets.*', $response['data']['events']); + $this->assertContains("buckets.*.files.*.update", $response['data']['events']); + $this->assertContains("buckets.*.files.*", $response['data']['events']); + $this->assertContains("buckets.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test File Delete */ - $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1218,9 +1221,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("buckets.{$bucketId}", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}.delete", $response['data']['events']); $this->assertContains("buckets.*.files.{$fileId}", $response['data']['events']); - $this->assertContains('buckets.*.files.*.delete', $response['data']['events']); - $this->assertContains('buckets.*.files.*', $response['data']['events']); - $this->assertContains('buckets.*', $response['data']['events']); + $this->assertContains("buckets.*.files.*.delete", $response['data']['events']); + $this->assertContains("buckets.*.files.*", $response['data']['events']); + $this->assertContains("buckets.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $client->close(); @@ -1234,7 +1237,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['executions'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session ]); $response = json_decode($client->receive(), true); @@ -1254,7 +1257,7 @@ class RealtimeCustomClientTest extends Scope $function = $this->client->call(Client::METHOD_POST, '/functions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'functionId' => ID::unique(), 'name' => 'Test', @@ -1271,18 +1274,18 @@ class RealtimeCustomClientTest extends Scope $folder = 'timeout'; $stderr = ''; $stdout = ''; - $code = realpath(__DIR__.'/../../../resources/functions')."/{$folder}/code.tar.gz"; + $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); + 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([ + $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'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', basename($code)), - 'activate' => true, + 'activate' => true ]); $deploymentId = $deployment['body']['$id'] ?? ''; @@ -1293,20 +1296,20 @@ class RealtimeCustomClientTest extends Scope // Wait for deployment to be built. sleep(10); - $response = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), []); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']['$id']); - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'async' => true, + 'async' => true ]); $this->assertEquals($execution['headers']['status-code'], 202); @@ -1334,9 +1337,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("functions.{$functionId}", $response['data']['events']); $this->assertContains("functions.*.executions.{$executionId}.create", $response['data']['events']); $this->assertContains("functions.*.executions.{$executionId}", $response['data']['events']); - $this->assertContains('functions.*.executions.*.create', $response['data']['events']); - $this->assertContains('functions.*.executions.*', $response['data']['events']); - $this->assertContains('functions.*', $response['data']['events']); + $this->assertContains("functions.*.executions.*.create", $response['data']['events']); + $this->assertContains("functions.*.executions.*", $response['data']['events']); + $this->assertContains("functions.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertArrayHasKey('type', $responseUpdate); @@ -1356,15 +1359,15 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("functions.{$functionId}", $responseUpdate['data']['events']); $this->assertContains("functions.*.executions.{$executionId}.update", $responseUpdate['data']['events']); $this->assertContains("functions.*.executions.{$executionId}", $responseUpdate['data']['events']); - $this->assertContains('functions.*.executions.*.update', $responseUpdate['data']['events']); - $this->assertContains('functions.*.executions.*', $responseUpdate['data']['events']); - $this->assertContains('functions.*', $responseUpdate['data']['events']); + $this->assertContains("functions.*.executions.*.update", $responseUpdate['data']['events']); + $this->assertContains("functions.*.executions.*", $responseUpdate['data']['events']); + $this->assertContains("functions.*", $responseUpdate['data']['events']); $this->assertNotEmpty($responseUpdate['data']['payload']); $client->close(); // Cleanup : Delete function - $response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$functionId, [ + $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'], @@ -1381,7 +1384,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['teams'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session ]); $response = json_decode($client->receive(), true); @@ -1403,7 +1406,7 @@ class RealtimeCustomClientTest extends Scope 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal', + 'name' => 'Arsenal' ]); $teamId = $team['body']['$id'] ?? ''; @@ -1423,18 +1426,18 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("teams.{$teamId}", $response['data']['channels']); $this->assertContains("teams.{$teamId}.create", $response['data']['events']); $this->assertContains("teams.{$teamId}", $response['data']['events']); - $this->assertContains('teams.*.create', $response['data']['events']); - $this->assertContains('teams.*', $response['data']['events']); + $this->assertContains("teams.*.create", $response['data']['events']); + $this->assertContains("teams.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test Team Update */ - $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$teamId, array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ - 'name' => 'Manchester', + 'name' => 'Manchester' ]); $this->assertEquals($team['headers']['status-code'], 200); @@ -1452,21 +1455,21 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("teams.{$teamId}", $response['data']['channels']); $this->assertContains("teams.{$teamId}.update", $response['data']['events']); $this->assertContains("teams.{$teamId}", $response['data']['events']); - $this->assertContains('teams.*.update', $response['data']['events']); - $this->assertContains('teams.*', $response['data']['events']); + $this->assertContains("teams.*.update", $response['data']['events']); + $this->assertContains("teams.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); /** * Test Team Update Prefs */ - $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$teamId.'/prefs', array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamId . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ 'prefs' => [ 'funcKey1' => 'funcValue1', 'funcKey2' => 'funcValue2', - ], + ] ]); $this->assertEquals($team['headers']['status-code'], 200); @@ -1486,9 +1489,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("teams.{$teamId}.update", $response['data']['events']); $this->assertContains("teams.{$teamId}.update.prefs", $response['data']['events']); $this->assertContains("teams.{$teamId}", $response['data']['events']); - $this->assertContains('teams.*.update.prefs', $response['data']['events']); - $this->assertContains('teams.*.update', $response['data']['events']); - $this->assertContains('teams.*', $response['data']['events']); + $this->assertContains("teams.*.update.prefs", $response['data']['events']); + $this->assertContains("teams.*.update", $response['data']['events']); + $this->assertContains("teams.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $this->assertEquals($response['data']['payload']['funcKey1'], 'funcValue1'); $this->assertEquals($response['data']['payload']['funcKey2'], 'funcValue2'); @@ -1511,7 +1514,7 @@ class RealtimeCustomClientTest extends Scope $client = $this->getWebsocket(['memberships'], [ 'origin' => 'http://localhost', - 'cookie' => 'a_session_'.$projectId.'='.$session, + 'cookie' => 'a_session_' . $projectId . '=' . $session ]); $response = json_decode($client->receive(), true); @@ -1525,7 +1528,7 @@ class RealtimeCustomClientTest extends Scope $this->assertNotEmpty($response['data']['user']); $this->assertEquals($user['$id'], $response['data']['user']['$id']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamId.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamId . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1536,12 +1539,12 @@ class RealtimeCustomClientTest extends Scope * Test Update Membership */ $roles = ['admin', 'editor', 'uncle']; - $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamId.'/memberships/'.$membershipId, array_merge([ + $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamId . '/memberships/' . $membershipId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'roles' => $roles, + 'roles' => $roles ]); $response = json_decode($client->receive(), true); @@ -1561,9 +1564,9 @@ class RealtimeCustomClientTest extends Scope $this->assertContains("teams.{$teamId}", $response['data']['events']); $this->assertContains("teams.*.memberships.{$membershipId}.update", $response['data']['events']); $this->assertContains("teams.*.memberships.{$membershipId}", $response['data']['events']); - $this->assertContains('teams.*.memberships.*.update', $response['data']['events']); - $this->assertContains('teams.*.memberships.*', $response['data']['events']); - $this->assertContains('teams.*', $response['data']['events']); + $this->assertContains("teams.*.memberships.*.update", $response['data']['events']); + $this->assertContains("teams.*.memberships.*", $response['data']['events']); + $this->assertContains("teams.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); $client->close(); diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index 9b0a6449d3..b19fe49ed0 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -4,6 +4,7 @@ namespace Tests\E2E\Services\Storage; use CURLFile; use Tests\E2E\Client; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -25,7 +26,7 @@ trait StorageBase 'name' => 'Test Bucket', 'fileSecurity' => true, 'maximumFileSize' => 2000000, //2MB - 'allowedFileExtensions' => ['jpg', 'png'], + 'allowedFileExtensions' => ["jpg", "png"], 'permissions' => [ Permission::read(Role::any()), Permission::create(Role::any()), @@ -38,12 +39,12 @@ trait StorageBase $bucketId = $bucket['body']['$id']; - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -57,7 +58,7 @@ trait StorageBase $this->assertEquals('logo.png', $file['body']['name']); $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $this->assertTrue(md5_file(realpath(__DIR__.'/../../../resources/logo.png')) == $file['body']['signature']); + $this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) == $file['body']['signature']); /** * Test for Large File above 20MB * This should also validate the test for when Bucket encryption @@ -84,26 +85,27 @@ trait StorageBase /** * Chunked Upload */ - $source = __DIR__.'/../../../resources/disk-a/large-file.mp4'; + + $source = __DIR__ . "/../../../resources/disk-a/large-file.mp4"; $totalSize = \filesize($source); $chunkSize = 5 * 1024 * 1024; - $handle = @fopen($source, 'rb'); + $handle = @fopen($source, "rb"); $fileId = 'unique()'; $mimeType = mime_content_type($source); $counter = 0; $size = filesize($source); $headers = [ 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ]; $id = ''; - while (! feof($handle)) { - $curlFile = new \CURLFile('data://'.$mimeType.';base64,'.base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4'); - $headers['content-range'] = 'bytes '.($counter * $chunkSize).'-'.min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1).'/'.$size; - if (! empty($id)) { + while (!feof($handle)) { + $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4'); + $headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size; + if (!empty($id)) { $headers['x-appwrite-id'] = $id; } - $largeFile = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucket2['body']['$id'].'/files', array_merge($headers, $this->getHeaders()), [ + $largeFile = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket2['body']['$id'] . '/files', array_merge($headers, $this->getHeaders()), [ 'fileId' => $fileId, 'file' => $curlFile, 'permissions' => [ @@ -123,28 +125,28 @@ trait StorageBase $this->assertEquals('large-file.mp4', $largeFile['body']['name']); $this->assertEquals('video/mp4', $largeFile['body']['mimeType']); $this->assertEquals($totalSize, $largeFile['body']['sizeOriginal']); - $this->assertEquals(md5_file(realpath(__DIR__.'/../../../resources/disk-a/large-file.mp4')), $largeFile['body']['signature']); // should validate that the file is not encrypted + $this->assertEquals(md5_file(realpath(__DIR__ . '/../../../resources/disk-a/large-file.mp4')), $largeFile['body']['signature']); // should validate that the file is not encrypted /** * Failure * Test for Chunk above 5MB */ - $source = __DIR__.'/../../../resources/disk-a/large-file.mp4'; + $source = __DIR__ . "/../../../resources/disk-a/large-file.mp4"; $totalSize = \filesize($source); $chunkSize = 6 * 1024 * 1024; - $handle = @fopen($source, 'rb'); + $handle = @fopen($source, "rb"); $fileId = 'unique()'; $mimeType = mime_content_type($source); $counter = 0; $size = filesize($source); $headers = [ 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ]; $id = ''; - $curlFile = new \CURLFile('data://'.$mimeType.';base64,'.base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4'); - $headers['content-range'] = 'bytes '.($counter * $chunkSize).'-'.min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1).'/'.$size; - $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucket2['body']['$id'].'/files', $this->getHeaders(), [ + $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4'); + $headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size; + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket2['body']['$id'] . '/files', $this->getHeaders(), [ 'fileId' => $fileId, 'file' => $curlFile, 'permissions' => [ @@ -157,15 +159,17 @@ trait StorageBase $this->assertEquals(413, $res['headers']['status-code']); + /** * Test for FAILURE unknown Bucket */ + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/empty/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -177,12 +181,13 @@ trait StorageBase /** * Test for FAILURE file above bucket's file size limit */ - $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/disk-b/kitten-1.png'), 'image/png', 'kitten-1.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/disk-b/kitten-1.png'), 'image/png', 'kitten-1.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -196,12 +201,13 @@ trait StorageBase /** * Test for FAILURE unsupported bucket file extension */ - $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/disk-a/kitten-3.gif'), 'image/gif', 'kitten-3.gif'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/disk-a/kitten-3.gif'), 'image/gif', 'kitten-3.gif'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -224,7 +230,7 @@ trait StorageBase 'name' => 'Test Bucket 2', 'fileSecurity' => true, 'maximumFileSize' => 200000000, //200MB - 'allowedFileExtensions' => ['jpg', 'png'], + 'allowedFileExtensions' => ["jpg", "png"], 'permissions' => [ Permission::read(Role::any()), Permission::create(Role::any()), @@ -238,12 +244,12 @@ trait StorageBase /** * Test for FAILURE set x-appwrite-id to unique() */ - $source = realpath(__DIR__.'/../../../resources/logo.png'); + $source = realpath(__DIR__ . '/../../../resources/logo.png'); $totalSize = \filesize($source); - $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'content-range' => 'bytes 0-'.$size.'/'.$size, + 'content-range' => 'bytes 0-' . $size . '/' . $size, 'x-appwrite-id' => 'unique()', ], $this->getHeaders()), [ 'fileId' => ID::unique(), @@ -272,7 +278,7 @@ trait StorageBase 'name' => 'Test Bucket', 'fileSecurity' => true, 'maximumFileSize' => 2000000, //2MB - 'allowedFileExtensions' => ['jpg', 'png'], + 'allowedFileExtensions' => ["jpg", "png"], 'compression' => 'zstd', 'permissions' => [ Permission::read(Role::any()), @@ -287,12 +293,12 @@ trait StorageBase $bucketId = $bucket['body']['$id']; - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -305,7 +311,7 @@ trait StorageBase $this->assertEquals('logo.png', $file['body']['name']); $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $this->assertTrue(md5_file(realpath(__DIR__.'/../../../resources/logo.png')) == $file['body']['signature']); + $this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) == $file['body']['signature']); return ['bucketId' => $bucketId]; } @@ -318,7 +324,7 @@ trait StorageBase /** * Test for SUCCESS */ - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -326,38 +332,38 @@ trait StorageBase $this->assertGreaterThan(0, $files['body']['total']); $this->assertGreaterThan(0, count($files['body']['files'])); - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(1)'], + 'queries' => [ 'limit(1)' ] ]); $this->assertEquals(200, $files['headers']['status-code']); $this->assertEquals(1, count($files['body']['files'])); - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(1)'], + 'queries' => [ 'offset(1)' ] ]); $this->assertEquals(200, $files['headers']['status-code']); $this->assertEquals(0, count($files['body']['files'])); - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("mimeType", "image/png")'], + 'queries' => [ 'equal("mimeType", "image/png")' ] ]); $this->assertEquals(200, $files['headers']['status-code']); $this->assertEquals(1, count($files['body']['files'])); - $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("mimeType", "image/jpeg")'], + 'queries' => [ 'equal("mimeType", "image/jpeg")' ] ]); $this->assertEquals(200, $files['headers']['status-code']); $this->assertEquals(0, count($files['body']['files'])); @@ -365,6 +371,7 @@ trait StorageBase /** * Test for FAILURE unknown Bucket */ + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/empty/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -383,7 +390,7 @@ trait StorageBase /** * Test for SUCCESS */ - $file1 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'], array_merge([ + $file1 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -397,7 +404,7 @@ trait StorageBase $this->assertIsArray($file1['body']['$permissions']); $this->assertCount(3, $file1['body']['$permissions']); - $file2 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/preview', array_merge([ + $file2 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -407,7 +414,7 @@ trait StorageBase $this->assertNotEmpty($file2['body']); //new image preview features - $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/preview', array_merge([ + $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -425,13 +432,13 @@ trait StorageBase $image = new \Imagick(); $image->readImageBlob($file3['body']); - $original = new \Imagick(__DIR__.'/../../../resources/logo-after.png'); + $original = new \Imagick(__DIR__ . '/../../../resources/logo-after.png'); $this->assertEquals($image->getImageWidth(), $original->getImageWidth()); $this->assertEquals($image->getImageHeight(), $original->getImageHeight()); $this->assertEquals('PNG', $image->getImageFormat()); - $file4 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/preview', array_merge([ + $file4 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -448,13 +455,13 @@ trait StorageBase $image = new \Imagick(); $image->readImageBlob($file4['body']); - $original = new \Imagick(__DIR__.'/../../../resources/logo-after.jpg'); + $original = new \Imagick(__DIR__ . '/../../../resources/logo-after.jpg'); $this->assertEquals($image->getImageWidth(), $original->getImageWidth()); $this->assertEquals($image->getImageHeight(), $original->getImageHeight()); $this->assertEquals('JPEG', $image->getImageFormat()); - $file5 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ + $file5 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -465,13 +472,13 @@ trait StorageBase $this->assertNotEmpty($file5['body']); // Test ranged download - $file51 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ + $file51 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'Range' => 'bytes=0-99', ], $this->getHeaders())); - $path = __DIR__.'/../../../resources/logo.png'; + $path = __DIR__ . '/../../../resources/logo.png'; $originalChunk = \file_get_contents($path, false, null, 0, 100); $this->assertEquals(206, $file51['headers']['status-code']); @@ -481,7 +488,7 @@ trait StorageBase $this->assertEquals($originalChunk, $file51['body']); // Test ranged download - with invalid range - $file52 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ + $file52 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'Range' => 'bytes=0-', @@ -490,7 +497,7 @@ trait StorageBase $this->assertEquals(206, $file52['headers']['status-code']); // Test ranged download - with invalid range - $file53 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ + $file53 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'Range' => 'bytes=988', @@ -499,7 +506,7 @@ trait StorageBase $this->assertEquals(416, $file53['headers']['status-code']); // Test ranged download - with invalid range - $file54 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/download', array_merge([ + $file54 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'Range' => 'bytes=-988', @@ -507,7 +514,7 @@ trait StorageBase $this->assertEquals(416, $file54['headers']['status-code']); - $file6 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/view', array_merge([ + $file6 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -517,7 +524,7 @@ trait StorageBase $this->assertNotEmpty($file6['body']); // Test for negative angle values in fileGetPreview - $file7 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$data['fileId'].'/preview', array_merge([ + $file7 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -535,7 +542,7 @@ trait StorageBase $image = new \Imagick(); $image->readImageBlob($file7['body']); - $original = new \Imagick(__DIR__.'/../../../resources/logo-after.png'); + $original = new \Imagick(__DIR__ . '/../../../resources/logo-after.png'); $this->assertEquals($image->getImageWidth(), $original->getImageWidth()); $this->assertEquals($image->getImageHeight(), $original->getImageHeight()); @@ -544,7 +551,7 @@ trait StorageBase /** * Test large files decompress successfully */ - $file7 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$data['largeBucketId'].'/files/'.$data['largeFileId'].'/download', array_merge([ + $file7 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['largeBucketId'] . '/files/' . $data['largeFileId'] . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -553,16 +560,17 @@ trait StorageBase $this->assertEquals('attachment; filename="large-file.mp4"', $file7['headers']['content-disposition']); $this->assertEquals('video/mp4', $file7['headers']['content-type']); $this->assertNotEmpty($fileData); - $this->assertEquals(md5_file(realpath(__DIR__.'/../../../resources/disk-a/large-file.mp4')), md5($fileData)); // validate the file is downloaded correctly + $this->assertEquals(md5_file(realpath(__DIR__ . '/../../../resources/disk-a/large-file.mp4')), md5($fileData)); // validate the file is downloaded correctly /** * Test for FAILURE unknown Bucket */ - $file8 = $this->client->call(Client::METHOD_GET, '/storage/buckets/empty/files/'.$data['fileId'], array_merge([ + + $file8 = $this->client->call(Client::METHOD_GET, '/storage/buckets/empty/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'limit' => 2, + 'limit' => 2 ]); $this->assertEquals(404, $file8['headers']['status-code']); @@ -577,12 +585,12 @@ trait StorageBase { $bucketId = $data['bucketId']; - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::custom('testcache'), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -595,7 +603,7 @@ trait StorageBase $fileId = $file['body']['$id']; //get image preview - $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -614,7 +622,7 @@ trait StorageBase $imageBefore = new \Imagick(); $imageBefore->readImageBlob($file3['body']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$data['bucketId'].'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $data['bucketId'] . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -623,12 +631,12 @@ trait StorageBase $this->assertEmpty($file['body']); sleep(1); //upload again using the same ID - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::custom('testcache'), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/disk-b/kitten-2.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/disk-b/kitten-2.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -639,7 +647,7 @@ trait StorageBase $this->assertNotEmpty($file['body']['$id']); //get image preview after - $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -670,12 +678,12 @@ trait StorageBase { $bucketId = $data['bucketId']; - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -688,7 +696,7 @@ trait StorageBase $fileId = $file['body']['$id']; //get image preview - $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -715,7 +723,7 @@ trait StorageBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -724,7 +732,7 @@ trait StorageBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); $this->assertEquals(200, $file['headers']['status-code']); @@ -746,7 +754,8 @@ trait StorageBase /** * Test for FAILURE unknown Bucket */ - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/empty/files/'.$data['fileId'], array_merge([ + + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/empty/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -754,7 +763,7 @@ trait StorageBase Permission::read(Role::user($this->getUser()['$id'])), Permission::update(Role::user($this->getUser()['$id'])), Permission::delete(Role::user($this->getUser()['$id'])), - ], + ] ]); $this->assertEquals(404, $file['headers']['status-code']); @@ -770,7 +779,7 @@ trait StorageBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -778,7 +787,7 @@ trait StorageBase $this->assertEquals(204, $file['headers']['status-code']); $this->assertEmpty($file['body']); - $file = $this->client->call(Client::METHOD_GET, '/storage/files/'.$data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/e2e/Services/Storage/StorageConsoleClientTest.php b/tests/e2e/Services/Storage/StorageConsoleClientTest.php index 2d473c5c73..aff055f18d 100644 --- a/tests/e2e/Services/Storage/StorageConsoleClientTest.php +++ b/tests/e2e/Services/Storage/StorageConsoleClientTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Storage; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideConsole; use Utopia\Database\Helpers\ID; @@ -21,9 +21,9 @@ class StorageConsoleClientTest extends Scope */ $response = $this->client->call(Client::METHOD_GET, '/storage/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '32h', + 'range' => '32h' ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -33,9 +33,9 @@ class StorageConsoleClientTest extends Scope */ $response = $this->client->call(Client::METHOD_GET, '/storage/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '24h', + 'range' => '24h' ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -55,7 +55,7 @@ class StorageConsoleClientTest extends Scope ], $this->getHeaders()), [ 'bucketId' => ID::unique(), 'name' => 'Test Bucket', - 'permission' => 'file', + 'permission' => 'file' ]); $this->assertEquals(201, $bucket['headers']['status-code']); $bucketId = $bucket['body']['$id']; @@ -63,11 +63,12 @@ class StorageConsoleClientTest extends Scope /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/storage/'.$bucketId.'/usage', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/storage/' . $bucketId . '/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '32h', + 'range' => '32h' ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -76,9 +77,9 @@ class StorageConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/storage/randomBucketId/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '24h', + 'range' => '24h' ]); $this->assertEquals($response['headers']['status-code'], 404); @@ -86,11 +87,11 @@ class StorageConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/storage/'.$bucketId.'/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/storage/' . $bucketId . '/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ - 'range' => '24h', + 'range' => '24h' ]); $this->assertEquals($response['headers']['status-code'], 200); diff --git a/tests/e2e/Services/Storage/StorageCustomClientTest.php b/tests/e2e/Services/Storage/StorageCustomClientTest.php index f9ca64644a..12fc006968 100644 --- a/tests/e2e/Services/Storage/StorageCustomClientTest.php +++ b/tests/e2e/Services/Storage/StorageCustomClientTest.php @@ -4,9 +4,10 @@ namespace Tests\E2E\Services\Storage; use CURLFile; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -45,13 +46,13 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -62,14 +63,14 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -82,14 +83,14 @@ class StorageCustomClientTest extends Scope $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -100,14 +101,14 @@ class StorageCustomClientTest extends Scope $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -119,34 +120,35 @@ class StorageCustomClientTest extends Scope public function testBucketAnyPermissions(): void { + /** * Test for SUCCESS */ $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'bucketId' => ID::unique(), - 'name' => 'Test Bucket', - 'permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], + 'bucketId' => ID::unique(), + 'name' => 'Test Bucket', + 'permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], ]); $bucketId = $bucket['body']['$id']; $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ - 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -157,46 +159,46 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'name' => 'permissions.png', + 'name' => 'permissions.png', ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(204, $file['headers']['status-code']); @@ -227,12 +229,12 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -243,35 +245,35 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -283,24 +285,24 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -309,7 +311,7 @@ class StorageCustomClientTest extends Scope $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -319,7 +321,7 @@ class StorageCustomClientTest extends Scope /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -352,12 +354,12 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -368,35 +370,35 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals(47218, $file['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -408,22 +410,22 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(401, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); - $this->client->call(CLient::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $this->client->call(CLient::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], [ @@ -434,50 +436,50 @@ class StorageCustomClientTest extends Scope $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals($file['headers']['status-code'], 401); - $email = ID::unique().'@localhost.test'; + $email = ID::unique() . '@localhost.test'; $password = 'password'; $user2 = $this->createUser('user2', $email, $password); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ], [ 'permissions' => [], ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); @@ -485,11 +487,12 @@ class StorageCustomClientTest extends Scope /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); + $this->assertEquals(204, $file['headers']['status-code']); $this->assertEmpty($file['body']); } @@ -498,8 +501,8 @@ class StorageCustomClientTest extends Scope { $team1 = $this->createTeam(ID::unique(), 'Team 1'); $team2 = $this->createTeam(ID::unique(), 'Team 1'); - $user1 = $this->createUser(ID::unique(), ID::unique().'@localhost.test', 'password'); - $user2 = $this->createUser(ID::unique(), ID::unique().'@localhost.test', 'password'); + $user1 = $this->createUser(ID::unique(), ID::unique() . '@localhost.test', 'password'); + $user2 = $this->createUser(ID::unique(), ID::unique() . '@localhost.test', 'password'); $this->addToTeam($user1['$id'], $team1['$id']); $this->addToTeam($user2['$id'], $team2['$id']); @@ -528,13 +531,13 @@ class StorageCustomClientTest extends Scope $this->assertNotEmpty($bucketId); // Team 1 create success - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -546,73 +549,73 @@ class StorageCustomClientTest extends Scope $this->assertEquals(47218, $file['body']['sizeOriginal']); // Team 1 read success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 read success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 preview success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 preview success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 download success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 download success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 view success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 view success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); @@ -622,22 +625,22 @@ class StorageCustomClientTest extends Scope */ // Team 2 create failure - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); // Team 2 update failure - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ], [ 'permissions' => [], ]); @@ -645,10 +648,10 @@ class StorageCustomClientTest extends Scope $this->assertEquals($file['headers']['status-code'], 401); // Team 2 delete failure - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); @@ -657,10 +660,10 @@ class StorageCustomClientTest extends Scope * Test for SUCCESS */ // Team 1 delete success - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(204, $file['headers']['status-code']); @@ -680,20 +683,20 @@ class StorageCustomClientTest extends Scope 'bucketId' => ID::unique(), 'name' => 'Test Bucket', 'permissions' => [], - 'fileSecurity' => true, + 'fileSecurity' => true ]); $bucketId = $bucket['body']['$id']; $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::read(Role::any()), ], @@ -707,28 +710,28 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file1['body']['mimeType']); $this->assertEquals(47218, $file1['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -738,17 +741,17 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals(401, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -769,20 +772,20 @@ class StorageCustomClientTest extends Scope 'bucketId' => ID::unique(), 'name' => 'Test Bucket', 'permissions' => [], - 'fileSecurity' => true, + 'fileSecurity' => true ]); $bucketId = $bucket['body']['$id']; $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::read(Role::users()), ], @@ -796,28 +799,28 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file1['body']['mimeType']); $this->assertEquals(47218, $file1['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -827,17 +830,17 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals(401, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -858,20 +861,20 @@ class StorageCustomClientTest extends Scope 'bucketId' => ID::unique(), 'name' => 'Test Bucket', 'permissions' => [], - 'fileSecurity' => true, + 'fileSecurity' => true ]); $bucketId = $bucket['body']['$id']; $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::read(Role::user($this->getUser()['$id'])), ], @@ -885,28 +888,28 @@ class StorageCustomClientTest extends Scope $this->assertEquals('image/png', $file1['body']['mimeType']); $this->assertEquals(47218, $file1['body']['sizeOriginal']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -916,58 +919,58 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals(401, $file['headers']['status-code']); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(401, $file['headers']['status-code']); - $user2 = $this->createUser(ID::unique(), uniqid().'@localhost.test', 'password'); + $user2 = $this->createUser(ID::unique(), uniqid() . '@localhost.test', 'password'); - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 404); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ], [ 'permissions' => [], ]); $this->assertEquals($file['headers']['status-code'], 401); - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); @@ -977,8 +980,8 @@ class StorageCustomClientTest extends Scope { $team1 = $this->createTeam(ID::unique(), 'Team 1'); $team2 = $this->createTeam(ID::unique(), 'Team 1'); - $user1 = $this->createUser(ID::unique(), ID::unique().'@localhost.test', 'password'); - $user2 = $this->createUser(ID::unique(), ID::unique().'@localhost.test', 'password'); + $user1 = $this->createUser(ID::unique(), ID::unique() . '@localhost.test', 'password'); + $user2 = $this->createUser(ID::unique(), ID::unique() . '@localhost.test', 'password'); $this->addToTeam($user1['$id'], $team1['$id']); $this->addToTeam($user2['$id'], $team2['$id']); @@ -1001,13 +1004,13 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucketId); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::read(Role::team(ID::custom($team1['$id']))), Permission::read(Role::team(ID::custom($team2['$id']))), @@ -1025,73 +1028,73 @@ class StorageCustomClientTest extends Scope $this->assertEquals(47218, $file['body']['sizeOriginal']); // Team 1 read success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 read success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 preview success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 preview success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/preview', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 download success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 2 download success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/download', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 view success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); // Team 1 view success - $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/'.$bucketId.'/files/'.$fileId.'/view', [ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals(200, $file['headers']['status-code']); @@ -1101,32 +1104,32 @@ class StorageCustomClientTest extends Scope */ // Team 1 create failure - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); // Team 2 create failure - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 401); // Team 2 update failure - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ], [ 'permissions' => [], ]); @@ -1134,10 +1137,10 @@ class StorageCustomClientTest extends Scope $this->assertEquals($file['headers']['status-code'], 401); // Team 2 delete failure - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user2['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user2['session'], ]); $this->assertEquals($file['headers']['status-code'], 401); @@ -1146,10 +1149,10 @@ class StorageCustomClientTest extends Scope * Test for SUCCESS */ // Team 1 delete success - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId.'/files/'.$fileId, [ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$user1['session'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $user1['session'], ]); $this->assertEquals(204, $file['headers']['status-code']); @@ -1184,15 +1187,15 @@ class StorageCustomClientTest extends Scope $this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $bucket['body']['$permissions']); // File aliases write to update, delete - $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', array_merge([ + $file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::write(Role::user($this->getUser()['$id'])), - ], + ] ]); $this->assertNotContains(Permission::create(Role::user($this->getUser()['$id'])), $file1['body']['$permissions']); @@ -1204,15 +1207,15 @@ class StorageCustomClientTest extends Scope */ // File does not allow create permission - $file2 = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucketId.'/files', [ + $file2 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'permissions' => [ Permission::create(Role::user($this->getUser()['$id'])), - ], + ] ]); $this->assertEquals(400, $file2['headers']['status-code']); @@ -1241,12 +1244,12 @@ class StorageCustomClientTest extends Scope $this->assertEquals(201, $bucket['headers']['status-code']); $this->assertNotEmpty($bucket['body']['$id']); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$bucket['body']['$id'].'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket['body']['$id'] . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $this->assertEquals($file['headers']['status-code'], 201); @@ -1270,12 +1273,12 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'folderId' => ID::custom('xyz'), 'permissions' => [ Permission::read(Role::user(ID::custom('notme'))), @@ -1286,33 +1289,33 @@ class StorageCustomClientTest extends Scope $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'folderId' => ID::custom('xyz'), 'permissions' => [ Permission::update(Role::user(ID::custom('notme'))), Permission::delete(Role::user(ID::custom('notme'))), - ], + ] ]); $this->assertEquals(401, $file['headers']['status-code']); $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), 'folderId' => ID::custom('xyz'), 'permissions' => [ Permission::read(Role::user(ID::custom('notme'))), @@ -1325,7 +1328,7 @@ class StorageCustomClientTest extends Scope $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); } /** @@ -1336,7 +1339,7 @@ class StorageCustomClientTest extends Scope /** * Test for FAILURE */ - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1349,25 +1352,25 @@ class StorageCustomClientTest extends Scope $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'permissions' => [ Permission::update(Role::user(ID::custom('notme'))), Permission::delete(Role::user(ID::custom('notme'))), - ], + ] ]); $this->assertEquals(401, $file['headers']['status-code']); $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1382,6 +1385,6 @@ class StorageCustomClientTest extends Scope $this->assertStringStartsWith('Permissions must be one of:', $file['body']['message']); $this->assertStringContainsString('any', $file['body']['message']); $this->assertStringContainsString('users', $file['body']['message']); - $this->assertStringContainsString('user:'.$this->getUser()['$id'], $file['body']['message']); + $this->assertStringContainsString('user:' . $this->getUser()['$id'], $file['body']['message']); } } diff --git a/tests/e2e/Services/Storage/StorageCustomServerTest.php b/tests/e2e/Services/Storage/StorageCustomServerTest.php index 2da95f7983..38fb0e0b9d 100644 --- a/tests/e2e/Services/Storage/StorageCustomServerTest.php +++ b/tests/e2e/Services/Storage/StorageCustomServerTest.php @@ -83,8 +83,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets', array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -98,7 +98,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(1)'], + 'queries' => [ 'limit(1)' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -108,7 +108,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(1)'], + 'queries' => [ 'offset(1)' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -118,7 +118,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("$id", "bucket1")'], + 'queries' => [ 'equal("$id", "bucket1")' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -128,7 +128,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("fileSecurity", true)'], + 'queries' => [ 'equal("fileSecurity", true)' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -138,7 +138,7 @@ class StorageCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("'.$response['body']['buckets'][0]['$id'].'")'], + 'queries' => [ 'cursorAfter("' . $response['body']['buckets'][0]['$id'] . '")' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -147,7 +147,6 @@ class StorageCustomServerTest extends Scope $this->assertCount(1, $response['body']['buckets']); $this->assertEquals('bucket1', $response['body']['buckets'][0]['$id']); - return $data; } @@ -162,11 +161,11 @@ class StorageCustomServerTest extends Scope */ $response = $this->client->call( Client::METHOD_GET, - '/storage/buckets/'.$id, + '/storage/buckets/' . $id, array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -179,13 +178,14 @@ class StorageCustomServerTest extends Scope /** * Test for FAILURE */ + $response = $this->client->call( Client::METHOD_GET, '/storage/buckets/empty', array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -197,8 +197,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets/id-is-really-long-id-is-really-long-id-is-really-long-id-is-really-long', array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -217,7 +217,7 @@ class StorageCustomServerTest extends Scope /** * Test for SUCCESS */ - $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$id, array_merge([ + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -239,7 +239,7 @@ class StorageCustomServerTest extends Scope /** * Test for FAILURE */ - $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$id, array_merge([ + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -262,11 +262,11 @@ class StorageCustomServerTest extends Scope */ $response = $this->client->call( Client::METHOD_DELETE, - '/storage/buckets/'.$id, + '/storage/buckets/' . $id, array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -276,11 +276,11 @@ class StorageCustomServerTest extends Scope $response = $this->client->call( Client::METHOD_GET, - '/storage/buckets/'.$id, + '/storage/buckets/' . $id, array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) diff --git a/tests/e2e/Services/Storage/StoragePermissionsScope.php b/tests/e2e/Services/Storage/StoragePermissionsScope.php index e6502cc183..09b35fad36 100644 --- a/tests/e2e/Services/Storage/StoragePermissionsScope.php +++ b/tests/e2e/Services/Storage/StoragePermissionsScope.php @@ -7,7 +7,6 @@ use Tests\E2E\Client; trait StoragePermissionsScope { public array $users = []; - public array $teams = []; public function createUser(string $id, string $email, string $password = 'test123!'): array @@ -19,7 +18,7 @@ trait StoragePermissionsScope ], [ 'userId' => $id, 'email' => $email, - 'password' => $password, + 'password' => $password ]); $this->assertEquals(201, $user['headers']['status-code']); @@ -33,7 +32,8 @@ trait StoragePermissionsScope 'password' => $password, ]); - $session = $this->client->parseCookie((string) $session['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$session['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; + $user = [ '$id' => $user['body']['$id'], @@ -54,7 +54,7 @@ trait StoragePermissionsScope { $team = $this->client->call(Client::METHOD_POST, '/teams', $this->getServerHeader(), [ 'teamId' => $id, - 'name' => $name, + 'name' => $name ]); $this->teams[$id] = $team['body']; @@ -63,16 +63,16 @@ trait StoragePermissionsScope public function addToTeam(string $user, string $team, array $roles = []): array { - $membership = $this->client->call(Client::METHOD_POST, '/teams/'.$team.'/memberships', $this->getServerHeader(), [ + $membership = $this->client->call(Client::METHOD_POST, '/teams/' . $team . '/memberships', $this->getServerHeader(), [ 'teamId' => $team, 'email' => $this->getCreatedUser($user)['email'], 'roles' => $roles, - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); return [ 'user' => $membership['body']['userId'], - 'membership' => $membership['body']['$id'], + 'membership' => $membership['body']['$id'] ]; } @@ -81,7 +81,7 @@ trait StoragePermissionsScope return [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]; } } diff --git a/tests/e2e/Services/Teams/TeamsBase.php b/tests/e2e/Services/Teams/TeamsBase.php index 7b960b3aa5..83b9042f13 100644 --- a/tests/e2e/Services/Teams/TeamsBase.php +++ b/tests/e2e/Services/Teams/TeamsBase.php @@ -3,6 +3,7 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Client; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -41,7 +42,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => $teamId, - 'name' => 'Manchester United', + 'name' => 'Manchester United' ]); $this->assertEquals(201, $response2['headers']['status-code']); @@ -58,7 +59,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Newcastle', + 'name' => 'Newcastle' ]); $this->assertEquals(201, $response3['headers']['status-code']); @@ -84,7 +85,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => $teamId, - 'name' => 'John', + 'name' => 'John' ]); $this->assertEquals(409, $response['headers']['status-code']); @@ -103,7 +104,7 @@ trait TeamsBase /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$id, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -146,7 +147,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(2)'], + 'queries' => [ 'limit(2)' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -156,7 +157,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(1)'], + 'queries' => [ 'offset(1)' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -166,7 +167,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['greaterThanEqual("total", 0)'], + 'queries' => [ 'greaterThanEqual("total", 0)' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -176,7 +177,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("name", ["Arsenal", "Newcastle"])'], + 'queries' => [ 'equal("name", ["Arsenal", "Newcastle"])' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -225,7 +226,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(2)'], + 'queries' => [ 'limit(2)' ], ]); $this->assertEquals(200, $teams['headers']['status-code']); @@ -237,7 +238,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(1)', 'cursorAfter("'.$teams['body']['teams'][0]['$id'].'")'], + 'queries' => [ 'limit(1)', 'cursorAfter("' . $teams['body']['teams'][0]['$id'] . '")' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -250,7 +251,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(1)', 'cursorBefore("'.$teams['body']['teams'][1]['$id'].'")'], + 'queries' => [ 'limit(1)', 'cursorBefore("' . $teams['body']['teams'][1]['$id'] . '")' ], ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -266,7 +267,7 @@ trait TeamsBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("unknown")'], + 'queries' => [ 'cursorAfter("unknown")' ], ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -284,7 +285,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Demo', + 'name' => 'Demo' ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -294,12 +295,12 @@ trait TeamsBase $this->assertIsInt($response['body']['total']); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['$createdAt'])); - $response = $this->client->call(Client::METHOD_PUT, '/teams/'.$response['body']['$id'], array_merge([ + $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()), [ 'teamId' => ID::unique(), - 'name' => 'Demo New', + 'name' => 'Demo New' ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -313,7 +314,7 @@ trait TeamsBase /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PUT, '/teams/'.$response['body']['$id'], array_merge([ + $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()), [ @@ -334,7 +335,7 @@ trait TeamsBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Demo', + 'name' => 'Demo' ]); $teamUid = $response['body']['$id']; @@ -348,7 +349,7 @@ trait TeamsBase $dateValidator = new DatetimeValidator(); $this->assertEquals(true, $dateValidator->isValid($response['body']['$createdAt'])); - $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -359,7 +360,7 @@ trait TeamsBase /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -379,7 +380,7 @@ trait TeamsBase /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$id.'/prefs', array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $id . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -393,7 +394,7 @@ trait TeamsBase $this->assertEquals($team['body']['funcKey1'], 'funcValue1'); $this->assertEquals($team['body']['funcKey2'], 'funcValue2'); - $team = $this->client->call(Client::METHOD_GET, '/teams/'.$id.'/prefs', array_merge([ + $team = $this->client->call(Client::METHOD_GET, '/teams/' . $id . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -404,7 +405,7 @@ trait TeamsBase 'funcKey2' => 'funcValue2', ]); - $team = $this->client->call(Client::METHOD_GET, '/teams/'.$id, array_merge([ + $team = $this->client->call(Client::METHOD_GET, '/teams/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -418,7 +419,7 @@ trait TeamsBase /** * Test for FAILURE */ - $user = $this->client->call(Client::METHOD_PUT, '/teams/'.$id.'/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PUT, '/teams/' . $id . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 4a3a2859dd..7b6b439558 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -3,6 +3,7 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Client; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -19,7 +20,7 @@ trait TeamsBaseClient /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -35,51 +36,51 @@ trait TeamsBaseClient $membershipId = $response['body']['memberships'][0]['$id']; - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(1)'], + 'queries' => [ 'limit(1)' ] ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(1)'], + 'queries' => [ 'offset(1)' ] ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(0, $response['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("confirm", true)'], + 'queries' => [ 'equal("confirm", true)' ] ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(1, $response['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("confirm", false)'], + 'queries' => [ 'equal("confirm", false)' ] ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertCount(0, $response['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => $this->getUser()['$id'], + 'search' => $this->getUser()['$id'] ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -91,11 +92,11 @@ trait TeamsBaseClient $this->assertContains('owner', $response['body']['memberships'][0]['roles']); $this->assertContains('player', $response['body']['memberships'][0]['roles']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => $membershipId, + 'search' => $membershipId ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -107,11 +108,11 @@ trait TeamsBaseClient $this->assertContains('owner', $response['body']['memberships'][0]['roles']); $this->assertContains('player', $response['body']['memberships'][0]['roles']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'unknown', + 'search' => 'unknown' ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -137,7 +138,7 @@ trait TeamsBaseClient /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -156,14 +157,15 @@ trait TeamsBaseClient /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'dasdasd', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid . 'dasdasd', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid, [ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -178,20 +180,20 @@ trait TeamsBaseClient { $teamUid = $data['teamUid'] ?? ''; $teamName = $data['teamName'] ?? ''; - $email = uniqid().'friend@localhost.test'; + $email = uniqid() . 'friend@localhost.test'; $name = 'Friend User'; /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -209,7 +211,7 @@ trait TeamsBaseClient $this->assertEquals($email, $lastEmail['to'][0]['address']); $this->assertEquals($name, $lastEmail['to'][0]['name']); - $this->assertEquals('Invitation to '.$teamName.' Team at '.$this->getProject()['name'], $lastEmail['subject']); + $this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']); $secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256); $membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20); @@ -219,7 +221,7 @@ trait TeamsBaseClient * Test with UserId * Create user */ - $secondEmail = uniqid().'foe@localhost.test'; + $secondEmail = uniqid() . 'foe@localhost.test'; $secondName = 'Another Foe'; $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ 'content-type' => 'application/json', @@ -228,7 +230,7 @@ trait TeamsBaseClient 'userId' => 'unique()', 'email' => $secondEmail, 'password' => 'password', - 'name' => $secondName, + 'name' => $secondName ]); $this->assertEquals(201, $response['headers']['status-code']); $userId = $response['body']['$id']; @@ -237,13 +239,13 @@ trait TeamsBaseClient * Test for UserID * Failure */ - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'userId' => 'abcdefdg', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -252,13 +254,13 @@ trait TeamsBaseClient * Test for UserID * SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'userId' => $userId, 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -276,55 +278,56 @@ trait TeamsBaseClient $this->assertEquals($secondEmail, $lastEmail['to'][0]['address']); $this->assertEquals($secondName, $lastEmail['to'][0]['name']); - $this->assertEquals('Invitation to '.$teamName.' Team at '.$this->getProject()['name'], $lastEmail['subject']); + $this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']); /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(409, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => 'dasdkaskdjaskdjasjkd', 'name' => $name, 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, 'roles' => 'bad string', - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, 'roles' => ['admin', 'editor'], - 'url' => 'http://example.com/join-us#title', // bad url + 'url' => 'http://example.com/join-us#title' // bad url ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -336,7 +339,7 @@ trait TeamsBaseClient 'membershipUid' => $membershipUid, 'userUid' => $userUid, 'email' => $email, - 'name' => $name, + 'name' => $name ]; } @@ -345,7 +348,7 @@ trait TeamsBaseClient */ public function testListTeamMemberships($data): void { - $memberships = $this->client->call(Client::METHOD_GET, '/teams/'.$data['teamUid'].'/memberships', array_merge([ + $memberships = $this->client->call(Client::METHOD_GET, '/teams/' . $data['teamUid'] . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -355,11 +358,11 @@ trait TeamsBaseClient $this->assertNotEmpty($memberships['body']['memberships']); $this->assertCount(3, $memberships['body']['memberships']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$data['teamUid'].'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $data['teamUid'] . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("'.$memberships['body']['memberships'][0]['$id'].'")'], + 'queries' => [ 'cursorAfter("' . $memberships['body']['memberships'][0]['$id'] . '")' ] ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -384,7 +387,7 @@ trait TeamsBaseClient /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -400,18 +403,19 @@ trait TeamsBaseClient $this->assertCount(2, $response['body']['roles']); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['joined'])); $this->assertEquals(true, $response['body']['confirm']); - $session = $this->client->parseCookie((string) $response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $data['session'] = $session; $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals(true, $response['body']['emailVerification']); + /** [START] TESTS TO CHECK PASSWORD UPDATE OF NEW USER CREATED USING TEAM INVITE */ /** * New User tries to update password without old password -> SHOULD PASS @@ -420,9 +424,9 @@ trait TeamsBaseClient 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'password' => 'new-password', + 'password' => 'new-password' ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -440,7 +444,7 @@ trait TeamsBaseClient 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'password' => 'new-password', ]); @@ -453,10 +457,10 @@ trait TeamsBaseClient 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'password' => 'newer-password', - 'oldPassword' => 'new-password', + 'oldPassword' => 'new-password' ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -472,7 +476,7 @@ trait TeamsBaseClient /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -483,7 +487,7 @@ trait TeamsBaseClient $this->assertEquals(401, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -494,7 +498,7 @@ trait TeamsBaseClient $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -505,7 +509,7 @@ trait TeamsBaseClient $this->assertEquals(401, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -516,7 +520,7 @@ trait TeamsBaseClient $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -527,7 +531,7 @@ trait TeamsBaseClient $this->assertEquals(401, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -554,12 +558,12 @@ trait TeamsBaseClient * Test for SUCCESS */ $roles = ['admin', 'editor', 'uncle']; - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid, array_merge([ + $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, + 'roles' => $roles ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -574,12 +578,12 @@ trait TeamsBaseClient /** * Test for unknown team */ - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.'abc'.'/memberships/'.$membershipUid, array_merge([ + $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, + 'roles' => $roles ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -587,26 +591,27 @@ trait TeamsBaseClient /** * Test for unknown membership ID */ - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.'abc', array_merge([ + $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, + '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, [ + $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, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ], [ - 'roles' => $roles, + 'roles' => $roles ]); $this->assertEquals(401, $response['headers']['status-code']); @@ -615,7 +620,7 @@ trait TeamsBaseClient return $data; } - /** + /** * @depends testUpdateTeamMembershipRoles */ public function testDeleteTeamMembership($data): array @@ -624,7 +629,7 @@ trait TeamsBaseClient $membershipUid = $data['membershipUid'] ?? ''; $session = $data['session'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -641,11 +646,11 @@ trait TeamsBaseClient /** * Test deleting a membership that does not exists */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/dne', [ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/dne', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -653,11 +658,11 @@ trait TeamsBaseClient /** * Test deleting another user's membership */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, [ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]); $this->assertEquals(401, $response['headers']['status-code']); @@ -669,17 +674,17 @@ trait TeamsBaseClient /** * Test for when a user other than the owner tries to delete their membership */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$membershipUid, [ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]); $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -690,7 +695,7 @@ trait TeamsBaseClient /** * Test for when the owner tries to delete their membership */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -699,7 +704,7 @@ trait TeamsBaseClient $this->assertEquals(204, $response['headers']['status-code']); $this->assertEmpty($response['body']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Teams/TeamsBaseServer.php b/tests/e2e/Services/Teams/TeamsBaseServer.php index 642078d72b..7bb6241c4a 100644 --- a/tests/e2e/Services/Teams/TeamsBaseServer.php +++ b/tests/e2e/Services/Teams/TeamsBaseServer.php @@ -17,7 +17,7 @@ trait TeamsBaseServer /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$id.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $id . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -43,7 +43,7 @@ trait TeamsBaseServer /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -62,14 +62,15 @@ trait TeamsBaseServer /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'dasdasd', array_merge([ + + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid . 'dasdasd', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(404, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid, [ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]); @@ -84,19 +85,19 @@ trait TeamsBaseServer { $teamUid = $data['teamUid'] ?? ''; $teamName = $data['teamName'] ?? ''; - $email = uniqid().'friend@localhost.test'; + $email = uniqid() . 'friend@localhost.test'; /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -125,50 +126,51 @@ trait TeamsBaseServer /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(409, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => 'dasdkaskdjaskdjasjkd', 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => 'bad string', - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(400, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://example.com/join-us#title', // bad url + 'url' => 'http://example.com/join-us#title' // bad url ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -176,7 +178,7 @@ trait TeamsBaseServer return [ 'teamUid' => $teamUid, 'userUid' => $userUid, - 'membershipUid' => $membershipUid, + 'membershipUid' => $membershipUid ]; } @@ -192,12 +194,12 @@ trait TeamsBaseServer * Test for SUCCESS */ $roles = ['admin', 'editor', 'uncle']; - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid, array_merge([ + $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, + 'roles' => $roles ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -209,18 +211,19 @@ trait TeamsBaseServer $this->assertEquals($roles[1], $response['body']['roles'][1]); $this->assertEquals($roles[2], $response['body']['roles'][2]); + /** * Test for FAILURE */ $apiKey = $this->getNewKey(['teams.read']); $roles = ['admin', 'editor', 'uncle']; - $response = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid, [ + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $apiKey, + 'x-appwrite-key' => $apiKey ], [ - 'roles' => $roles, + 'roles' => $roles ]); $this->assertEquals(401, $response['headers']['status-code']); @@ -237,7 +240,7 @@ trait TeamsBaseServer $userUid = $data['userUid'] ?? ''; /** Get Team Count */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -250,7 +253,7 @@ trait TeamsBaseServer $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['$createdAt'])); /** Delete User */ - $user = $this->client->call(Client::METHOD_DELETE, '/users/'.$userUid, array_merge([ + $user = $this->client->call(Client::METHOD_DELETE, '/users/' . $userUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -261,11 +264,12 @@ trait TeamsBaseServer sleep(5); /** Get Team Count */ - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); $this->assertEquals('Arsenal', $response['body']['name']); diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index 7c5a667bbc..e86c18a8e2 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; @@ -22,10 +22,10 @@ class TeamsConsoleClientTest extends Scope */ $response = $this->client->call(Client::METHOD_POST, '/teams', \array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => 'console', + 'x-appwrite-project' => 'console' ], $this->getHeaders()), [ 'name' => 'Latest version Team', - 'teamId' => ID::unique(), + 'teamId' => ID::unique() ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -37,9 +37,9 @@ class TeamsConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/teams', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', - 'x-appwrite-response-format' => '0.11.0', + 'x-appwrite-response-format' => '0.11.0' ], $this->getHeaders()), [ - 'name' => 'Latest version Team', + 'name' => 'Latest version Team' // Notice "teamId' is not defined ]); @@ -49,14 +49,14 @@ class TeamsConsoleClientTest extends Scope /** * Cleanup, so I don't invalidate some listTeams requests by mistake */ - $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$team1Id, \array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $team1Id, \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$team2Id, \array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $team2Id, \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => 'console', ], $this->getHeaders())); @@ -71,18 +71,18 @@ class TeamsConsoleClientTest extends Scope { $teamUid = $data['teamUid'] ?? ''; $teamName = $data['teamName'] ?? ''; - $email = uniqid().'friend@localhost.test'; + $email = uniqid() . 'friend@localhost.test'; $name = 'Friend User'; $password = 'password'; // 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, + 'x-appwrite-project' => 'console'], [ + 'userId' => 'unique()', + 'email' => $email, + 'password' => $password, + 'name' => $name, ], false); $this->assertEquals(201, $user['headers']['status-code']); @@ -90,14 +90,14 @@ class TeamsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => $name, 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -108,7 +108,7 @@ class TeamsConsoleClientTest extends Scope ], $this->getHeaders())); $this->assertEquals(401, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -117,7 +117,7 @@ class TeamsConsoleClientTest extends Scope $ownerMembershipUid = $response['body']['memberships'][1]['$id']; - $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Teams/TeamsCustomClientTest.php b/tests/e2e/Services/Teams/TeamsCustomClientTest.php index 83a8080d1d..3b46cbcb7f 100644 --- a/tests/e2e/Services/Teams/TeamsCustomClientTest.php +++ b/tests/e2e/Services/Teams/TeamsCustomClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Teams; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; class TeamsCustomClientTest extends Scope diff --git a/tests/e2e/Services/Teams/TeamsCustomServerTest.php b/tests/e2e/Services/Teams/TeamsCustomServerTest.php index 325b5892fc..ccbb598934 100644 --- a/tests/e2e/Services/Teams/TeamsCustomServerTest.php +++ b/tests/e2e/Services/Teams/TeamsCustomServerTest.php @@ -5,6 +5,7 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; +use Tests\E2E\Client; class TeamsCustomServerTest extends Scope { diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index 5842212e07..baf601789a 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -107,7 +107,7 @@ trait UsersBase 'email' => 'sha512@appwrite.io', 'password' => '4243da0a694e8a2f727c8060fe0507c8fa01ca68146c76d2c190805b638c20c6bf6ba04e21f11ae138785d0bff63c416e6f87badbffad37f6dee50094cc38c70', // appwrite (sha512) 'name' => 'SHA512 User', - 'passwordVersion' => 'sha512', + 'passwordVersion' => 'sha512' ]); $this->assertEquals($res['headers']['status-code'], 201); @@ -127,7 +127,7 @@ trait UsersBase 'passwordCpu' => 16384, 'passwordMemory' => 13, 'passwordParallel' => 2, - 'passwordLength' => 64, + 'passwordLength' => 64 ]); $this->assertEquals($res['headers']['status-code'], 201); @@ -191,7 +191,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]), [ - 'email' => $userId.'@appwrite.io', + 'email' => $userId . '@appwrite.io', 'password' => 'appwrite', ]); @@ -201,14 +201,14 @@ trait UsersBase foreach ($userIds as $userId) { // Ensure all passwords were re-hashed - $response = $this->client->call(Client::METHOD_GET, '/users/'.$userId, array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/' . $userId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($userId, $response['body']['$id']); - $this->assertEquals($userId.'@appwrite.io', $response['body']['email']); + $this->assertEquals($userId . '@appwrite.io', $response['body']['email']); $this->assertEquals('argon2', $response['body']['hash']); $this->assertStringStartsWith('$argon2', $response['body']['password']); } @@ -220,7 +220,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ]), [ - 'email' => $userId.'@appwrite.io', + 'email' => $userId . '@appwrite.io', 'password' => 'appwrite', ]); @@ -349,7 +349,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("name", "'.$user1['name'].'")'], + 'queries' => ['equal("name", "' . $user1['name'] . '")'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -362,7 +362,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("email", "'.$user1['email'].'")'], + 'queries' => ['equal("email", "' . $user1['email'] . '")'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -375,7 +375,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("status", true)'], + 'queries' => ['equal("status", true)'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -391,7 +391,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("status", false)'], + 'queries' => ['equal("status", false)'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -403,7 +403,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("passwordUpdate", "'.$user1['passwordUpdate'].'")'], + 'queries' => ['equal("passwordUpdate", "' . $user1['passwordUpdate'] . '")'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -416,7 +416,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("registration", "'.$user1['registration'].'")'], + 'queries' => ['equal("registration", "' . $user1['registration'] . '")'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -429,7 +429,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("emailVerification", false)'], + 'queries' => ['equal("emailVerification", false)'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -445,7 +445,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("emailVerification", true)'], + 'queries' => ['equal("emailVerification", true)'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -457,7 +457,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("phoneVerification", false)'], + 'queries' => ['equal("phoneVerification", false)'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -469,7 +469,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("phoneVerification", true)'], + 'queries' => ['equal("phoneVerification", true)'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -481,7 +481,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("'.$data['userId'].'")'], + 'queries' => ['cursorAfter("' . $data['userId'] . '")'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -494,7 +494,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorBefore("user1")'], + 'queries' => ['cursorBefore("user1")'] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -510,7 +510,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'Ronaldo', + 'search' => "Ronaldo", ]); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']); @@ -522,7 +522,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'cristiano.ronaldo@manchester-united.co.uk', + 'search' => "cristiano.ronaldo@manchester-united.co.uk", ]); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']); @@ -534,7 +534,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'cristiano.ronaldo', + 'search' => "cristiano.ronaldo", ]); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']); @@ -546,7 +546,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'manchester', + 'search' => "manchester", ]); $this->assertEquals($response['headers']['status-code'], 200); $this->assertNotEmpty($response['body']); @@ -558,7 +558,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'united.co.uk', + 'search' => "united.co.uk", ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -572,7 +572,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'search' => 'man', + 'search' => "man", ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -602,7 +602,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAfter("unknown")'], + 'queries' => ['cursorAfter("unknown")'] ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -616,7 +616,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -627,7 +627,7 @@ trait UsersBase $this->assertEquals($user['body']['status'], true); $this->assertGreaterThan('2000-01-01 00:00:00', $user['body']['registration']); - $sessions = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/sessions', array_merge([ + $sessions = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/sessions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -670,7 +670,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/name', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/name', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -680,7 +680,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['name'], 'Updated name'); - $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -737,7 +737,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/email', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/email', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -747,7 +747,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['email'], 'users.service@updated.com'); - $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -804,7 +804,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/password', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/password', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -819,7 +819,7 @@ trait UsersBase 'x-appwrite-project' => $this->getProject()['$id'], ], [ 'email' => 'users.service@updated.com', - 'password' => 'password2', + 'password' => 'password2' ]); $this->assertEquals($session['headers']['status-code'], 201); @@ -836,7 +836,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/status', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/status', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -846,7 +846,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['status'], false); - $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -865,7 +865,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/verification', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/verification', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -875,7 +875,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['emailVerification'], true); - $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -895,7 +895,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -909,7 +909,7 @@ trait UsersBase $this->assertEquals($user['body']['funcKey1'], 'funcValue1'); $this->assertEquals($user['body']['funcKey2'], 'funcValue2'); - $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -923,7 +923,7 @@ trait UsersBase /** * Test for FAILURE */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -932,7 +932,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 400); - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -950,8 +950,8 @@ trait UsersBase /** * Test for SUCCESS */ - $updatedNumber = '+910000000000'; //dummy number - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/phone', array_merge([ + $updatedNumber = "+910000000000"; //dummy number + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/phone', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -961,7 +961,7 @@ trait UsersBase $this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['body']['phone'], $updatedNumber); - $user = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -972,12 +972,13 @@ trait UsersBase /** * Test for FAILURE */ - $errorType = 'user_phone_already_exists'; - $user1Id = 'user1'; + + $errorType = "user_phone_already_exists"; + $user1Id = "user1"; $statusCodeForUserPhoneAlredyExists = 409; // adding same number ($updatedNumber) to different user i.e user1 - $response = $this->client->call(Client::METHOD_PATCH, '/users/'.$user1Id.'/phone', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $user1Id . '/phone', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -996,7 +997,7 @@ trait UsersBase public function testUpdateUserNumberSearch($data): void { $id = $data['userId'] ?? ''; - $newNumber = '+910000000000'; //dummy number + $newNumber = "+910000000000"; //dummy number /** * Test for SUCCESS @@ -1066,7 +1067,7 @@ trait UsersBase */ public function testUpdateUserLabels(array $labels, int $expectedStatus, array $expectedLabels, array $data): array { - $user = $this->client->call(Client::METHOD_PUT, '/users/'.$data['userId'].'/labels', array_merge([ + $user = $this->client->call(Client::METHOD_PUT, '/users/' . $data['userId'] . '/labels', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1086,7 +1087,7 @@ trait UsersBase */ public function testUpdateUserLabelsWithoutLabels(array $data): array { - $user = $this->client->call(Client::METHOD_PUT, '/users/'.$data['userId'].'/labels', array_merge([ + $user = $this->client->call(Client::METHOD_PUT, '/users/' . $data['userId'] . '/labels', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -1108,6 +1109,7 @@ trait UsersBase $this->assertEquals(Response::STATUS_CODE_NOT_FOUND, $user['headers']['status-code']); } + /** * @depends testGetUser */ @@ -1116,7 +1118,7 @@ trait UsersBase /** * Test for SUCCESS */ - $logs = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1125,7 +1127,7 @@ trait UsersBase $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1137,7 +1139,7 @@ trait UsersBase $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1148,7 +1150,7 @@ trait UsersBase $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); - $logs = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ + $logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1163,47 +1165,47 @@ trait UsersBase /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['limit(-1)'], + 'queries' => ['limit(-1)'] ]); $this->assertEquals($response['headers']['status-code'], 400); - $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['offset(-1)'], + 'queries' => ['offset(-1)'] ]); $this->assertEquals($response['headers']['status-code'], 400); - $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['equal("$id", "asdf")'], + 'queries' => ['equal("$id", "asdf")'] ]); $this->assertEquals($response['headers']['status-code'], 400); - $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['orderAsc("$id")'], + 'queries' => ['orderAsc("$id")'] ]); $this->assertEquals($response['headers']['status-code'], 400); - $response = $this->client->call(Client::METHOD_GET, '/users/'.$data['userId'].'/logs', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['cursorAsc("$id")'], + 'queries' => ['cursorAsc("$id")'] ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -1217,7 +1219,7 @@ trait UsersBase /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_DELETE, '/users/'.$data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -1227,7 +1229,7 @@ trait UsersBase /** * Test for FAILURE */ - $user = $this->client->call(Client::METHOD_DELETE, '/users/'.$data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/e2e/Services/Users/UsersConsoleClientTest.php b/tests/e2e/Services/Users/UsersConsoleClientTest.php index cc44520387..8943bfab63 100644 --- a/tests/e2e/Services/Users/UsersConsoleClientTest.php +++ b/tests/e2e/Services/Users/UsersConsoleClientTest.php @@ -2,9 +2,9 @@ namespace Tests\E2E\Services\Users; -use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Client; use Tests\E2E\Scopes\SideConsole; class UsersConsoleClientTest extends Scope @@ -17,9 +17,10 @@ class UsersConsoleClientTest extends Scope /** * Test for FAILURE */ + $response = $this->client->call(Client::METHOD_GET, '/users/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ 'range' => '32h', ]); @@ -31,7 +32,7 @@ class UsersConsoleClientTest extends Scope */ $response = $this->client->call(Client::METHOD_GET, '/users/usage', array_merge([ 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ 'range' => '24h', ]); diff --git a/tests/e2e/Services/Users/UsersCustomServerTest.php b/tests/e2e/Services/Users/UsersCustomServerTest.php index 2442f1bf7d..6b9a990d4c 100644 --- a/tests/e2e/Services/Users/UsersCustomServerTest.php +++ b/tests/e2e/Services/Users/UsersCustomServerTest.php @@ -2,6 +2,7 @@ namespace Tests\E2E\Services\Users; +use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; diff --git a/tests/e2e/Services/Webhooks/WebhooksBase.php b/tests/e2e/Services/Webhooks/WebhooksBase.php index 663167e38b..6e30e7abc1 100644 --- a/tests/e2e/Services/Webhooks/WebhooksBase.php +++ b/tests/e2e/Services/Webhooks/WebhooksBase.php @@ -5,6 +5,7 @@ namespace Tests\E2E\Services\Webhooks; use Appwrite\Tests\Retry; use CURLFile; use Tests\E2E\Client; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -15,34 +16,34 @@ trait WebhooksBase public static function getWebhookSignature(array $webhook, string $signatureKey): string { $payload = json_encode($webhook['data']); - $url = $webhook['url']; - - return base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + return base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); } + public function testCreateCollection(): array { /** * Create database */ $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'databaseId' => ID::unique(), - 'name' => 'Actors DB', + 'databaseId' => ID::unique(), + 'name' => 'Actors DB', ]); $databaseId = $database['body']['$id']; - /** + /** * Test for SUCCESS */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Actors', @@ -66,8 +67,8 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); @@ -90,30 +91,30 @@ trait WebhooksBase $actorsId = $data['actorsId']; $databaseId = $data['databaseId']; - $firstName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ + $firstName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'firstName', 'size' => 256, 'required' => true, ]); - $lastName = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ + $lastName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'lastName', 'size' => 256, 'required' => true, ]); - $extra = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/attributes/string', array_merge([ + $extra = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'extra', 'size' => 64, @@ -138,9 +139,9 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.attributes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -150,10 +151,10 @@ trait WebhooksBase $this->assertNotEmpty($webhook['data']['key']); $this->assertEquals($webhook['data']['key'], 'extra'); - $removed = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['actorsId'].'/attributes/'.$extra['body']['key'], array_merge([ + $removed = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/attributes/' . $extra['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals(204, $removed['headers']['status-code']); @@ -164,9 +165,9 @@ trait WebhooksBase // $this->assertEquals($webhook['method'], 'DELETE'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.attributes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -190,7 +191,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -217,9 +218,9 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -253,7 +254,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $document = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$data['documentId'], array_merge([ + $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $data['documentId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -279,9 +280,9 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -314,7 +315,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $document = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents', array_merge([ + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -336,7 +337,7 @@ trait WebhooksBase $this->assertEquals($document['headers']['status-code'], 201); $this->assertNotEmpty($document['body']['$id']); - $document = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actorsId.'/documents/'.$document['body']['$id'], array_merge([ + $document = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $document['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -349,9 +350,9 @@ trait WebhooksBase $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.documents.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.documents.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.*.documents.{$documentId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -372,6 +373,7 @@ trait WebhooksBase return $data; } + public function testCreateStorageBucket(): array { /** @@ -380,7 +382,7 @@ trait WebhooksBase $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'bucketId' => ID::unique(), 'name' => 'Test Bucket', @@ -429,10 +431,10 @@ trait WebhooksBase /** * Test for SUCCESS */ - $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'], array_merge([ + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Test Bucket Updated', 'fileSecurity' => true, @@ -472,10 +474,10 @@ trait WebhooksBase $bucketId = $data['bucketId']; //enable bucket - $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$data['bucketId'], array_merge([ + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Test Bucket Updated', 'fileSecurity' => true, @@ -486,12 +488,12 @@ trait WebhooksBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'.$data['bucketId'].'/files', array_merge([ + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([ 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__.'/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), 'permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), @@ -549,7 +551,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/'.$bucketId.'/files/'.$fileId, array_merge([ + $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -605,7 +607,7 @@ trait WebhooksBase /** * Test for SUCCESS */ - $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$data['bucketId'].'/files/'.$data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -653,10 +655,10 @@ trait WebhooksBase /** * Test for SUCCESS */ - $bucket = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/'.$bucketId, array_merge([ + $bucket = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $this->assertEquals($bucket['headers']['status-code'], 204); @@ -692,7 +694,7 @@ trait WebhooksBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Arsenal', + 'name' => 'Arsenal' ]); $teamId = $team['body']['$id']; @@ -735,11 +737,11 @@ trait WebhooksBase /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$teamId, array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'name' => 'Demo New', + 'name' => 'Demo New' ]); $this->assertEquals(200, $team['headers']['status-code']); @@ -778,14 +780,14 @@ trait WebhooksBase { $id = $data['teamId'] ?? ''; - $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$id.'/prefs', array_merge([ + $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $id . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'prefs' => [ 'prefKey1' => 'prefValue1', 'prefKey2' => 'prefValue2', - ], + ] ]); $this->assertEquals($team['headers']['status-code'], 200); @@ -794,8 +796,8 @@ trait WebhooksBase $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -828,7 +830,7 @@ trait WebhooksBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'teamId' => ID::unique(), - 'name' => 'Chelsea', + 'name' => 'Chelsea' ]); $teamId = $team['body']['$id']; @@ -836,7 +838,7 @@ trait WebhooksBase $this->assertEquals(201, $team['headers']['status-code']); $this->assertNotEmpty($team['body']['$id']); - $team = $this->client->call(Client::METHOD_DELETE, '/teams/'.$team['body']['$id'], array_merge([ + $team = $this->client->call(Client::METHOD_DELETE, '/teams/' . $team['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -873,19 +875,19 @@ trait WebhooksBase public function testCreateTeamMembership($data): array { $teamId = $data['teamId'] ?? ''; - $email = uniqid().'friend@localhost.test'; + $email = uniqid() . 'friend@localhost.test'; /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_POST, '/teams/'.$teamId.'/memberships', array_merge([ + $team = $this->client->call(Client::METHOD_POST, '/teams/' . $teamId . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $this->assertEquals(201, $team['headers']['status-code']); @@ -940,19 +942,19 @@ trait WebhooksBase public function testDeleteTeamMembership($data): void { $teamId = $data['teamId'] ?? ''; - $email = uniqid().'friend@localhost.test'; + $email = uniqid() . 'friend@localhost.test'; /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_POST, '/teams/'.$teamId.'/memberships', array_merge([ + $team = $this->client->call(Client::METHOD_POST, '/teams/' . $teamId . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'email' => $email, 'name' => 'Friend User', 'roles' => ['admin', 'editor'], - 'url' => 'http://localhost:5000/join-us#title', + 'url' => 'http://localhost:5000/join-us#title' ]); $membershipId = $team['body']['$id'] ?? ''; @@ -960,7 +962,7 @@ trait WebhooksBase $this->assertEquals(201, $team['headers']['status-code']); $this->assertNotEmpty($team['body']['$id']); - $team = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamId.'/memberships/'.$team['body']['$id'], array_merge([ + $team = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamId . '/memberships/' . $team['body']['$id'], array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php index 48f33a24e5..67c2dec36b 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php @@ -4,9 +4,10 @@ namespace Tests\E2E\Services\Webhooks; use Appwrite\Tests\Retry; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -18,7 +19,7 @@ class WebhooksCustomClientTest extends Scope public function testCreateAccount(): array { - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -44,8 +45,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -76,7 +77,7 @@ class WebhooksCustomClientTest extends Scope public function testDeleteAccount(): array { - $email = uniqid().'user1@localhost.test'; + $email = uniqid() . 'user1@localhost.test'; $password = 'password'; $name = 'User Name 1'; @@ -106,13 +107,13 @@ class WebhooksCustomClientTest extends Scope $this->assertEquals($accountSession['headers']['status-code'], 201); $id = $account['body']['$id']; - $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $account = $this->client->call(Client::METHOD_PATCH, '/account/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($account['headers']['status-code'], 200); @@ -120,8 +121,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -169,13 +170,13 @@ class WebhooksCustomClientTest extends Scope $this->assertEquals($accountSession['headers']['status-code'], 201); $sessionId = $accountSession['body']['$id']; - $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -247,15 +248,15 @@ class WebhooksCustomClientTest extends Scope ]); $sessionId = $accountSession['body']['$id']; - $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $this->assertEquals($accountSession['headers']['status-code'], 201); - $accountSession = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionId, array_merge([ + $accountSession = $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionId, array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($accountSession['headers']['status-code'], 204); @@ -263,8 +264,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -333,7 +334,7 @@ class WebhooksCustomClientTest extends Scope ]); $sessionId = $accountSession['body']['$id']; - $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; $this->assertEquals($accountSession['headers']['status-code'], 201); @@ -341,7 +342,7 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); $this->assertEquals($accountSession['headers']['status-code'], 204); @@ -349,8 +350,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -406,7 +407,7 @@ class WebhooksCustomClientTest extends Scope $this->assertEquals($accountSession['headers']['status-code'], 201); $sessionId = $accountSession['body']['$id']; - $session = $this->client->parseCookie((string) $accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']]; return array_merge($data, [ 'sessionId' => $sessionId, @@ -429,9 +430,9 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ - 'name' => $newName, + 'name' => $newName ]); $this->assertEquals($account['headers']['status-code'], 200); @@ -440,8 +441,9 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); + $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -481,7 +483,7 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'password' => 'new-password', 'oldPassword' => $password, @@ -493,8 +495,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -529,14 +531,14 @@ class WebhooksCustomClientTest extends Scope { $id = $data['id'] ?? ''; $email = $data['email'] ?? ''; - $newEmail = uniqid().'new@localhost.test'; + $newEmail = uniqid() . 'new@localhost.test'; $session = $data['session'] ?? ''; $account = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'email' => $newEmail, 'password' => 'new-password', @@ -548,8 +550,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -590,12 +592,12 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'prefs' => [ 'prefKey1' => 'prefValue1', 'prefKey2' => 'prefValue2', - ], + ] ]); $this->assertEquals($account['headers']['status-code'], 200); @@ -604,8 +606,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -659,8 +661,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -719,8 +721,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -762,7 +764,7 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'url' => 'http://localhost/verification', ]); @@ -775,8 +777,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -819,7 +821,7 @@ class WebhooksCustomClientTest extends Scope 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session, + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]), [ 'userId' => $id, 'secret' => $secret, @@ -833,8 +835,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); @@ -876,7 +878,7 @@ class WebhooksCustomClientTest extends Scope /** * Test for SUCCESS */ - $team = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([ + $team = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -891,8 +893,8 @@ class WebhooksCustomClientTest extends Scope $webhook = $this->getLastRequest(); $signatureKey = $this->getProject()['signatureKey']; $payload = json_encode($webhook['data']); - $url = $webhook['url']; - $signatureExpected = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true)); + $url = $webhook['url']; + $signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true)); $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index 836c81822b..02c3a2dbfd 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -8,6 +8,7 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; use Utopia\CLI\Console; +use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -30,10 +31,10 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $actors = $this->client->call(Client::METHOD_PUT, '/databases/'.$databaseId.'/collections/'.$id, array_merge([ + $actors = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'name' => 'Actors1', 'documentSecurity' => true, @@ -48,8 +49,8 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); @@ -72,10 +73,10 @@ class WebhooksCustomServerTest extends Scope $actorsId = $data['actorsId']; $databaseId = $data['databaseId']; - $index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$data['actorsId'].'/indexes', array_merge([ + $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/indexes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'key' => 'fullname', 'type' => 'key', @@ -96,9 +97,9 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -108,10 +109,10 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true); // Remove index - $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$data['actorsId'].'/indexes/'.$index['body']['key'], array_merge([ + $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/indexes/' . $index['body']['key'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ])); // // wait for database worker to remove index @@ -121,9 +122,9 @@ class WebhooksCustomServerTest extends Scope // $this->assertEquals($webhook['method'], 'DELETE'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.indexes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); @@ -143,7 +144,7 @@ class WebhooksCustomServerTest extends Scope $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ], $this->getHeaders()), [ 'databaseId' => ID::unique(), 'name' => 'Actors DB', @@ -154,10 +155,10 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $actors = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections', array_merge([ + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'collectionId' => ID::unique(), 'name' => 'Demo', @@ -175,10 +176,10 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($actors['headers']['status-code'], 201); $this->assertNotEmpty($actors['body']['$id']); - $actors = $this->client->call(Client::METHOD_DELETE, '/databases/'.$databaseId.'/collections/'.$actors['body']['$id'], array_merge([ + $actors = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), []); $this->assertEquals($actors['headers']['status-code'], 204); @@ -189,8 +190,8 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString('databases.'.$databaseId.'.collections.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); + $this->assertStringContainsString('databases.' . $databaseId . '.collections.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("databases.{$databaseId}.collections.{$id}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); @@ -207,7 +208,7 @@ class WebhooksCustomServerTest extends Scope public function testCreateUser(): array { - $email = uniqid().'user@localhost.test'; + $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; @@ -267,11 +268,11 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$id.'/prefs', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $id . '/prefs', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'prefs' => ['a' => 'b'], + 'prefs' => ['a' => 'b'] ]); $this->assertEquals($user['headers']['status-code'], 200); @@ -308,7 +309,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_PATCH, '/users/'.$data['userId'].'/status', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/status', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -355,7 +356,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $user = $this->client->call(Client::METHOD_DELETE, '/users/'.$data['userId'], array_merge([ + $user = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -441,7 +442,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $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()), [ @@ -450,14 +451,14 @@ class WebhooksCustomServerTest extends Scope 'execute' => [Role::any()->toString()], 'vars' => [ 'key1' => 'value1', - ], + ] ]); $this->assertEquals($function['headers']['status-code'], 200); $this->assertEquals($function['body']['$id'], $data['functionId']); // Create variable - $variable = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/variables', array_merge([ + $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -495,16 +496,16 @@ class WebhooksCustomServerTest extends Scope $stderr = ''; $stdout = ''; $folder = 'timeout'; - $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); + $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/'.$data['functionId'].'/deployments', array_merge([ + $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()), [ 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), - 'activate' => true, + 'activate' => true ]); $id = $data['functionId'] ?? ''; @@ -545,7 +546,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_PATCH, '/functions/'.$id.'/deployments/'.$deploymentId, array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $id . '/deployments/' . $deploymentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), []); @@ -593,11 +594,11 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$id.'/executions', array_merge([ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $id . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'async' => true, + 'async' => true ]); $executionId = $execution['body']['$id'] ?? ''; @@ -664,7 +665,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $deployment = $this->client->call(Client::METHOD_DELETE, '/functions/'.$id.'/deployments/'.$deploymentId, array_merge([ + $deployment = $this->client->call(Client::METHOD_DELETE, '/functions/' . $id . '/deployments/' . $deploymentId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -709,7 +710,7 @@ class WebhooksCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_DELETE, '/functions/'.$id, array_merge([ + $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $id, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/extensions/Retryable.php b/tests/extensions/Retryable.php index aa85d22eae..61fec0ef12 100644 --- a/tests/extensions/Retryable.php +++ b/tests/extensions/Retryable.php @@ -14,7 +14,6 @@ trait Retryable * accounting for any retries configured by the {@see Retry} annotation. * * @return void - * * @throws \ReflectionException * @throws \Throwable */ @@ -22,15 +21,14 @@ trait Retryable { $retries = $this->getNumberOfRetries(); $ex = null; - for ($i = 0; $i <= $retries; $i++) { + for ($i = 0; $i <= $retries; ++$i) { try { parent::runBare(); - return; - } catch (\Throwable|\Exception $ex) { + } catch (\Throwable | \Exception $ex) { // Swallow the exception until we have exhausted our retries. if ($i !== $retries) { - echo 'Flaky test failed, retrying...'.PHP_EOL; + echo 'Flaky test failed, retrying...' . PHP_EOL; } } } @@ -41,7 +39,6 @@ trait Retryable /** * @return int - * * @throws \ReflectionException */ private function getNumberOfRetries(): int @@ -56,12 +53,11 @@ trait Retryable $attribute = $attributes[0] ?? null; $args = $attribute?->getArguments(); $retries = $args['count'] ?? 0; - return \max(0, $retries); } /** - * @param \ReflectionClass $reflection + * @param \ReflectionClass $reflection * @return \ReflectionClass */ private function getTestCaseRoot(\ReflectionClass $reflection): \ReflectionClass @@ -69,7 +65,6 @@ trait Retryable if ($reflection->getName() === TestCase::class) { return $reflection; } - return $this->getTestCaseRoot($reflection->getParentClass()); } } diff --git a/tests/extensions/TestHook.php b/tests/extensions/TestHook.php index f6db16a227..67c1215c4c 100644 --- a/tests/extensions/TestHook.php +++ b/tests/extensions/TestHook.php @@ -3,11 +3,11 @@ namespace Appwrite\Tests; use PHPUnit\Runner\AfterTestHook; +use Exception; class TestHook implements AfterTestHook { protected const MAX_SECONDS_ALLOWED = 15; - public function executeAfterTest(string $test, float $time): void { printf( diff --git a/tests/resources/functions/php-fn/index.php b/tests/resources/functions/php-fn/index.php index 6da31cd499..7947c4a6a6 100644 --- a/tests/resources/functions/php-fn/index.php +++ b/tests/resources/functions/php-fn/index.php @@ -1,7 +1,7 @@ json([ 'APPWRITE_FUNCTION_ID' => $request['variables']['APPWRITE_FUNCTION_ID'], diff --git a/tests/resources/functions/php-large/index.php b/tests/resources/functions/php-large/index.php index 83140c27ff..84b6a991fe 100644 --- a/tests/resources/functions/php-large/index.php +++ b/tests/resources/functions/php-large/index.php @@ -10,6 +10,6 @@ return function ($request, $response) { 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'], 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'], 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'], - 'UNICODE_TEST' => 'êä', + 'UNICODE_TEST' => "êä" ]); }; diff --git a/tests/resources/functions/php/index.php b/tests/resources/functions/php/index.php index 83140c27ff..84b6a991fe 100644 --- a/tests/resources/functions/php/index.php +++ b/tests/resources/functions/php/index.php @@ -10,6 +10,6 @@ return function ($request, $response) { 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'], 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'], 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'], - 'UNICODE_TEST' => 'êä', + 'UNICODE_TEST' => "êä" ]); }; diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php index a3aa78bc6d..3e6a760b25 100644 --- a/tests/unit/Auth/AuthTest.php +++ b/tests/unit/Auth/AuthTest.php @@ -3,12 +3,12 @@ namespace Tests\Unit\Auth; use Appwrite\Auth\Auth; -use PHPUnit\Framework\TestCase; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; +use PHPUnit\Framework\TestCase; use Utopia\Database\Validator\Roles; class AuthTest extends TestCase @@ -127,13 +127,13 @@ class AuthTest extends TestCase // Scrypt $plain = 'some-scrypt-password'; $hash = 'b448ad7ba88b653b5b56b8053a06806724932d0751988bc9cd0ef7ff059e8ba8a020e1913b7069a650d3f99a1559aba0221f2c277826919513a054e76e339028'; - $generatedHash = Auth::passwordHash($plain, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2]); + $generatedHash = Auth::passwordHash($plain, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2]); - $this->assertEquals(true, Auth::passwordVerify($plain, $generatedHash, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); - $this->assertEquals(true, Auth::passwordVerify($plain, $hash, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); - $this->assertEquals(false, Auth::passwordVerify($plain, $hash, 'scrypt', ['salt' => 'some-wrong-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); - $this->assertEquals(false, Auth::passwordVerify($plain, $hash, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 10, 'costParallel' => 2])); - $this->assertEquals(false, Auth::passwordVerify('wrongPassword', $hash, 'scrypt', ['salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); + $this->assertEquals(true, Auth::passwordVerify($plain, $generatedHash, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); + $this->assertEquals(true, Auth::passwordVerify($plain, $hash, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); + $this->assertEquals(false, Auth::passwordVerify($plain, $hash, 'scrypt', [ 'salt' => 'some-wrong-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); + $this->assertEquals(false, Auth::passwordVerify($plain, $hash, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 10, 'costParallel' => 2])); + $this->assertEquals(false, Auth::passwordVerify('wrongPassword', $hash, 'scrypt', [ 'salt' => 'some-salt', 'length' => 64, 'costCpu' => 16384, 'costMemory' => 12, 'costParallel' => 2])); // ScryptModified tested are in provider-specific tests below @@ -164,7 +164,7 @@ class AuthTest extends TestCase $saltSeparator = 'Bw=='; $signerKey = 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=='; - $options = ['salt' => $salt, 'saltSeparator' => $saltSeparator, 'signerKey' => $signerKey]; + $options = [ 'salt' => $salt, 'saltSeparator' => $saltSeparator, 'signerKey' => $signerKey ]; $generatedHash = Auth::passwordHash($plain, 'scryptMod', $options); $this->assertEquals(true, Auth::passwordVerify($plain, $generatedHash, 'scryptMod', $options)); $this->assertEquals(true, Auth::passwordVerify($plain, $hash, 'scryptMod', $options)); @@ -339,7 +339,7 @@ class AuthTest extends TestCase public function testGuestRoles(): void { $user = new Document([ - '$id' => '', + '$id' => '' ]); $roles = Auth::getRoles($user); @@ -349,11 +349,11 @@ class AuthTest extends TestCase public function testUserRoles(): void { - $user = new Document([ + $user = new Document([ '$id' => ID::custom('123'), 'labels' => [ 'vip', - 'admin', + 'admin' ], 'emailVerification' => true, 'phoneVerification' => true, @@ -364,18 +364,18 @@ class AuthTest extends TestCase 'confirm' => true, 'roles' => [ 'administrator', - 'moderator', - ], + 'moderator' + ] ], [ '$id' => ID::custom('abc'), 'teamId' => ID::custom('def'), 'confirm' => true, 'roles' => [ - 'guest', - ], - ], - ], + 'guest' + ] + ] + ] ]); $roles = Auth::getRoles($user); @@ -414,7 +414,7 @@ class AuthTest extends TestCase public function testPrivilegedUserRoles(): void { Authorization::setRole(Auth::USER_ROLE_OWNER); - $user = new Document([ + $user = new Document([ '$id' => ID::custom('123'), 'emailVerification' => true, 'phoneVerification' => true, @@ -425,18 +425,18 @@ class AuthTest extends TestCase 'confirm' => true, 'roles' => [ 'administrator', - 'moderator', - ], + 'moderator' + ] ], [ '$id' => ID::custom('abc'), 'teamId' => ID::custom('def'), 'confirm' => true, 'roles' => [ - 'guest', - ], - ], - ], + 'guest' + ] + ] + ] ]); $roles = Auth::getRoles($user); @@ -458,7 +458,7 @@ class AuthTest extends TestCase public function testAppUserRoles(): void { Authorization::setRole(Auth::USER_ROLE_APPS); - $user = new Document([ + $user = new Document([ '$id' => ID::custom('123'), 'memberships' => [ [ @@ -467,18 +467,18 @@ class AuthTest extends TestCase 'confirm' => true, 'roles' => [ 'administrator', - 'moderator', - ], + 'moderator' + ] ], [ '$id' => ID::custom('abc'), 'teamId' => ID::custom('def'), 'confirm' => true, 'roles' => [ - 'guest', - ], - ], - ], + 'guest' + ] + ] + ] ]); $roles = Auth::getRoles($user); diff --git a/tests/unit/Auth/Validator/PasswordDictionaryTest.php b/tests/unit/Auth/Validator/PasswordDictionaryTest.php index 283d5c79fa..fd7f51ff16 100644 --- a/tests/unit/Auth/Validator/PasswordDictionaryTest.php +++ b/tests/unit/Auth/Validator/PasswordDictionaryTest.php @@ -4,6 +4,7 @@ namespace Tests\Unit\Auth\Validator; use Appwrite\Auth\Validator\PasswordDictionary; use PHPUnit\Framework\TestCase; +use Utopia\Database\Document; class PasswordDictionaryTest extends TestCase { diff --git a/tests/unit/Docker/ComposeTest.php b/tests/unit/Docker/ComposeTest.php index 350b41a820..56448ffd01 100644 --- a/tests/unit/Docker/ComposeTest.php +++ b/tests/unit/Docker/ComposeTest.php @@ -12,7 +12,7 @@ class ComposeTest extends TestCase public function setUp(): void { - $data = @file_get_contents(__DIR__.'/../../resources/docker/docker-compose.yml'); + $data = @file_get_contents(__DIR__ . '/../../resources/docker/docker-compose.yml'); if ($data === false) { throw new Exception('Failed to read compose file'); diff --git a/tests/unit/Docker/EnvTest.php b/tests/unit/Docker/EnvTest.php index b271bde504..e6c9b8cadf 100644 --- a/tests/unit/Docker/EnvTest.php +++ b/tests/unit/Docker/EnvTest.php @@ -12,7 +12,7 @@ class EnvTest extends TestCase public function setUp(): void { - $data = @file_get_contents(__DIR__.'/../../resources/docker/.env'); + $data = @file_get_contents(__DIR__ . '/../../resources/docker/.env'); if ($data === false) { throw new Exception('Failed to read compose file'); @@ -34,10 +34,10 @@ class EnvTest extends TestCase public function testExport(): void { - $this->assertEquals('_APP_X=value1 + $this->assertEquals("_APP_X=value1 _APP_Y=value2 _APP_Z=value3 _APP_W=value5= -', $this->object->export()); +", $this->object->export()); } } diff --git a/tests/unit/Event/EventTest.php b/tests/unit/Event/EventTest.php index 13f2bb4fd2..a328c8d599 100644 --- a/tests/unit/Event/EventTest.php +++ b/tests/unit/Event/EventTest.php @@ -10,16 +10,15 @@ use Utopia\App; class EventTest extends TestCase { protected ?Event $object = null; - protected string $queue = ''; public function setUp(): void { $redisHost = App::getEnv('_APP_REDIS_HOST', ''); $redisPort = App::getEnv('_APP_REDIS_PORT', ''); - \Resque::setBackend($redisHost.':'.$redisPort); + \Resque::setBackend($redisHost . ':' . $redisPort); - $this->queue = 'v1-tests'.uniqid(); + $this->queue = 'v1-tests' . uniqid(); $this->object = new Event($this->queue, 'TestsV1'); } @@ -86,7 +85,7 @@ class EventTest extends TestCase public function testGenerateEvents(): void { $event = Event::generateEvents('users.[userId].create', [ - 'userId' => 'torsten', + 'userId' => 'torsten' ]); $this->assertCount(4, $event); $this->assertContains('users.torsten.create', $event); @@ -95,7 +94,7 @@ class EventTest extends TestCase $this->assertContains('users.*', $event); $event = Event::generateEvents('users.[userId].update.email', [ - 'userId' => 'torsten', + 'userId' => 'torsten' ]); $this->assertCount(6, $event); $this->assertContains('users.torsten.update.email', $event); @@ -152,9 +151,10 @@ class EventTest extends TestCase $this->assertContains('databases.chaptersDB.collections.*.documents.*', $event); $this->assertContains('databases.chaptersDB.collections.*.documents.*.create', $event); + try { $event = Event::generateEvents('collections.[collectionId].documents.[documentId].create', [ - 'collectionId' => 'chapters', + 'collectionId' => 'chapters' ]); $this->fail(); } catch (\Throwable $th) { diff --git a/tests/unit/General/CollectionsTest.php b/tests/unit/General/CollectionsTest.php index 8596b857a8..73a9ccd0c2 100644 --- a/tests/unit/General/CollectionsTest.php +++ b/tests/unit/General/CollectionsTest.php @@ -10,7 +10,7 @@ class CollectionsTest extends TestCase public function setUp(): void { - $this->collections = require 'app/config/collections.php'; + $this->collections = require('app/config/collections.php'); } public function testDuplicateRules(): void diff --git a/tests/unit/Messaging/MessagingChannelsTest.php b/tests/unit/Messaging/MessagingChannelsTest.php index 14ec84a8e6..6fe7dda71f 100644 --- a/tests/unit/Messaging/MessagingChannelsTest.php +++ b/tests/unit/Messaging/MessagingChannelsTest.php @@ -3,9 +3,9 @@ namespace Tests\Unit\Messaging; use Appwrite\Auth\Auth; +use Utopia\Database\Document; use Appwrite\Messaging\Adapter\Realtime; use PHPUnit\Framework\TestCase; -use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; @@ -17,15 +17,10 @@ class MessagingChannelsTest extends TestCase public $connectionsPerChannel = 10; public Realtime $realtime; - public $connectionsCount = 0; - public $connectionsAuthenticated = 0; - public $connectionsGuest = 0; - public $connectionsTotal = 0; - public $allChannels = [ 'files', 'files.1', @@ -56,19 +51,19 @@ class MessagingChannelsTest extends TestCase for ($i = 0; $i < $this->connectionsPerChannel; $i++) { foreach ($this->allChannels as $index => $channel) { $user = new Document([ - '$id' => ID::custom('user'.$this->connectionsCount), + '$id' => ID::custom('user' . $this->connectionsCount), 'memberships' => [ [ - '$id' => ID::custom('member'.$i), - 'teamId' => ID::custom('team'.$i), + '$id' => ID::custom('member' . $i), + 'teamId' => ID::custom('team' . $i), 'confirm' => true, 'roles' => [ empty($index % 2) ? Auth::USER_ROLE_ADMIN : 'member', - ], - ], - ], + ] + ] + ] ]); $roles = Auth::getRoles($user); @@ -92,7 +87,7 @@ class MessagingChannelsTest extends TestCase for ($i = 0; $i < $this->connectionsPerChannel; $i++) { foreach ($this->allChannels as $index => $channel) { $user = new Document([ - '$id' => '', + '$id' => '' ]); $roles = Auth::getRoles($user); @@ -175,8 +170,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ], - ], + ] + ] ]; $receivers = $this->realtime->getSubscribers($event); @@ -199,7 +194,7 @@ class MessagingChannelsTest extends TestCase { $roles = [ Role::guests()->toString(), - Role::users()->toString(), + Role::users()->toString() ]; foreach ($this->allChannels as $index => $channel) { foreach ($roles as $role) { @@ -211,8 +206,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ], - ], + ] + ] ]; $receivers = $this->realtime->getSubscribers($event); @@ -237,7 +232,7 @@ class MessagingChannelsTest extends TestCase foreach ($this->allChannels as $index => $channel) { $permissions = []; for ($i = 0; $i < $this->connectionsPerChannel; $i++) { - $permissions[] = Role::user(ID::custom('user'.(! empty($i) ? $i : '').$index))->toString(); + $permissions[] = Role::user(ID::custom('user' . (!empty($i) ? $i : '') . $index))->toString(); } $event = [ 'project' => '1', @@ -245,8 +240,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ], - ], + ] + ] ]; $receivers = $this->realtime->getSubscribers($event); @@ -271,8 +266,8 @@ class MessagingChannelsTest extends TestCase $permissions = []; for ($i = 0; $i < $this->connectionsPerChannel; $i++) { - $permissions[] = Role::team(ID::custom('team'.$i))->toString(); - $permissions[] = Role::member(ID::custom('member'.$i))->toString(); + $permissions[] = Role::team(ID::custom('team' . $i))->toString(); + $permissions[] = Role::member(ID::custom('member' . $i))->toString(); } $event = [ 'project' => '1', @@ -280,8 +275,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ], - ], + ] + ] ]; $receivers = $this->realtime->getSubscribers($event); @@ -303,8 +298,8 @@ class MessagingChannelsTest extends TestCase : 'member'; $permissions = [ - Role::team(ID::custom('team'.$index), $role)->toString(), - Role::member(ID::custom('member'.$index))->toString(), + Role::team(ID::custom('team' . $index), $role)->toString(), + Role::member(ID::custom('member' . $index))->toString() ]; $event = [ @@ -313,8 +308,8 @@ class MessagingChannelsTest extends TestCase 'data' => [ 'channels' => [ 0 => $channel, - ], - ], + ] + ] ]; $receivers = $this->realtime->getSubscribers($event); diff --git a/tests/unit/Messaging/MessagingGuestTest.php b/tests/unit/Messaging/MessagingGuestTest.php index 660e9519e3..1aaa1febca 100644 --- a/tests/unit/Messaging/MessagingGuestTest.php +++ b/tests/unit/Messaging/MessagingGuestTest.php @@ -27,8 +27,8 @@ class MessagingGuestTest extends TestCase 'channels' => [ 0 => 'documents', 1 => 'documents', - ], - ], + ] + ] ]; $receivers = $realtime->getSubscribers($event); diff --git a/tests/unit/Messaging/MessagingTest.php b/tests/unit/Messaging/MessagingTest.php index d6ae6b095b..c2e3971945 100644 --- a/tests/unit/Messaging/MessagingTest.php +++ b/tests/unit/Messaging/MessagingTest.php @@ -2,9 +2,9 @@ namespace Tests\Unit\Messaging; +use Utopia\Database\Document; use Appwrite\Messaging\Adapter\Realtime; use PHPUnit\Framework\TestCase; -use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -44,8 +44,8 @@ class MessagingTest extends TestCase 'data' => [ 'channels' => [ 0 => 'account.123', - ], - ], + ] + ] ]; $receivers = $realtime->getSubscribers($event); @@ -148,7 +148,7 @@ class MessagingTest extends TestCase public function testConvertChannelsGuest(): void { $user = new Document([ - '$id' => '', + '$id' => '' ]); $channels = [ @@ -156,7 +156,7 @@ class MessagingTest extends TestCase 1 => 'documents', 2 => 'documents.789', 3 => 'account', - 4 => 'account.456', + 4 => 'account.456' ]; $channels = Realtime::convertChannels($channels, $user->getId()); @@ -170,30 +170,30 @@ class MessagingTest extends TestCase public function testConvertChannelsUser(): void { - $user = new Document([ + $user = new Document([ '$id' => ID::custom('123'), 'memberships' => [ [ 'teamId' => ID::custom('abc'), 'roles' => [ 'administrator', - 'moderator', - ], + 'moderator' + ] ], [ 'teamId' => ID::custom('def'), 'roles' => [ - 'guest', - ], - ], - ], + 'guest' + ] + ] + ] ]); $channels = [ 0 => 'files', 1 => 'documents', 2 => 'documents.789', 3 => 'account', - 4 => 'account.456', + 4 => 'account.456' ]; $channels = Realtime::convertChannels($channels, $user->getId()); @@ -321,7 +321,7 @@ class MessagingTest extends TestCase Permission::update(Role::team('123abc')), Permission::delete(Role::team('123abc')), ], - 'fileSecurity' => true, + 'fileSecurity' => true ]) ); diff --git a/tests/unit/Migration/MigrationTest.php b/tests/unit/Migration/MigrationTest.php index c322cc9635..13f9b9a3f5 100644 --- a/tests/unit/Migration/MigrationTest.php +++ b/tests/unit/Migration/MigrationTest.php @@ -22,12 +22,12 @@ abstract class MigrationTest extends TestCase /** * Runs every document fix twice, to prevent corrupted data on multiple migrations. * - * @param Document $document + * @param Document $document */ protected function fixDocument(Document $document) { return $this->method->invokeArgs($this->migration, [ - $this->method->invokeArgs($this->migration, [$document]), + $this->method->invokeArgs($this->migration, [$document]) ]); } @@ -36,14 +36,14 @@ abstract class MigrationTest extends TestCase */ public function testMigrationVersions(): void { - require_once __DIR__.'/../../../app/init.php'; + require_once __DIR__ . '/../../../app/init.php'; foreach (Migration::$versions as $class) { - $this->assertTrue(class_exists('Appwrite\\Migration\\Version\\'.$class)); + $this->assertTrue(class_exists('Appwrite\\Migration\\Version\\' . $class)); } // Test if current version exists // Only test official releases - skip if latest is release candidate - if (! (\str_contains(APP_VERSION_STABLE, 'RC'))) { + if (!(\str_contains(APP_VERSION_STABLE, 'RC'))) { $this->assertArrayHasKey(APP_VERSION_STABLE, Migration::$versions); } } @@ -60,8 +60,8 @@ abstract class MigrationTest extends TestCase 'a' => true, 'b' => 'abc', 'c' => 123, - 'd' => ['a', 'b', 'c'], - ], + 'd' => ['a', 'b', 'c'] + ] ], [ 'bool' => true, 'string' => 'abc', @@ -71,8 +71,8 @@ abstract class MigrationTest extends TestCase 'a' => true, 'b' => 'abc', 'c' => 123, - 'd' => ['a', 'b', 'c'], - ], + 'd' => ['a', 'b', 'c'] + ] ])); $this->assertFalse(Migration::hasDifference([ 'bool' => true, @@ -83,15 +83,15 @@ abstract class MigrationTest extends TestCase 'a' => true, 'b' => 'abc', 'c' => 123, - 'd' => ['a', 'b', 'c'], - ], + 'd' => ['a', 'b', 'c'] + ] ], [ 'string' => 'abc', 'assoc' => [ 'a' => true, 'b' => 'abc', 'c' => 123, - 'd' => ['a', 'b', 'c'], + 'd' => ['a', 'b', 'c'] ], 'int' => 123, 'array' => ['a', 'b', 'c'], @@ -99,40 +99,40 @@ abstract class MigrationTest extends TestCase ])); $this->assertTrue(Migration::hasDifference([ - 'a' => true, + 'a' => true ], [ - 'b' => true, + 'b' => true ])); $this->assertTrue(Migration::hasDifference([ - 'a' => 'true', + 'a' => 'true' ], [ - 'a' => true, + 'a' => true ])); $this->assertTrue(Migration::hasDifference([ - 'a' => true, + 'a' => true ], [ - 'a' => false, + 'a' => false ])); $this->assertTrue(Migration::hasDifference([ 'nested' => [ - 'a' => true, - ], + 'a' => true + ] ], [ - 'nested' => [], + 'nested' => [] ])); $this->assertTrue(Migration::hasDifference([ 'assoc' => [ 'bool' => true, 'string' => 'abc', 'int' => 123, - 'array' => ['a', 'b', 'c'], - ], + 'array' => ['a', 'b', 'c'] + ] ], [ 'nested' => [ 'a' => true, 'int' => '123', - 'array' => ['a', 'b', 'c'], - ], + 'array' => ['a', 'b', 'c'] + ] ])); } } diff --git a/tests/unit/Network/Validators/EmailTest.php b/tests/unit/Network/Validators/EmailTest.php index d74f2c30fc..f629ed6ddc 100755 --- a/tests/unit/Network/Validators/EmailTest.php +++ b/tests/unit/Network/Validators/EmailTest.php @@ -3,13 +3,12 @@ /** * Utopia PHP Framework * + * @package Framework + * @subpackage Tests * * @link https://github.com/utopia-php/framework - * * @author Appwrite Team - * * @version 1.0 RC4 - * * @license The MIT License (MIT) */ diff --git a/tests/unit/Template/TemplateTest.php b/tests/unit/Template/TemplateTest.php index ab4cb49742..1ca1595ca3 100644 --- a/tests/unit/Template/TemplateTest.php +++ b/tests/unit/Template/TemplateTest.php @@ -14,9 +14,10 @@ class TemplateTest extends TestCase public function setUp(): void { - $this->object = new Template(__DIR__.'/../../resources/template.tpl'); + $this->object = new Template(__DIR__ . '/../../resources/template.tpl'); $this->object - ->setParam('{{world}}', 'WORLD'); + ->setParam('{{world}}', 'WORLD') + ; } public function tearDown(): void diff --git a/tests/unit/Usage/StatsTest.php b/tests/unit/Usage/StatsTest.php index 72fadab70e..0c9914f4bd 100644 --- a/tests/unit/Usage/StatsTest.php +++ b/tests/unit/Usage/StatsTest.php @@ -13,26 +13,25 @@ use Utopia\Queue\Connection; class StatsTest extends TestCase { protected ?Connection $connection = null; - protected ?Client $client = null; protected const QUEUE_NAME = 'usage-test-q'; public function setUp(): void { - $env = App::getEnv('_APP_CONNECTIONS_QUEUE', AppwriteURL::unparse([ - 'scheme' => 'redis', - 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), - 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), - 'user' => App::getEnv('_APP_REDIS_USER', ''), - 'pass' => App::getEnv('_APP_REDIS_PASS', ''), - ])); + $env = App::getEnv('_APP_CONNECTIONS_QUEUE', AppwriteURL::unparse([ + 'scheme' => 'redis', + 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), + 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), + 'user' => App::getEnv('_APP_REDIS_USER', ''), + 'pass' => App::getEnv('_APP_REDIS_PASS', ''), + ])); $dsn = explode('=', $env); $dsn = $dsn[1] ?? ''; $dsn = new DSN($dsn); $this->connection = new Queue\Connection\Redis($dsn->getHost(), $dsn->getPort()); - $this->client = new Client(self::QUEUE_NAME, $this->connection); + $this->client = new Client(self::QUEUE_NAME, $this->connection); } public function tearDown(): void @@ -42,13 +41,13 @@ class StatsTest extends TestCase public function testSamePayload(): void { $inToQueue = [ - 'key_1' => 'value_1', - 'key_2' => 'value_2', + 'key_1' => 'value_1', + 'key_2' => 'value_2', ]; $result = $this->client->enqueue($inToQueue); $this->assertTrue($result); - $outFromQueue = $this->connection->leftPopArray('utopia-queue.queue.'.self::QUEUE_NAME, 0)['payload']; + $outFromQueue = $this->connection->leftPopArray('utopia-queue.queue.' . self::QUEUE_NAME, 0)['payload']; $this->assertNotEmpty($outFromQueue); $this->assertSame($inToQueue, $outFromQueue); } diff --git a/tests/unit/Utopia/Lists.php b/tests/unit/Utopia/Lists.php index ac54a293a5..8f003cc2ae 100644 --- a/tests/unit/Utopia/Lists.php +++ b/tests/unit/Utopia/Lists.php @@ -12,7 +12,7 @@ class Lists extends Model ->addRule('singles', [ 'type' => 'single', 'default' => '', - 'array' => true, + 'array' => true ]); } diff --git a/tests/unit/Utopia/Nested.php b/tests/unit/Utopia/Nested.php index b18f73977e..2be0e85762 100644 --- a/tests/unit/Utopia/Nested.php +++ b/tests/unit/Utopia/Nested.php @@ -15,7 +15,7 @@ class Nested extends Model ]) ->addRule('single', [ 'type' => 'single', - 'default' => '', + 'default' => '' ]); } diff --git a/tests/unit/Utopia/Request/Filters/V15Test.php b/tests/unit/Utopia/Request/Filters/V15Test.php index 7a37213d44..70bf71d4cb 100644 --- a/tests/unit/Utopia/Request/Filters/V15Test.php +++ b/tests/unit/Utopia/Request/Filters/V15Test.php @@ -28,7 +28,7 @@ class V15Test extends TestCase return [ 'basic test' => [ ['limit' => '12', 'offset' => '0'], - ['queries' => ['limit(12)', 'offset(0)']], + ['queries' => ['limit(12)', 'offset(0)']] ], ]; } @@ -72,8 +72,8 @@ class V15Test extends TestCase 'limit(12)', 'offset(0)', 'cursorBefore("abcd")', - 'orderAsc("")', - ], + 'orderAsc("")' + ] ], ], ]; @@ -90,7 +90,7 @@ class V15Test extends TestCase [ 'queries' => [ 'cursorAfter("abcd")', - ], + ] ], ], 'cursorDirection invalid' => [ @@ -101,7 +101,7 @@ class V15Test extends TestCase [ 'queries' => [ 'cursorAfter("abcd")', - ], + ] ], ], ]; @@ -117,7 +117,7 @@ class V15Test extends TestCase [ 'queries' => [ 'orderDesc("")', - ], + ] ], ], 'orderType invalid' => [ @@ -127,7 +127,7 @@ class V15Test extends TestCase [ 'queries' => [ 'orderAsc("")', - ], + ] ], ], ]; @@ -239,7 +239,7 @@ class V15Test extends TestCase 'write invalid' => [ ['write' => ['invalid', 'invalid:a']], ['permissions' => ['write("invalid:a")']], - ], + ] ]; } @@ -320,7 +320,7 @@ class V15Test extends TestCase 'queries' => [ 'orderDesc("lastName")', 'orderAsc("firstName")', - ], + ] ], ], 'orderType only' => [ @@ -330,7 +330,7 @@ class V15Test extends TestCase [ 'queries' => [ 'orderDesc("")', - ], + ] ], ], 'orderType invalid' => [ @@ -341,7 +341,7 @@ class V15Test extends TestCase [ 'queries' => [ 'orderAsc("lastName")', - ], + ] ], ], ]; @@ -371,7 +371,7 @@ class V15Test extends TestCase 'greaterThan("age", [20])', 'greaterThanEqual("age", [21])', 'search("address", ["pla"])', - ], + ] ], ], ]; @@ -439,7 +439,7 @@ class V15Test extends TestCase 'team:b', 'team:c/member', 'member:z', - ], + ] ], ], ]; diff --git a/tests/unit/Utopia/Response/Filters/V15Test.php b/tests/unit/Utopia/Response/Filters/V15Test.php index cf08d9bb70..fc38e5320b 100644 --- a/tests/unit/Utopia/Response/Filters/V15Test.php +++ b/tests/unit/Utopia/Response/Filters/V15Test.php @@ -2,11 +2,11 @@ namespace Tests\Unit\Utopia\Response\Filters; -use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Filters\V15; -use PHPUnit\Framework\TestCase; +use Appwrite\Utopia\Response; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use PHPUnit\Framework\TestCase; class V15Test extends TestCase { @@ -196,7 +196,7 @@ class V15Test extends TestCase 'maximumFileSize' => 100, 'allowedFileExtensions' => [ 'jpg', - 'png', + 'png' ], 'encryption' => false, 'antivirus' => false, @@ -213,7 +213,7 @@ class V15Test extends TestCase 'maximumFileSize' => 100, 'allowedFileExtensions' => [ 'jpg', - 'png', + 'png' ], 'encryption' => false, 'antivirus' => false, @@ -275,8 +275,8 @@ class V15Test extends TestCase [ 'startTime' => 1592981250, 'endTime' => 1592981250, - ], - ], + ] + ] ]; } @@ -346,14 +346,14 @@ class V15Test extends TestCase 'status' => 'available', 'required' => true, 'array' => false, - 'default' => false, + 'default' => false ], 'indexes' => [ 'key' => 'index1', 'type' => 'primary', 'status' => 'available', 'attributes' => [], - 'orders' => [], + 'orders' => [] ], ], [ @@ -361,10 +361,10 @@ class V15Test extends TestCase '$createdAt' => 1592981250, '$updatedAt' => 1592981250, '$read' => [ - 'role:all', + 'role:all' ], '$write' => [ - 'user:608f9da25e7e1', + 'user:608f9da25e7e1' ], 'databaseId' => '5e5ea5c16897e', 'name' => 'My Collection', @@ -376,14 +376,14 @@ class V15Test extends TestCase 'status' => 'available', 'required' => true, 'array' => false, - 'default' => false, + 'default' => false ], 'indexes' => [ 'key' => 'index1', 'type' => 'primary', 'status' => 'available', 'attributes' => [], - 'orders' => [], + 'orders' => [] ], ], ], @@ -511,7 +511,7 @@ class V15Test extends TestCase '$databaseId' => '5e5ea5c15117e', '$createdAt' => '2020-06-24T06:47:30.000Z', '$updatedAt' => '2020-06-24T06:47:30.000Z', - '$permissions' => [Permission::read(Role::any())], + '$permissions' => [Permission::read(Role::any())] ], [ '$id' => '5e5ea5c16897e', @@ -605,7 +605,7 @@ class V15Test extends TestCase '$createdAt' => '2020-06-24T06:47:30.000Z', '$updatedAt' => '2020-06-24T06:47:30.000Z', '$permissions' => [ - 'any', + "any" ], 'functionId' => '5e5ea6g16897e', 'trigger' => 'http', @@ -614,14 +614,14 @@ class V15Test extends TestCase 'response' => '', 'stdout' => '', 'stderr' => '', - 'duration' => 0.4, + 'duration' => 0.4 ], [ '$id' => '5e5ea5c16897e', '$createdAt' => 1592981250, '$updatedAt' => 1592981250, '$read' => [ - 'role:all', + "role:all" ], 'functionId' => '5e5ea6g16897e', 'trigger' => 'http', @@ -629,7 +629,7 @@ class V15Test extends TestCase 'statusCode' => 0, 'response' => '', 'stderr' => '', - 'time' => 0.4, + 'time' => 0.4 ], ], ]; @@ -730,37 +730,37 @@ class V15Test extends TestCase 'key' => 'key', 'value' => 'value', 'functionId' => '5e5ea5c16897e', - ], + ] ], 'events' => [ - 'account.create', + 'account.create' ], 'schedule' => '5 4 * * *', 'scheduleNext' => '2020-06-24T06:48:12.000Z', 'schedulePrevious' => '2020-06-24T06:47:17.000Z', - 'timeout' => 1592981237, + 'timeout' => 1592981237 ], [ '$id' => '5e5ea5c16897e', '$createdAt' => 1592981250, '$updatedAt' => 1592981250, 'execute' => [ - 'role:member', + 'role:member' ], 'name' => 'My Function', 'status' => 'enabled', 'runtime' => 'python-3.8', 'deployment' => '5e5ea5c16897e', 'vars' => [ - 'key' => 'value', + 'key' => 'value' ], 'events' => [ - 'account.create', + 'account.create' ], 'schedule' => '5 4 * * *', 'scheduleNext' => 1592981292, 'schedulePrevious' => 1592981237, - 'timeout' => 1592981237, + 'timeout' => 1592981237 ], ], 'enabled false' => [ @@ -877,7 +877,7 @@ class V15Test extends TestCase 'deviceBrand' => 'Google', 'deviceModel' => 'Nexus 5', 'countryCode' => 'US', - 'countryName' => 'United States', + 'countryName' => 'United States' ], [ 'event' => 'account.sessions.create', @@ -900,8 +900,8 @@ class V15Test extends TestCase 'deviceBrand' => 'Google', 'deviceModel' => 'Nexus 5', 'countryCode' => 'US', - 'countryName' => 'United States', - ], + 'countryName' => 'United States' + ] ], ]; } diff --git a/tests/unit/Utopia/ResponseTest.php b/tests/unit/Utopia/ResponseTest.php index f7be5a03a4..e4389b3953 100644 --- a/tests/unit/Utopia/ResponseTest.php +++ b/tests/unit/Utopia/ResponseTest.php @@ -2,9 +2,9 @@ namespace Tests\Unit\Utopia; +use Exception; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Filters\V11; -use Exception; use PHPUnit\Framework\TestCase; use Swoole\Http\Response as SwooleResponse; use Utopia\Database\Document; @@ -80,8 +80,8 @@ class ResponseTest extends TestCase 'string' => 'lorem ipsum', 'integer' => 123, 'boolean' => true, - 'hidden' => 'secret', - ]), + 'hidden' => 'secret' + ]) ], 'hidden' => 'secret', ]), 'lists'); @@ -107,8 +107,8 @@ class ResponseTest extends TestCase 'string' => 'lorem ipsum', 'integer' => 123, 'boolean' => true, - 'hidden' => 'secret', - ]), + 'hidden' => 'secret' + ]) ], 'hidden' => 'secret', ]), @@ -116,7 +116,7 @@ class ResponseTest extends TestCase 'string' => 'lorem ipsum', 'integer' => 123, 'boolean' => true, - 'hidden' => 'secret', + 'hidden' => 'secret' ]), 'hidden' => 'secret', ]), 'nested'); @@ -126,6 +126,7 @@ class ResponseTest extends TestCase $this->assertArrayNotHasKey('hidden', $output); $this->assertCount(1, $output['lists']['singles']); + $single = $output['single']; $this->assertArrayHasKey('string', $single); $this->assertArrayHasKey('integer', $single); diff --git a/tests/unit/Utopia/Single.php b/tests/unit/Utopia/Single.php index 6e9fd3c9ec..3bd09ef6da 100644 --- a/tests/unit/Utopia/Single.php +++ b/tests/unit/Utopia/Single.php @@ -12,7 +12,7 @@ class Single extends Model ->addRule('string', [ 'type' => self::TYPE_STRING, 'example' => '5e5ea5c16897e', - 'required' => true, + 'required' => true ]) ->addRule('integer', [ 'type' => self::TYPE_INTEGER, @@ -27,7 +27,7 @@ class Single extends Model ->addRule('required', [ 'type' => self::TYPE_STRING, 'default' => 'default', - 'required' => true, + 'required' => true ]); } From ec540002636c9802d2bd54366f6e3e87340244a9 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 24 Aug 2023 01:54:25 +0530 Subject: [PATCH 034/196] adds test for target controllers --- app/config/errors.php | 2 +- app/controllers/api/account.php | 90 +++++++------- app/controllers/api/users.php | 44 ++++--- tests/e2e/Scopes/ProjectCustom.php | 2 + tests/e2e/Services/Account/AccountBase.php | 2 +- .../Account/AccountCustomClientTest.php | 112 ++++++++++++++++++ tests/e2e/Services/Users/UsersBase.php | 94 +++++++++++++++ 7 files changed, 278 insertions(+), 68 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 5942c6027c..add3562cda 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -243,7 +243,7 @@ return [ Exception::USER_TARGET_ALREADY_EXISTS => [ 'name' => Exception::USER_TARGET_ALREADY_EXISTS, 'description' => 'A target with the same ID already exists.', - 'code' => 404, + 'code' => 409, ], /** Teams */ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 46acd2efdb..046297f5ef 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1834,9 +1834,9 @@ App::get('/v1/account/targets') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET_LIST) - ->inject('response') ->inject('user') - ->action(function (Response $response, Document $user) { + ->inject('response') + ->action(function (Document $user, Response $response) { $targets = $user->getAttribute('targets', []); @@ -1900,13 +1900,13 @@ App::get('/v1/account/targets/:targetId') ->label('sdk.description', '/docs/references/account/get-Target.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_SESSION) + ->label('sdk.response.model', Response::MODEL_TARGET) ->label('sdk.offline.model', '/account/targets') ->label('sdk.offline.key', '{targetId}') ->param('targetId', '', new UID(), 'Target ID.') - ->inject('response') ->inject('user') - ->action(function (string $targetId, Response $response, Document $user) { + ->inject('response') + ->action(function (string $targetId, Document $user, Response $response) { $target = $user->find('$id', $targetId, 'targets'); @@ -2999,9 +2999,12 @@ App::put('/v1/account/verification/phone') }); App::post('/v1/account/targets') - ->desc('Create User Target') + ->desc('Create Account\'s Target') ->groups(['api', 'account']) ->label('event', 'users.[userId].targets.[targetId].create') + ->label('audits.event', 'target.create') + ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') @@ -3010,26 +3013,20 @@ App::post('/v1/account/targets') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET) - ->param('userId', '', new UID(), 'ID of the user.', false) - ->param('targetId', '', new UID(), 'Target ID.', false) - ->param('providerId', '', new UID(), 'ID of the provider.', false) - ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', false) + ->param('targetId', '', new UID(), 'Target ID.') + ->param('providerId', '', new UID(), 'Provider ID.') + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') + ->inject('user') ->inject('response') ->inject('dbForProject') ->inject('events') - ->action(function (string $targetId, string $userId, string $providerId, string $identifier, Response $response, Database $dbForProject, Event $events) { - $provider = $dbForProject->getDocument('providers', $providerId); + ->action(function (string $targetId, string $providerId, string $identifier, Document $user, Response $response, Database $dbForProject, Event $events) { + $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } - $user = $dbForProject->getDocument('users', $userId); - - if ($user->isEmpty()) { - throw new Exception(Exception::USER_NOT_FOUND); - } - $target = $dbForProject->getDocument('targets', $targetId); if (!$target->isEmpty()) { @@ -3038,29 +3035,34 @@ App::post('/v1/account/targets') $target = $dbForProject->createDocument('targets', new Document([ '$id' => $targetId, - // TO DO: what permissions should be given when created a target. '$permissions' => [ - Permission::read(Role::any()) + Permission::read(Role::user($user->getId())), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), ], 'providerId' => $providerId, 'providerInternalId' => $provider->getInternalId(), 'providerType' => null, - 'userId' => $userId, + 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), 'identifier' => $identifier, ])); $dbForProject->deleteCachedDocument('users', $user->getId()); $events - ->setParam('userId', $userId); + ->setParam('userId', $user->getId()) + ->setParam('targetId', $targetId); $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($target, Response::MODEL_TARGET); }); App::patch('/v1/account/targets/:targetId/identifier') - ->desc('Update user target\'s identifier') + ->desc('Update account\'s target identifier') ->groups(['api', 'account']) ->label('event', 'users.[userId].targets.[targetId].update') + ->label('audits.event', 'target.update') + ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') @@ -3069,19 +3071,13 @@ App::patch('/v1/account/targets/:targetId/identifier') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET) - ->param('userId', '', new UID(), 'ID of the user.', false) - ->param('targetId', '', new UID(), 'Target ID.', false) - ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) + ->param('targetId', '', new UID(), 'Target ID.') + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') + ->inject('user') ->inject('response') ->inject('dbForProject') ->inject('events') - ->action(function (string $targetId, string $userId, string $identifier, Response $response, Database $dbForProject, Event $events) { - - $user = $dbForProject->getDocument('users', $userId); - - if ($user->isEmpty()) { - throw new Exception(Exception::USER_NOT_FOUND); - } + ->action(function (string $targetId, string $identifier, Document $user, Response $response, Database $dbForProject, Event $events) { $target = $dbForProject->getDocument('targets', $targetId); @@ -3096,37 +3092,34 @@ App::patch('/v1/account/targets/:targetId/identifier') $dbForProject->deleteCachedDocument('users', $user->getId()); $events - ->setParam('userId', $userId); + ->setParam('userId', $user->getId()) + ->setParam('targetId', $targetId); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($target, Response::MODEL_TARGET); }); App::delete('/v1/account/targets/:targetId') - ->desc('Delete user target') + ->desc('Delete account\'s target') ->groups(['api', 'account']) ->label('event', 'users.[userId].targets.[targetId].delete') + ->label('audits.event', 'target.delete') + ->label('audits.resource', 'user/{response.userId}') + ->label('audits.userId', '{response.userId}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'deleteTarget') ->label('sdk.description', '/docs/references/account/delete-target.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('userId', '', new UID(), 'ID of the user.', false) - ->param('targetId', '', new UID(), 'Target ID.', false) + ->param('targetId', '', new UID(), 'Target ID.') + ->inject('user') ->inject('response') ->inject('dbForProject') ->inject('events') - ->action(function (string $targetId, string $userId, Response $response, Database $dbForProject, Event $events) { - - $user = $dbForProject->getDocument('users', $userId); - - if ($user->isEmpty()) { - throw new Exception(Exception::USER_NOT_FOUND); - } + ->action(function (string $targetId, Document $user, Response $response, Database $dbForProject, Event $events) { $target = $dbForProject->getDocument('targets', $targetId); @@ -3136,13 +3129,14 @@ App::delete('/v1/account/targets/:targetId') $target = $dbForProject->deleteDocument('targets', $target->getId()); $dbForProject->deleteCachedDocument('users', $user->getId()); - $user = $dbForProject->getDocument('users', $userId); + $user = $dbForProject->getDocument('users', $user->getId()); // clone user object to send to workers $clone = clone $user; $events - ->setParam('userId', $userId) + ->setParam('userId', $user->getId()) + ->setParam('targetId', $targetId) ->setPayload($response->output($clone, Response::MODEL_USER)); $response->noContent(); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index cf94135351..e5599c762d 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -376,6 +376,8 @@ App::post('/v1/users/:userId/targets') ->desc('Create User Target') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].create') + ->label('audits.event', 'target.create') + ->label('audits.resource', 'user/{response.$id}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -384,14 +386,14 @@ App::post('/v1/users/:userId/targets') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET) - ->param('userId', '', new UID(), 'ID of the user.', false) - ->param('targetId', '', new UID(), 'Target ID.', false) - ->param('providerId', '', new UID(), 'ID of the provider.', false) - ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', false) + ->param('userId', '', new UID(), 'User ID.') + ->param('targetId', '', new UID(), 'Target ID.') + ->param('providerId', '', new UID(), 'Provider ID.') + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') ->inject('response') ->inject('dbForProject') ->inject('events') - ->action(function (string $targetId, string $userId, string $providerId, string $identifier, Response $response, Database $dbForProject, Event $events) { + ->action(function (string $userId, string $targetId, string $providerId, string $identifier, Response $response, Database $dbForProject, Event $events) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -425,7 +427,8 @@ App::post('/v1/users/:userId/targets') ])); $dbForProject->deleteCachedDocument('users', $user->getId()); $events - ->setParam('userId', $userId); + ->setParam('userId', $userId) + ->setParam('targetId', $targetId); $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($target, Response::MODEL_TARGET); @@ -532,7 +535,7 @@ App::get('/v1/users/:userId/prefs') App::get('/v1/users/:userId/targets/:targetId') ->desc('Get User Target') ->groups(['api', 'users']) - ->label('scope', 'users.read') + ->label('scope', 'targets.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'getTarget') @@ -725,7 +728,7 @@ App::get('/v1/users/:userId/logs') App::get('/v1/users/:userId/targets') ->desc('List User Targets') ->groups(['api', 'users']) - ->label('scope', 'users.read') + ->label('scope', 'targets.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'listTargets') @@ -1215,6 +1218,8 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->desc('Update user target\'s identifier') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].update') + ->label('audits.event', 'target.update') + ->label('audits.resource', 'user/{response.$id}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -1223,13 +1228,13 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET) - ->param('userId', '', new UID(), 'ID of the user.', false) - ->param('targetId', '', new UID(), 'Target ID.', false) - ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) + ->param('userId', '', new UID(), 'User ID.') + ->param('targetId', '', new UID(), 'Target ID.') + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') ->inject('response') ->inject('dbForProject') ->inject('events') - ->action(function (string $targetId, string $userId, string $identifier, Response $response, Database $dbForProject, Event $events) { + ->action(function (string $userId, string $targetId, string $identifier, Response $response, Database $dbForProject, Event $events) { $user = $dbForProject->getDocument('users', $userId); @@ -1250,10 +1255,10 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') $dbForProject->deleteCachedDocument('users', $user->getId()); $events - ->setParam('userId', $userId); + ->setParam('userId', $userId) + ->setParam ('targetId', $targetId); $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($target, Response::MODEL_TARGET); }); @@ -1388,20 +1393,22 @@ App::delete('/v1/users/:userId/targets/:targetId') ->desc('Delete user target') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].delete') + ->label('audits.event', 'target.delete') + ->label('audits.resource', 'user/{response.$id}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'deleteTarget') ->label('sdk.description', '/docs/references/users/delete-target.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('userId', '', new UID(), 'ID of the user.', false) - ->param('targetId', '', new UID(), 'Target ID.', false) + ->param('userId', '', new UID(), 'User ID.') + ->param('targetId', '', new UID(), 'Target ID.') ->inject('response') ->inject('dbForProject') ->inject('events') - ->action(function (string $targetId, string $userId, Response $response, Database $dbForProject, Event $events) { + ->action(function (string $userId, string $targetId, Response $response, Database $dbForProject, Event $events) { $user = $dbForProject->getDocument('users', $userId); @@ -1424,6 +1431,7 @@ App::delete('/v1/users/:userId/targets/:targetId') $events ->setParam('userId', $userId) + ->setParam('targetId', $targetId) ->setPayload($response->output($clone, Response::MODEL_USER)); $response->noContent(); diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index ee41129fde..2a1b0a8039 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -81,6 +81,8 @@ trait ProjectCustom 'locale.read', 'avatars.read', 'health.read', + 'targets.read', + 'targets.write', 'providers.read', 'providers.write', 'messages.read', diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 291d55b221..c611b6e920 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -363,7 +363,7 @@ trait AccountBase $this->assertEquals($response['headers']['status-code'], 200); $this->assertIsArray($response['body']['logs']); $this->assertNotEmpty($response['body']['logs']); - $this->assertCount(3, $response['body']['logs']); + $this->assertCount(5, $response['body']['logs']); $this->assertIsNumeric($response['body']['total']); $this->assertContains($response['body']['logs'][1]['event'], ["session.create"]); $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index d225496a65..d429854ec8 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -116,6 +116,118 @@ class AccountCustomClientTest extends Scope return []; } + /** + * @depends testCreateAccountSession + */ + public function testCreateAccountTarget(array $data): array + { + $session = $data['session'] ?? ''; + $apiKey = $this->getProject()['apiKey']; + + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $apiKey, + ], [ + 'name' => 'Sengrid1', + 'apiKey' => 'my-apikey' + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + $response = $this->client->call(Client::METHOD_POST, '/account/targets', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]), [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => 'my-token', + ]); + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertEquals($provider['body']['$id'], $response['body']['providerId']); + $this->assertEquals('my-token', $response['body']['identifier']); + return ['target' => $response['body'], 'session' => $session]; + } + + /** + * @depends testCreateAccountTarget + */ + public function testUpdateAccountTarget(array $data): array + { + $session = $data['session'] ?? ''; + $target = $data['target']; + $response = $this->client->call(Client::METHOD_PATCH, '/account/targets/' . $target['$id'] .'/identifier', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]), [ + 'identifier' => 'my-updated-token', + ]); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('my-updated-token', $response['body']['identifier']); + return $data; + } + + /** + * @depends testCreateAccountSession + */ + public function testListAccountTarget(array $data) + { + $session = $data['session'] ?? ''; + $response = $this->client->call(Client::METHOD_GET, '/account/targets', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(1, $response['body']['total']); + } + + /** + * @depends testCreateAccountTarget + */ + public function testGetAccountTarget(array $data) + { + $session = $data['session'] ?? ''; + $target = $data['target']; + + $response = $this->client->call(Client::METHOD_GET, '/account/targets/' .$target['$id'], array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($data['target']['$id'], $response['body']['$id']); + } + + /** + * @depends testUpdateAccountTarget + */ + public function testDeleteAccountTarget(array $data) + { + $session = $data['session'] ?? ''; + $target = $data['target']; + + $response = $this->client->call(Client::METHOD_DELETE, '/account/targets/' .$target['$id'], array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); + $this->assertEquals(204, $response['headers']['status-code']); + $response = $this->client->call(Client::METHOD_GET, '/account/targets', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(0, $response['body']['total']); + } + public function testBlockedAccount(): array { $email = uniqid() . 'user@localhost.test'; diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index baf601789a..1d859a626d 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -1211,6 +1211,100 @@ trait UsersBase $this->assertEquals($response['headers']['status-code'], 400); } + /** + * @depends testGetUser + */ + public function testCreateUserTarget(array $data): array + { + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'name' => 'Sengrid1', + 'apiKey' => 'my-apikey' + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + $response = $this->client->call(Client::METHOD_POST, '/users/' . $data['userId'] . '/targets', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => 'my-token', + ]); + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertEquals($provider['body']['$id'], $response['body']['providerId']); + $this->assertEquals('my-token', $response['body']['identifier']); + return $response['body']; + } + + /** + * @depends testCreateUserTarget + */ + public function testUpdateUserTarget(array $data): array + { + $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/targets/' . $data['$id'] .'/identifier', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'identifier' => 'my-updated-token', + ]); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('my-updated-token', $response['body']['identifier']); + return $response['body']; + } + + /** + * @depends testGetUser + */ + public function testListUserTarget(array $data) + { + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ])); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(1, $response['body']['total']); + } + + /** + * @depends testUpdateUserTarget + */ + public function testGetUserTarget(array $data) + { + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets/' .$data['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ])); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($data['$id'], $response['body']['$id']); + } + + /** + * @depends testUpdateUserTarget + */ + public function testDeleteUserTarget(array $data) + { + $response = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'] . '/targets/' .$data['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ])); + $this->assertEquals(204, $response['headers']['status-code']); + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ])); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(0, $response['body']['total']); + } + /** * @depends testGetUser */ From a95c29d546a5988e0bfc6077820efd14cd22e55c Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 24 Aug 2023 01:55:08 +0530 Subject: [PATCH 035/196] lint fix --- app/controllers/api/account.php | 2 +- app/controllers/api/users.php | 2 +- .../e2e/Services/Account/AccountCustomClientTest.php | 8 ++++---- tests/e2e/Services/Messaging/MessagingServerTest.php | 1 - tests/e2e/Services/Users/UsersBase.php | 12 ++++++------ 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 046297f5ef..332103cf80 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1906,7 +1906,7 @@ App::get('/v1/account/targets/:targetId') ->param('targetId', '', new UID(), 'Target ID.') ->inject('user') ->inject('response') - ->action(function (string $targetId, Document $user, Response $response) { + ->action(function (string $targetId, Document $user, Response $response) { $target = $user->find('$id', $targetId, 'targets'); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index e5599c762d..7984fb24d9 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1256,7 +1256,7 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') $events ->setParam('userId', $userId) - ->setParam ('targetId', $targetId); + ->setParam('targetId', $targetId); $response ->dynamic($target, Response::MODEL_TARGET); diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index d429854ec8..39fa8d0fa5 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -119,7 +119,7 @@ class AccountCustomClientTest extends Scope /** * @depends testCreateAccountSession */ - public function testCreateAccountTarget(array $data): array + public function testCreateAccountTarget(array $data): array { $session = $data['session'] ?? ''; $apiKey = $this->getProject()['apiKey']; @@ -156,7 +156,7 @@ class AccountCustomClientTest extends Scope { $session = $data['session'] ?? ''; $target = $data['target']; - $response = $this->client->call(Client::METHOD_PATCH, '/account/targets/' . $target['$id'] .'/identifier', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/account/targets/' . $target['$id'] . '/identifier', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -193,7 +193,7 @@ class AccountCustomClientTest extends Scope $session = $data['session'] ?? ''; $target = $data['target']; - $response = $this->client->call(Client::METHOD_GET, '/account/targets/' .$target['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/account/targets/' . $target['$id'], array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -211,7 +211,7 @@ class AccountCustomClientTest extends Scope $session = $data['session'] ?? ''; $target = $data['target']; - $response = $this->client->call(Client::METHOD_DELETE, '/account/targets/' .$target['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/account/targets/' . $target['$id'], array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Messaging/MessagingServerTest.php b/tests/e2e/Services/Messaging/MessagingServerTest.php index 9bc9f93caf..7b93ab29ac 100644 --- a/tests/e2e/Services/Messaging/MessagingServerTest.php +++ b/tests/e2e/Services/Messaging/MessagingServerTest.php @@ -187,5 +187,4 @@ class MessagingServerTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } } - } diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index 1d859a626d..947a3a5cd9 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -1214,7 +1214,7 @@ trait UsersBase /** * @depends testGetUser */ - public function testCreateUserTarget(array $data): array + public function testCreateUserTarget(array $data): array { $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [ 'content-type' => 'application/json', @@ -1239,13 +1239,13 @@ trait UsersBase $this->assertEquals('my-token', $response['body']['identifier']); return $response['body']; } - + /** * @depends testCreateUserTarget */ public function testUpdateUserTarget(array $data): array { - $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/targets/' . $data['$id'] .'/identifier', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/targets/' . $data['$id'] . '/identifier', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -1256,7 +1256,7 @@ trait UsersBase $this->assertEquals('my-updated-token', $response['body']['identifier']); return $response['body']; } - + /** * @depends testGetUser */ @@ -1276,7 +1276,7 @@ trait UsersBase */ public function testGetUserTarget(array $data) { - $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets/' .$data['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets/' . $data['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -1290,7 +1290,7 @@ trait UsersBase */ public function testDeleteUserTarget(array $data) { - $response = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'] . '/targets/' .$data['$id'], array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'] . '/targets/' . $data['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], From 82d220e15846d74693a9272fe57f99c629e5aa3e Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 24 Aug 2023 13:43:30 +0530 Subject: [PATCH 036/196] fixes audit events --- app/controllers/api/account.php | 6 ++--- app/controllers/api/messaging.php | 38 +++++++++++++++---------------- app/controllers/api/users.php | 6 ++--- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 332103cf80..4f64965a0b 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -3002,7 +3002,7 @@ App::post('/v1/account/targets') ->desc('Create Account\'s Target') ->groups(['api', 'account']) ->label('event', 'users.[userId].targets.[targetId].create') - ->label('audits.event', 'target.create') + ->label('audits.event', 'targets.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('scope', 'targets.write') @@ -3060,7 +3060,7 @@ App::patch('/v1/account/targets/:targetId/identifier') ->desc('Update account\'s target identifier') ->groups(['api', 'account']) ->label('event', 'users.[userId].targets.[targetId].update') - ->label('audits.event', 'target.update') + ->label('audits.event', 'targets.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('scope', 'targets.write') @@ -3103,7 +3103,7 @@ App::delete('/v1/account/targets/:targetId') ->desc('Delete account\'s target') ->groups(['api', 'account']) ->label('event', 'users.[userId].targets.[targetId].delete') - ->label('audits.event', 'target.delete') + ->label('audits.event', 'targets.delete') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('scope', 'targets.write') diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 1ff95fbeea..4d97323f3b 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -86,7 +86,7 @@ App::get('/v1/messaging/providers/:id') App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.create') + ->label('audits.event', 'providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -118,7 +118,7 @@ App::post('/v1/messaging/providers/mailgun') App::patch('/v1/messaging/providers/:id/mailgun') ->desc('Update Mailgun Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.update') + ->label('audits.event', 'providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -172,7 +172,7 @@ App::patch('/v1/messaging/providers/:id/mailgun') App::post('/v1/messaging/providers/sendgrid') ->desc('Create Sendgrid Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.create') + ->label('audits.event', 'providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -202,7 +202,7 @@ App::post('/v1/messaging/providers/sendgrid') App::patch('/v1/messaging/providers/:id/sendgrid') ->desc('Update Sendgrid Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.update') + ->label('audits.event', 'providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -251,7 +251,7 @@ App::patch('/v1/messaging/providers/:id/sendgrid') App::post('/v1/messaging/providers/msg91') ->desc('Create Msg91 Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.create') + ->label('audits.event', 'providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -283,7 +283,7 @@ App::post('/v1/messaging/providers/msg91') App::patch('/v1/messaging/providers/:id/msg91') ->desc('Update Msg91 Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.update') + ->label('audits.event', 'providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -337,7 +337,7 @@ App::patch('/v1/messaging/providers/:id/msg91') App::post('/v1/messaging/providers/telesign') ->desc('Create Telesign Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.create') + ->label('audits.event', 'providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -369,7 +369,7 @@ App::post('/v1/messaging/providers/telesign') App::patch('/v1/messaging/providers/:id/telesign') ->desc('Update Telesign Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.update') + ->label('audits.event', 'providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -423,7 +423,7 @@ App::patch('/v1/messaging/providers/:id/telesign') App::post('/v1/messaging/providers/textmagic') ->desc('Create Textmagic Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.create') + ->label('audits.event', 'providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -455,7 +455,7 @@ App::post('/v1/messaging/providers/textmagic') App::patch('/v1/messaging/providers/:id/textmagic') ->desc('Update Textmagic Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.update') + ->label('audits.event', 'providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -509,7 +509,7 @@ App::patch('/v1/messaging/providers/:id/textmagic') App::post('/v1/messaging/providers/twilio') ->desc('Create Twilio Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.create') + ->label('audits.event', 'providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -541,7 +541,7 @@ App::post('/v1/messaging/providers/twilio') App::patch('/v1/messaging/providers/:id/twilio') ->desc('Update Twilio Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.update') + ->label('audits.event', 'providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -595,7 +595,7 @@ App::patch('/v1/messaging/providers/:id/twilio') App::post('/v1/messaging/providers/vonage') ->desc('Create Vonage Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.create') + ->label('audits.event', 'providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -627,7 +627,7 @@ App::post('/v1/messaging/providers/vonage') App::patch('/v1/messaging/providers/:id/vonage') ->desc('Update Vonage Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.update') + ->label('audits.event', 'providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -684,7 +684,7 @@ App::patch('/v1/messaging/providers/:id/vonage') App::post('/v1/messaging/providers/fcm') ->desc('Create FCM Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.create') + ->label('audits.event', 'providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -714,7 +714,7 @@ App::post('/v1/messaging/providers/fcm') App::patch('/v1/messaging/providers/:id/fcm') ->desc('Update FCM Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.update') + ->label('audits.event', 'providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -758,7 +758,7 @@ App::patch('/v1/messaging/providers/:id/fcm') App::post('/v1/messaging/providers/apns') ->desc('Create APNS Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.create') + ->label('audits.event', 'providers.create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -796,7 +796,7 @@ App::post('/v1/messaging/providers/apns') App::patch('/v1/messaging/providers/:id/apns') ->desc('Update APNS Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.update') + ->label('audits.event', 'providers.update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -856,7 +856,7 @@ App::patch('/v1/messaging/providers/:id/apns') App::delete('/v1/messaging/providers/:id') ->desc('Delete Provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.providers.delete') + ->label('audits.event', 'providers.delete') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 7984fb24d9..d27d487ebb 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -376,7 +376,7 @@ App::post('/v1/users/:userId/targets') ->desc('Create User Target') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].create') - ->label('audits.event', 'target.create') + ->label('audits.event', 'targets.create') ->label('audits.resource', 'user/{response.$id}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) @@ -1218,7 +1218,7 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->desc('Update user target\'s identifier') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].update') - ->label('audits.event', 'target.update') + ->label('audits.event', 'targets.update') ->label('audits.resource', 'user/{response.$id}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) @@ -1393,7 +1393,7 @@ App::delete('/v1/users/:userId/targets/:targetId') ->desc('Delete user target') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].delete') - ->label('audits.event', 'target.delete') + ->label('audits.event', 'targets.delete') ->label('audits.resource', 'user/{response.$id}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) From e8cc60b0c2c972815c55a89cd044f5346bdea7da Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 24 Aug 2023 14:05:51 +0530 Subject: [PATCH 037/196] adds audit resource in messaging controllers --- app/controllers/api/messaging.php | 20 ++++++++++++++++++++ app/controllers/api/users.php | 6 +++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 4d97323f3b..a44ef63fb0 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -87,6 +87,7 @@ App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -119,6 +120,7 @@ App::patch('/v1/messaging/providers/:id/mailgun') ->desc('Update Mailgun Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -173,6 +175,7 @@ App::post('/v1/messaging/providers/sendgrid') ->desc('Create Sendgrid Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -203,6 +206,7 @@ App::patch('/v1/messaging/providers/:id/sendgrid') ->desc('Update Sendgrid Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -252,6 +256,7 @@ App::post('/v1/messaging/providers/msg91') ->desc('Create Msg91 Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -284,6 +289,7 @@ App::patch('/v1/messaging/providers/:id/msg91') ->desc('Update Msg91 Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -338,6 +344,7 @@ App::post('/v1/messaging/providers/telesign') ->desc('Create Telesign Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -370,6 +377,7 @@ App::patch('/v1/messaging/providers/:id/telesign') ->desc('Update Telesign Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -424,6 +432,7 @@ App::post('/v1/messaging/providers/textmagic') ->desc('Create Textmagic Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -456,6 +465,7 @@ App::patch('/v1/messaging/providers/:id/textmagic') ->desc('Update Textmagic Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -510,6 +520,7 @@ App::post('/v1/messaging/providers/twilio') ->desc('Create Twilio Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -542,6 +553,7 @@ App::patch('/v1/messaging/providers/:id/twilio') ->desc('Update Twilio Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -596,6 +608,7 @@ App::post('/v1/messaging/providers/vonage') ->desc('Create Vonage Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -628,6 +641,7 @@ App::patch('/v1/messaging/providers/:id/vonage') ->desc('Update Vonage Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -685,6 +699,7 @@ App::post('/v1/messaging/providers/fcm') ->desc('Create FCM Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -715,6 +730,7 @@ App::patch('/v1/messaging/providers/:id/fcm') ->desc('Update FCM Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -759,6 +775,7 @@ App::post('/v1/messaging/providers/apns') ->desc('Create APNS Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -797,6 +814,7 @@ App::patch('/v1/messaging/providers/:id/apns') ->desc('Update APNS Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -857,6 +875,7 @@ App::delete('/v1/messaging/providers/:id') ->desc('Delete Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.delete') + ->label('audits.resource', 'providers/{request.id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'messaging') @@ -885,6 +904,7 @@ App::post('/v1/messaging/messages/email') ->desc('Send an email.') ->groups(['api', 'messaging']) ->label('audits.event', 'messages.create') + ->label('audits.resource', 'messages/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index d27d487ebb..df5ea7925d 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -377,7 +377,7 @@ App::post('/v1/users/:userId/targets') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].create') ->label('audits.event', 'targets.create') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -1219,7 +1219,7 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].update') ->label('audits.event', 'targets.update') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -1394,7 +1394,7 @@ App::delete('/v1/users/:userId/targets/:targetId') ->groups(['api', 'users']) ->label('event', 'users.[userId].targets.[targetId].delete') ->label('audits.event', 'targets.delete') - ->label('audits.resource', 'user/{response.$id}') + ->label('audits.resource', 'user/{response.userId}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') From eafea1c41d811ac71cbb313bf8f13072282d2013 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 24 Aug 2023 14:31:22 +0530 Subject: [PATCH 038/196] formats messaging controller --- app/controllers/api/messaging.php | 1662 ++++++++++++++--------------- 1 file changed, 831 insertions(+), 831 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index a44ef63fb0..753abc8432 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -15,939 +15,939 @@ use Utopia\Validator\ArrayList; use Utopia\Validator\Text; App::get('/v1/messaging/providers') - ->desc('List Providers') - ->groups(['api', 'messaging']) - ->label('scope', 'providers.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'listProviders') - ->label('sdk.description', '/docs/references/messaging/list-providers.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER_LIST) - ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) - ->inject('dbForProject') - ->inject('response') - ->action(function (array $queries, Database $dbForProject, Response $response) { - $queries = Query::parseQueries($queries); + ->desc('List Providers') + ->groups(['api', 'messaging']) + ->label('scope', 'providers.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listProviders') + ->label('sdk.description', '/docs/references/messaging/list-providers.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER_LIST) + ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->inject('dbForProject') + ->inject('response') + ->action(function (array $queries, Database $dbForProject, Response $response) { + $queries = Query::parseQueries($queries); - // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); - $cursor = reset($cursor); + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); - if ($cursor) { - $providerId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ - Query::equal('$id', [$providerId]), - Query::limit(1), - ])); + if ($cursor) { + $providerId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ + Query::equal('$id', [$providerId]), + Query::limit(1), + ])); - if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { - throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); + if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument[0]); } - $cursor->setValue($cursorDocument[0]); - } - - $filterQueries = Query::groupByType($queries)['filters']; - $response->dynamic(new Document([ - 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), - 'indexes' => $dbForProject->find('providers', $queries), - ]), Response::MODEL_PROVIDER_LIST); - }); + $filterQueries = Query::groupByType($queries)['filters']; + $response->dynamic(new Document([ + 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), + 'indexes' => $dbForProject->find('providers', $queries), + ]), Response::MODEL_PROVIDER_LIST); + }); App::get('/v1/messaging/providers/:id') - ->desc('Get Provider') - ->groups(['api', 'messaging']) - ->label('scope', 'providers.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'getProvider') - ->label('sdk.description', '/docs/references/messaging/get-provider.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', null, new UID(), 'Provider ID.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Get Provider') + ->groups(['api', 'messaging']) + ->label('scope', 'providers.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'getProvider') + ->label('sdk.description', '/docs/references/messaging/get-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', null, new UID(), 'Provider ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } - $response->dynamic($provider, Response::MODEL_PROVIDER); - }); + $response->dynamic($provider, Response::MODEL_PROVIDER); + }); /** * Email Providers */ App::post('/v1/messaging/providers/mailgun') - ->desc('Create Mailgun Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderMailgun') - ->label('sdk.description', '/docs/references/messaging/create-provider-mailgun.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('name', '', new Text(128), 'Provider name.') - ->param('apiKey', '', new Text(0), 'Mailgun API Key.') - ->param('domain', '', new Text(0), 'Mailgun Domain.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'mailgun', - 'type' => 'email', - 'credentials' => [ - 'apiKey' => $apiKey, - 'domain' => $domain, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + ->desc('Create Mailgun Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderMailgun') + ->label('sdk.description', '/docs/references/messaging/create-provider-mailgun.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('apiKey', '', new Text(0), 'Mailgun API Key.') + ->param('domain', '', new Text(0), 'Mailgun Domain.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'mailgun', + 'type' => 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + 'domain' => $domain, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::patch('/v1/messaging/providers/:id/mailgun') - ->desc('Update Mailgun Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderMailgun') - ->label('sdk.description', '/docs/references/messaging/update-provider-mailgun.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) - ->param('domain', '', new Text(0), 'Mailgun Domain.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Update Mailgun Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderMailgun') + ->label('sdk.description', '/docs/references/messaging/update-provider-mailgun.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) + ->param('domain', '', new Text(0), 'Mailgun Domain.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); - - if ($providerAttr !== 'mailgun') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } - - if ($name) { - $provider->setAttribute('name', $name); - } - - if ($apiKey || $domain) { - // Check if all five variables are present - if ($apiKey && $domain) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'domain' => $domain - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); } - } + $providerAttr = $provider->getAttribute('provider'); - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + if ($providerAttr !== 'mailgun') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($apiKey || $domain) { + // Check if all five variables are present + if ($apiKey && $domain) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'domain' => $domain, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::post('/v1/messaging/providers/sendgrid') - ->desc('Create Sendgrid Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderSendgrid') - ->label('sdk.description', '/docs/references/messaging/create-provider-sendgrid.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('name', '', new Text(128), 'Provider name.') - ->param('apiKey', '', new Text(0), 'Sendgrid API key.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $name, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'sendgrid', - 'type' => 'email', - 'credentials' => [ - 'apiKey' => $apiKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + ->desc('Create Sendgrid Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderSendgrid') + ->label('sdk.description', '/docs/references/messaging/create-provider-sendgrid.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('apiKey', '', new Text(0), 'Sendgrid API key.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'sendgrid', + 'type' => 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::patch('/v1/messaging/providers/:id/sendgrid') - ->desc('Update Sendgrid Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderSendgrid') - ->label('sdk.description', '/docs/references/messaging/update-provider-sendgrid.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Update Sendgrid Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderSendgrid') + ->label('sdk.description', '/docs/references/messaging/update-provider-sendgrid.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'sendgrid') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'sendgrid') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($apiKey) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey - ]); - } + if ($apiKey) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + ]); + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); /** * SMS Providers */ App::post('/v1/messaging/providers/msg91') - ->desc('Create Msg91 Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderMsg91') - ->label('sdk.description', '/docs/references/messaging/create-provider-msg91.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('name', '', new Text(128), 'Provider name.') - ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') - ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'msg91', - 'type' => 'sms', - 'credentials' => [ - 'senderId' => $senderId, - 'authKey' => $authKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + ->desc('Create Msg91 Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderMsg91') + ->label('sdk.description', '/docs/references/messaging/create-provider-msg91.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') + ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'msg91', + 'type' => 'sms', + 'credentials' => [ + 'senderId' => $senderId, + 'authKey' => $authKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::patch('/v1/messaging/providers/:id/msg91') - ->desc('Update Msg91 Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderMsg91') - ->label('sdk.description', '/docs/references/messaging/update-provider-msg91.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) - ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Update Msg91 Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderMsg91') + ->label('sdk.description', '/docs/references/messaging/update-provider-msg91.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) + ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); - - if ($providerAttr !== 'msg91') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } - - if ($name) { - $provider->setAttribute('name', $name); - } - - if ($senderId || $authKey) { - // Check if all five variables are present - if ($senderId && $authKey) { - $provider->setAttribute('credentials', [ - 'senderId' => $senderId, - 'authKey' => $authKey - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); } - } + $providerAttr = $provider->getAttribute('provider'); - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + if ($providerAttr !== 'msg91') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($senderId || $authKey) { + // Check if all five variables are present + if ($senderId && $authKey) { + $provider->setAttribute('credentials', [ + 'senderId' => $senderId, + 'authKey' => $authKey, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::post('/v1/messaging/providers/telesign') - ->desc('Create Telesign Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderTelesign') - ->label('sdk.description', '/docs/references/messaging/create-provider-telesign.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('name', '', new Text(128), 'Provider name.') - ->param('username', '', new Text(0), 'Telesign username.') - ->param('password', '', new Text(0), 'Telesign password.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $name, string $username, string $password, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'telesign', - 'type' => 'sms', - 'credentials' => [ - 'username' => $username, - 'password' => $password, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + ->desc('Create Telesign Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderTelesign') + ->label('sdk.description', '/docs/references/messaging/create-provider-telesign.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('username', '', new Text(0), 'Telesign username.') + ->param('password', '', new Text(0), 'Telesign password.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $username, string $password, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'telesign', + 'type' => 'sms', + 'credentials' => [ + 'username' => $username, + 'password' => $password, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::patch('/v1/messaging/providers/:id/telesign') - ->desc('Update Telesign Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderTelesign') - ->label('sdk.description', '/docs/references/messaging/update-provider-telesign.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('username', '', new Text(0), 'Telesign username.', true) - ->param('password', '', new Text(0), 'Telesign password.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, string $username, string $password, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Update Telesign Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderTelesign') + ->label('sdk.description', '/docs/references/messaging/update-provider-telesign.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('username', '', new Text(0), 'Telesign username.', true) + ->param('password', '', new Text(0), 'Telesign password.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $username, string $password, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); - - if ($providerAttr !== 'telesign') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } - - if ($name) { - $provider->setAttribute('name', $name); - } - - if ($username || $password) { - // Check if all five variables are present - if ($username && $password) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'password' => $password - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); } - } + $providerAttr = $provider->getAttribute('provider'); - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + if ($providerAttr !== 'telesign') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($username || $password) { + // Check if all five variables are present + if ($username && $password) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'password' => $password, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::post('/v1/messaging/providers/textmagic') - ->desc('Create Textmagic Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderTextmagic') - ->label('sdk.description', '/docs/references/messaging/create-provider-textmagic.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('name', '', new Text(128), 'Provider name.') - ->param('username', '', new Text(0), 'Textmagic username.') - ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'text-magic', - 'type' => 'sms', - 'credentials' => [ - 'username' => $username, - 'apiKey' => $apiKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + ->desc('Create Textmagic Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderTextmagic') + ->label('sdk.description', '/docs/references/messaging/create-provider-textmagic.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('username', '', new Text(0), 'Textmagic username.') + ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'text-magic', + 'type' => 'sms', + 'credentials' => [ + 'username' => $username, + 'apiKey' => $apiKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::patch('/v1/messaging/providers/:id/textmagic') - ->desc('Update Textmagic Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderTextmagic') - ->label('sdk.description', '/docs/references/messaging/update-provider-textmagic.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('username', '', new Text(0), 'Textmagic username.', true) - ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Update Textmagic Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderTextmagic') + ->label('sdk.description', '/docs/references/messaging/update-provider-textmagic.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('username', '', new Text(0), 'Textmagic username.', true) + ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); - - if ($providerAttr !== 'text-magic') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } - - if ($name) { - $provider->setAttribute('name', $name); - } - - if ($username || $apiKey) { - // Check if all five variables are present - if ($username && $apiKey) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'apiKey' => $apiKey - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); } - } + $providerAttr = $provider->getAttribute('provider'); - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + if ($providerAttr !== 'text-magic') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($username || $apiKey) { + // Check if all five variables are present + if ($username && $apiKey) { + $provider->setAttribute('credentials', [ + 'username' => $username, + 'apiKey' => $apiKey, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::post('/v1/messaging/providers/twilio') - ->desc('Create Twilio Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderTwilio') - ->label('sdk.description', '/docs/references/messaging/create-provider-twilio.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('name', '', new Text(128), 'Provider name.') - ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') - ->param('authToken', '', new Text(0), 'Twilio authentication token.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'twilio', - 'type' => 'sms', - 'credentials' => [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + ->desc('Create Twilio Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderTwilio') + ->label('sdk.description', '/docs/references/messaging/create-provider-twilio.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') + ->param('authToken', '', new Text(0), 'Twilio authentication token.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'twilio', + 'type' => 'sms', + 'credentials' => [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::patch('/v1/messaging/providers/:id/twilio') - ->desc('Update Twilio Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderTwilio') - ->label('sdk.description', '/docs/references/messaging/update-provider-twilio.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) - ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Update Twilio Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderTwilio') + ->label('sdk.description', '/docs/references/messaging/update-provider-twilio.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) + ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); - - if ($providerAttr !== 'twilio') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } - - if ($name) { - $provider->setAttribute('name', $name); - } - - if ($accountSid || $authToken) { - // Check if all five variables are present - if ($accountSid && $authToken) { - $provider->setAttribute('credentials', [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); } - } + $providerAttr = $provider->getAttribute('provider'); - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + if ($providerAttr !== 'twilio') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($accountSid || $authToken) { + // Check if all five variables are present + if ($accountSid && $authToken) { + $provider->setAttribute('credentials', [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::post('/v1/messaging/providers/vonage') - ->desc('Create Vonage Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderVonage') - ->label('sdk.description', '/docs/references/messaging/create-provider-vonage.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('name', '', new Text(128), 'Provider name.') - ->param('apiKey', '', new Text(0), 'Vonage API key.') - ->param('apiSecret', '', new Text(0), 'Vonage API secret.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'vonage', - 'type' => 'sms', - 'credentials' => [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + ->desc('Create Vonage Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderVonage') + ->label('sdk.description', '/docs/references/messaging/create-provider-vonage.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('apiKey', '', new Text(0), 'Vonage API key.') + ->param('apiSecret', '', new Text(0), 'Vonage API secret.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'vonage', + 'type' => 'sms', + 'credentials' => [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::patch('/v1/messaging/providers/:id/vonage') - ->desc('Update Vonage Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderVonage') - ->label('sdk.description', '/docs/references/messaging/update-provider-vonage.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('apiKey', '', new Text(0), 'Vonage API key.', true) - ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Update Vonage Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderVonage') + ->label('sdk.description', '/docs/references/messaging/update-provider-vonage.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('apiKey', '', new Text(0), 'Vonage API key.', true) + ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); - - if ($providerAttr !== 'vonage') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } - - if ($name) { - $provider->setAttribute('name', $name); - } - - if ($apiKey || $apiSecret) { - // Check if all five variables are present - if ($apiKey && $apiSecret) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); } - } + $providerAttr = $provider->getAttribute('provider'); - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + if ($providerAttr !== 'vonage') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($apiKey || $apiSecret) { + // Check if all five variables are present + if ($apiKey && $apiSecret) { + $provider->setAttribute('credentials', [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); /** * Push Providers */ App::post('/v1/messaging/providers/fcm') - ->desc('Create FCM Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderFCM') - ->label('sdk.description', '/docs/references/messaging/create-provider-fcm.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('name', '', new Text(128), 'Provider name.') - ->param('serverKey', '', new Text(0), 'FCM Server Key.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $name, string $serverKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'fcm', - 'type' => 'push', - 'credentials' => [ - 'serverKey' => $serverKey, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + ->desc('Create FCM Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderFCM') + ->label('sdk.description', '/docs/references/messaging/create-provider-fcm.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('serverKey', '', new Text(0), 'FCM Server Key.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $serverKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'fcm', + 'type' => 'push', + 'credentials' => [ + 'serverKey' => $serverKey, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::patch('/v1/messaging/providers/:id/fcm') - ->desc('Update FCM Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderFCM') - ->label('sdk.description', '/docs/references/messaging/update-provider-fcm.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, string $serverKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Update FCM Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderFCM') + ->label('sdk.description', '/docs/references/messaging/update-provider-fcm.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $serverKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'fcm') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } + if ($providerAttr !== 'fcm') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - if ($name) { - $provider->setAttribute('name', $name); - } + if ($name) { + $provider->setAttribute('name', $name); + } - if ($serverKey) { - $provider->setAttribute('credentials', ['serverKey' => $serverKey]); - } + if ($serverKey) { + $provider->setAttribute('credentials', ['serverKey' => $serverKey]); + } - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::post('/v1/messaging/providers/apns') - ->desc('Create APNS Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderAPNS') - ->label('sdk.description', '/docs/references/messaging/create-provider-apns.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('name', '', new Text(128), 'Provider name.') - ->param('authKey', '', new Text(0), 'APNS authentication key.') - ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') - ->param('teamId', '', new Text(0), 'APNS team ID.') - ->param('bundleId', '', new Text(0), 'APNS bundle ID.') - ->param('endpoint', '', new Text(0), 'APNS endpoint.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ - 'name' => $name, - 'provider' => 'apns', - 'type' => 'push', - 'credentials' => [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ], - ])); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + ->desc('Create APNS Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createProviderAPNS') + ->label('sdk.description', '/docs/references/messaging/create-provider-apns.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('name', '', new Text(128), 'Provider name.') + ->param('authKey', '', new Text(0), 'APNS authentication key.') + ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') + ->param('teamId', '', new Text(0), 'APNS team ID.') + ->param('bundleId', '', new Text(0), 'APNS bundle ID.') + ->param('endpoint', '', new Text(0), 'APNS endpoint.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + $provider = $dbForProject->createDocument('providers', new Document([ + 'name' => $name, + 'provider' => 'apns', + 'type' => 'push', + 'credentials' => [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ], + ])); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::patch('/v1/messaging/providers/:id/apns') - ->desc('Update APNS Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderAPNS') - ->label('sdk.description', '/docs/references/messaging/update-provider-apns.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('authKey', '', new Text(0), 'APNS authentication key.', true) - ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) - ->param('teamId', '', new Text(0), 'APNS team ID.', true) - ->param('bundleId', '', new Text(0), 'APNS bundle ID.', true) - ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Update APNS Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderAPNS') + ->label('sdk.description', '/docs/references/messaging/update-provider-apns.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('authKey', '', new Text(0), 'APNS authentication key.', true) + ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) + ->param('teamId', '', new Text(0), 'APNS team ID.', true) + ->param('bundleId', '', new Text(0), 'APNS bundle ID.', true) + ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - $providerAttr = $provider->getAttribute('provider'); - - if ($providerAttr !== 'apns') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); - } - - if ($name) { - $provider->setAttribute('name', $name); - } - - if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { - // Check if all five variables are present - if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { - $provider->setAttribute('credentials', [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); } - } + $providerAttr = $provider->getAttribute('provider'); - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); + if ($providerAttr !== 'apns') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + } - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); + if ($name) { + $provider->setAttribute('name', $name); + } + + if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { + // Check if all five variables are present + if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { + $provider->setAttribute('credentials', [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ]); + } else { + // Not all credential params are present + throw new Exception(Exception::DOCUMENT_MISSING_DATA); + } + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); App::delete('/v1/messaging/providers/:id') - ->desc('Delete Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.delete') - ->label('audits.resource', 'providers/{request.id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'deleteProvider') - ->label('sdk.description', '/docs/references/messaging/delete-provider.md') - ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_NONE) - ->param('id', '', new UID(), 'Provider ID.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->desc('Delete Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.delete') + ->label('audits.resource', 'providers/{request.id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'deleteProvider') + ->label('sdk.description', '/docs/references/messaging/delete-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('id', '', new UID(), 'Provider ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } - $dbForProject->deleteCachedDocument('providers', $provider->getId()); - $dbForProject->deleteDocument('providers', $provider->getId()); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + $dbForProject->deleteDocument('providers', $provider->getId()); - $response->noContent(); - }); + $response->noContent(); + }); App::post('/v1/messaging/messages/email') - ->desc('Send an email.') - ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.create') - ->label('audits.resource', 'messages/{response.$id}') - ->label('scope', 'messages.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'sendEmail') - ->label('sdk.description', '/docs/references/messaging/send-email.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_MESSAGE) - ->param('providerId', '', new Text(128), 'Email Provider ID.') - ->param('to', [], new ArrayList(new Text(0)), 'Email Recepient.', true) - ->param('subject', null, new Text(0), 'Email Subject.', true) - ->param('content', null, new Text(0), 'Email Content.', true) - ->param('from', null, new Text(0), 'Email from.', false) - ->param('html', null, new Text(0), 'Is content of type HTML', false) - ->param('deliveryTime', null, new Datetime(), 'Delivery time of the message', false) - ->inject('dbForProject') - ->inject('events') - ->inject('response') - ->action(function (string $providerId, string $to, string $subject, string $content, string $from, string $html, DateTime $deliveryTime, Database $dbForProject, Event $eventsInstance, Response $response) { - $provider = $dbForProject->getDocument('providers', $providerId); + ->desc('Send an email.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.create') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'sendEmail') + ->label('sdk.description', '/docs/references/messaging/send-email.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('providerId', '', new Text(128), 'Email Provider ID.') + ->param('to', [], new ArrayList(new Text(0)), 'Email Recepient.', true) + ->param('subject', null, new Text(0), 'Email Subject.', true) + ->param('content', null, new Text(0), 'Email Content.', true) + ->param('from', null, new Text(0), 'Email from.', false) + ->param('html', null, new Text(0), 'Is content of type HTML', false) + ->param('deliveryTime', null, new Datetime(), 'Delivery time of the message', false) + ->inject('dbForProject') + ->inject('events') + ->inject('response') + ->action(function (string $providerId, string $to, string $subject, string $content, string $from, string $html, DateTime $deliveryTime, Database $dbForProject, Event $eventsInstance, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } - $message = $dbForProject->createDocument('messages', new Document([ - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), - 'to' => $to, - 'data' => [ - 'subject' => $subject, - 'content' => $content, - ], - 'deliveryTime' => $deliveryTime, - 'deliveryError' => null, - 'deliveredTo' => null, - 'delivered' => false, - 'search' => null, - ])); + $message = $dbForProject->createDocument('messages', new Document([ + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'to' => $to, + 'data' => [ + 'subject' => $subject, + 'content' => $content, + ], + 'deliveryTime' => $deliveryTime, + 'deliveryError' => null, + 'deliveredTo' => null, + 'delivered' => false, + 'search' => null, + ])); - $eventsInstance->setParam('messageId', $message->getId()); + $eventsInstance->setParam('messageId', $message->getId()); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_MESSAGE); - }); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_MESSAGE); + }); From a87745f685185ab9621cb54f816b03887ba56170 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 24 Aug 2023 15:37:59 +0530 Subject: [PATCH 039/196] fix tests --- tests/e2e/Services/Account/AccountBase.php | 3 +- .../Account/AccountCustomClientTest.php | 131 ++++++++++++++++++ 2 files changed, 132 insertions(+), 2 deletions(-) diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index c611b6e920..6e039b509a 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -359,11 +359,10 @@ trait AccountBase 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); - $this->assertEquals($response['headers']['status-code'], 200); $this->assertIsArray($response['body']['logs']); $this->assertNotEmpty($response['body']['logs']); - $this->assertCount(5, $response['body']['logs']); + $this->assertCount(3, $response['body']['logs']); $this->assertIsNumeric($response['body']['total']); $this->assertContains($response['body']['logs'][1]['event'], ["session.create"]); $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 39fa8d0fa5..6dce5d8f59 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -1205,4 +1205,135 @@ class AccountCustomClientTest extends Scope return $data; } + + /** + * @depends testCreateAccountSession + */ + public function testGetAccountLogs($data): array + { + sleep(10); + $session = $data['session'] ?? ''; + $sessionId = $data['sessionId'] ?? ''; + $userId = $data['id'] ?? ''; + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); + $this->assertEquals($response['headers']['status-code'], 200); + $this->assertIsArray($response['body']['logs']); + $this->assertNotEmpty($response['body']['logs']); + $this->assertCount(5, $response['body']['logs']); + $this->assertIsNumeric($response['body']['total']); + $this->assertContains($response['body']['logs'][1]['event'], ["targets.create"]); + $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); + $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['logs'][1]['time'])); + + $this->assertEquals('Windows', $response['body']['logs'][1]['osName']); + $this->assertEquals('WIN', $response['body']['logs'][1]['osCode']); + $this->assertEquals('10', $response['body']['logs'][1]['osVersion']); + + $this->assertEquals('browser', $response['body']['logs'][1]['clientType']); + $this->assertEquals('Chrome', $response['body']['logs'][1]['clientName']); + $this->assertEquals('CH', $response['body']['logs'][1]['clientCode']); + $this->assertEquals('70.0', $response['body']['logs'][1]['clientVersion']); + $this->assertEquals('Blink', $response['body']['logs'][1]['clientEngine']); + + $this->assertEquals('desktop', $response['body']['logs'][1]['deviceName']); + $this->assertEquals('', $response['body']['logs'][1]['deviceBrand']); + $this->assertEquals('', $response['body']['logs'][1]['deviceModel']); + $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); + + $this->assertEquals('--', $response['body']['logs'][1]['countryCode']); + $this->assertEquals('Unknown', $response['body']['logs'][1]['countryName']); + + $this->assertContains($response['body']['logs'][2]['event'], ["session.create"]); + $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); + $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['logs'][2]['time'])); + + $this->assertEquals('Windows', $response['body']['logs'][2]['osName']); + $this->assertEquals('WIN', $response['body']['logs'][2]['osCode']); + $this->assertEquals('10', $response['body']['logs'][2]['osVersion']); + + $this->assertEquals('browser', $response['body']['logs'][2]['clientType']); + $this->assertEquals('Chrome', $response['body']['logs'][2]['clientName']); + $this->assertEquals('CH', $response['body']['logs'][2]['clientCode']); + $this->assertEquals('70.0', $response['body']['logs'][2]['clientVersion']); + $this->assertEquals('Blink', $response['body']['logs'][2]['clientEngine']); + + $this->assertEquals('desktop', $response['body']['logs'][2]['deviceName']); + $this->assertEquals('', $response['body']['logs'][2]['deviceBrand']); + $this->assertEquals('', $response['body']['logs'][2]['deviceModel']); + $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); + + $this->assertEquals('--', $response['body']['logs'][2]['countryCode']); + $this->assertEquals('Unknown', $response['body']['logs'][2]['countryName']); + + $responseLimit = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]), [ + 'queries' => [ 'limit(1)' ], + ]); + + $this->assertEquals($responseLimit['headers']['status-code'], 200); + $this->assertIsArray($responseLimit['body']['logs']); + $this->assertNotEmpty($responseLimit['body']['logs']); + $this->assertCount(1, $responseLimit['body']['logs']); + $this->assertIsNumeric($responseLimit['body']['total']); + + $this->assertEquals($response['body']['logs'][0], $responseLimit['body']['logs'][0]); + + $responseOffset = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]), [ + 'queries' => [ 'offset(1)' ], + ]); + + $this->assertEquals($responseOffset['headers']['status-code'], 200); + $this->assertIsArray($responseOffset['body']['logs']); + $this->assertNotEmpty($responseOffset['body']['logs']); + $this->assertCount(4, $responseOffset['body']['logs']); + $this->assertIsNumeric($responseOffset['body']['total']); + + $this->assertEquals($response['body']['logs'][1], $responseOffset['body']['logs'][0]); + + $responseLimitOffset = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]), [ + 'queries' => [ 'limit(1)', 'offset(1)' ], + ]); + + $this->assertEquals($responseLimitOffset['headers']['status-code'], 200); + $this->assertIsArray($responseLimitOffset['body']['logs']); + $this->assertNotEmpty($responseLimitOffset['body']['logs']); + $this->assertCount(1, $responseLimitOffset['body']['logs']); + $this->assertIsNumeric($responseLimitOffset['body']['total']); + + $this->assertEquals($response['body']['logs'][1], $responseLimitOffset['body']['logs'][0]); + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ])); + + $this->assertEquals($response['headers']['status-code'], 401); + + return $data; + } } From df77f92860fc61683777007f0666e766c4e1773d Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 25 Aug 2023 01:22:16 +0530 Subject: [PATCH 040/196] adds sub query for targets and topics, permission for user target --- app/config/collections.php | 60 +++++++++++++-------------------- app/controllers/api/account.php | 2 +- app/controllers/api/users.php | 5 +-- app/init.php | 47 ++++++++++++++++++++++---- 4 files changed, 68 insertions(+), 46 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index c9005f8217..f066c38c70 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1664,6 +1664,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('targets'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => true, + 'filters' => ['subQueryTargets'], + ] ], 'indexes' => [ [ @@ -1702,28 +1713,6 @@ $commonCollections = [ '$id' => ID::custom('subscribers'), 'name' => 'Subscribers', 'attributes' => [ - [ - '$id' => ID::custom('userId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('userInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('targetId'), 'type' => Database::VAR_STRING, @@ -1770,20 +1759,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_userId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_userInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userInternalId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_targetId'), 'type' => Database::INDEX_KEY, @@ -1886,6 +1861,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('topics'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => true, + 'filters' => ['subQueryTopics'], + ] ], 'indexes' => [ [ @@ -1924,7 +1910,7 @@ $commonCollections = [ 'orders' => [], ], ], - ] + ], ]; $projectCollections = array_merge([ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 44a3bb9740..efcef85b68 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -3038,7 +3038,7 @@ App::post('/v1/account/targets') $target = $dbForProject->createDocument('targets', new Document([ '$id' => $targetId, '$permissions' => [ - Permission::read(Role::user($user->getId())), + Permission::read(Role::any()), Permission::update(Role::user($user->getId())), Permission::delete(Role::user($user->getId())), ], diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index e7affffdc0..5218057018 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -414,9 +414,10 @@ App::post('/v1/users/:userId/targets') $target = $dbForProject->createDocument('targets', new Document([ '$id' => $targetId, - // TO DO: what permissions should be given when created a target. '$permissions' => [ - Permission::read(Role::any()) + Permission::read(Role::any()), + Permission::update(Role::user($userId)), + Permission::delete(Role::user($userId)), ], 'providerId' => $providerId, 'providerInternalId' => $provider->getInternalId(), diff --git a/app/init.php b/app/init.php index 09b383c3a0..a71df23bf0 100644 --- a/app/init.php +++ b/app/init.php @@ -542,12 +542,13 @@ Database::addFilter( return null; }, function (mixed $value, Document $document, Database $database) { - $provider = Authorization::skip(fn() => $database - ->findOne('providers', [ - Query::equal('$id', [$document->getAttribute('providerId')]), - Query::select(['type']), - Query::limit(APP_LIMIT_SUBQUERY), - ])); + $provider = Authorization::skip(fn () => $database + ->getDocument( + 'providers', + $document->getAttribute('providerId'), + [Query::select(['type'])] + ) + ); if ($provider) { return $provider->getAttribute('type'); } @@ -555,6 +556,40 @@ Database::addFilter( } ); +Database::addFilter( + 'subQueryTopics', + function (mixed $value) { + return null; + }, + function (mixed $value, Document $document, Database $database) { + $topicIds = Authorization::skip(fn () => \array_map( + fn ($document) => $document->getAttribute('topicId'), $database + ->find('subscribers', [ + Query::equal('targetInternalId', [$document->getInternalId()]), + Query::limit(APP_LIMIT_SUBQUERY), + ])) + ); + return $database->find('topics', [Query::equal('$id', $topicIds)]); + } +); + +Database::addFilter( + 'subQueryTargets', + function (mixed $value) { + return null; + }, + function (mixed $value, Document $document, Database $database) { + $targetIds = Authorization::skip(fn () => \array_map( + fn ($document) => $document->getAttribute('targetId'), $database + ->find('subscribers', [ + Query::equal('topicInternalId', [$document->getInternalId()]), + Query::limit(APP_LIMIT_SUBQUERY), + ])) + ); + return $database->find('targets', [Query::equal('$id', $targetIds)]); + } +); + /** * DB Formats */ From 52f6b72f2377ccd15dc4bb86bdcf63c1061afc4b Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 25 Aug 2023 01:45:17 +0530 Subject: [PATCH 041/196] adds topic controllers --- app/config/errors.php | 9 +- app/controllers/api/messaging.php | 210 +++++++++++++++++- app/init.php | 21 +- src/Appwrite/Extend/Exception.php | 3 + .../Database/Validator/Queries/Topics.php | 20 ++ 5 files changed, 242 insertions(+), 21 deletions(-) create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Topics.php diff --git a/app/config/errors.php b/app/config/errors.php index b4b2429f31..97b5f0661c 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -707,5 +707,12 @@ return [ 'name' => Exception::PROVIDER_INCORRECT_TYPE, 'description' => 'Provider with the request ID is of incorrect type: ', 'code' => 400, - ] + ], + + /** Topic Errors */ + Exception::TOPIC_NOT_FOUND => [ + 'name' => Exception::TOPIC_NOT_FOUND, + 'description' => 'Provider with the request ID could not be found.', + 'code' => 404, + ], ]; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 753abc8432..df7744f798 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -2,11 +2,15 @@ use Appwrite\Event\Event; use Appwrite\Extend\Exception; +use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Database\Validator\Queries\Providers; +use Appwrite\Utopia\Database\Validator\Queries\Topics; use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Helpers\Permission; +use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime; @@ -25,7 +29,7 @@ App::get('/v1/messaging/providers') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER_LIST) - ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) ->inject('dbForProject') ->inject('response') ->action(function (array $queries, Database $dbForProject, Response $response) { @@ -144,7 +148,7 @@ App::patch('/v1/messaging/providers/:id/mailgun') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'mailgun') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -229,7 +233,7 @@ App::patch('/v1/messaging/providers/:id/sendgrid') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'sendgrid') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -313,7 +317,7 @@ App::patch('/v1/messaging/providers/:id/msg91') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'msg91') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -401,7 +405,7 @@ App::patch('/v1/messaging/providers/:id/telesign') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'telesign') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -489,7 +493,7 @@ App::patch('/v1/messaging/providers/:id/textmagic') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'text-magic') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -577,7 +581,7 @@ App::patch('/v1/messaging/providers/:id/twilio') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'twilio') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -665,7 +669,7 @@ App::patch('/v1/messaging/providers/:id/vonage') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'vonage') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -753,7 +757,7 @@ App::patch('/v1/messaging/providers/:id/fcm') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'fcm') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -841,7 +845,7 @@ App::patch('/v1/messaging/providers/:id/apns') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'apns') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -900,6 +904,192 @@ App::delete('/v1/messaging/providers/:id') $response->noContent(); }); +App::get('/v1/messaging/topics') + ->desc('List topics.') + ->groups(['api', 'messaging']) + ->label('scope', 'topics.read') + ->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', 'listTopics') + ->label('sdk.description', '/docs/references/messaging/list-topics.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TOPIC_LIST) + ->param('queries', [], new Topics(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Topics::ALLOWED_ATTRIBUTES), true) + ->inject('dbForProject') + ->inject('response') + ->action(function (array $queries, Database $dbForProject, Response $response) { + $queries = Query::parseQueries($queries); + + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); + + if ($cursor) { + $topicId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('topics', [ + Query::equal('$id', [$topicId]), + Query::limit(1), + ])); + + if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Topic '{$topicId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument[0]); + } + + $filterQueries = Query::groupByType($queries)['filters']; + $response->dynamic(new Document([ + 'total' => $dbForProject->count('topics', $filterQueries, APP_LIMIT_COUNT), + 'indexes' => $dbForProject->find('topics', $queries), + ]), Response::MODEL_TOPIC_LIST); + }); + +App::get('/v1/messaging/topics/:id') + ->desc('Get a topic.') + ->groups(['api', 'messaging']) + ->label('scope', 'topics.read') + ->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', 'getTopic') + ->label('sdk.description', '/docs/references/messaging/get-topic.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TOPIC) + ->param('id', '', new UID(), 'Topic ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, Database $dbForProject, Response $response) { + $topic = $dbForProject->getDocument('topics', $id); + + if ($topic->isEmpty()) { + throw new Exception(Exception::TOPIC_NOT_FOUND); + } + + $topic = $dbForProject->getDocument('topics', $id); + + $response + ->dynamic($topic, Response::MODEL_TOPIC); + }); + +App::post('/v1/messaging/topics') + ->desc('Create a topic.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'topics.create') + ->label('audits.resource', 'topics/{response.$id}') + ->label('scope', 'topics.write') + ->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', 'createTopic') + ->label('sdk.description', '/docs/references/messaging/create-topic.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TOPIC) + ->param('id', '', new CustomId(), 'Topic ID. Choose a custom Topic ID or a new Topic ID.') + ->param('providerId', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Topic Name.') + ->param('description', '', new Text(2048), 'Topic Description.', true) + ->inject('user') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $providerId, string $name, string $description, Document $user, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $topic = new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], + 'providerId' => $providerId, + 'providerInternalId' => $provider->getInternalId(), + 'name' => $name, + + ]); + + if ($description) { + $topic->setAttribute('description', $description); + } + + $topic = $dbForProject->createDocument('topics', $topic); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($topic, Response::MODEL_TOPIC); + }); + +App::patch('/v1/messaging/topics/:id') + ->desc('Update a topic.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'topics.update') + ->label('audits.resource', 'topics/{response.$id}') + ->label('scope', 'topics.write') + ->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', 'updateTopic') + ->label('sdk.description', '/docs/references/messaging/update-topic.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TOPIC) + ->param('id', '', new UID(), 'Topic ID.') + ->param('name', '', new Text(128), 'Topic Name.', true) + ->param('description', null, new Text(128), 'Topic Description.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, string $description, Database $dbForProject, Response $response) { + $topic = $dbForProject->getDocument('topics', $id); + + if ($topic->isEmpty()) { + throw new Exception(Exception::TOPIC_NOT_FOUND); + } + + if ($name) { + $topic->setAttribute('name', $name); + } + + if ($description) { + $topic->setAttribute('description', $description); + } + + $topic = $dbForProject->updateDocument('topics', $id, $topic); + + $response + ->dynamic($topic, Response::MODEL_TOPIC); + }); + +App::delete('/v1/messaging/topics/:id') + ->desc('Delete a topic.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'topics.delete') + ->label('audits.resource', 'topics/{request.id}') + ->label('scope', 'topics.write') + ->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', 'deleteTopic') + ->label('sdk.description', '/docs/references/messaging/delete-topic.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('id', '', new UID(), 'Topic ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, Database $dbForProject, Response $response) { + $topic = $dbForProject->getDocument('topics', $id); + + if ($topic->isEmpty()) { + throw new Exception(Exception::TOPIC_NOT_FOUND); + } + + $topic = $dbForProject->deleteDocument('topics', $id); + $response->noContent(); + }); + App::post('/v1/messaging/messages/email') ->desc('Send an email.') ->groups(['api', 'messaging']) diff --git a/app/init.php b/app/init.php index a71df23bf0..fa026df4cf 100644 --- a/app/init.php +++ b/app/init.php @@ -544,11 +544,10 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { $provider = Authorization::skip(fn () => $database ->getDocument( - 'providers', - $document->getAttribute('providerId'), + 'providers', + $document->getAttribute('providerId'), [Query::select(['type'])] - ) - ); + )); if ($provider) { return $provider->getAttribute('type'); } @@ -563,12 +562,13 @@ Database::addFilter( }, function (mixed $value, Document $document, Database $database) { $topicIds = Authorization::skip(fn () => \array_map( - fn ($document) => $document->getAttribute('topicId'), $database + fn ($document) => $document->getAttribute('topicId'), + $database ->find('subscribers', [ Query::equal('targetInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), - ])) - ); + ]) + )); return $database->find('topics', [Query::equal('$id', $topicIds)]); } ); @@ -580,12 +580,13 @@ Database::addFilter( }, function (mixed $value, Document $document, Database $database) { $targetIds = Authorization::skip(fn () => \array_map( - fn ($document) => $document->getAttribute('targetId'), $database + fn ($document) => $document->getAttribute('targetId'), + $database ->find('subscribers', [ Query::equal('topicInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), - ])) - ); + ]) + )); return $database->find('targets', [Query::equal('$id', $targetIds)]); } ); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 5ab806b254..4b5cac24a8 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -217,6 +217,9 @@ class Exception extends \Exception public const PROVIDER_NOT_FOUND = 'provider_not_found'; public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; + /** Topic */ + public const TOPIC_NOT_FOUND = 'topic_not_found'; + protected $type = ''; protected $errors = []; diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Topics.php b/src/Appwrite/Utopia/Database/Validator/Queries/Topics.php new file mode 100644 index 0000000000..120b3edc3f --- /dev/null +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Topics.php @@ -0,0 +1,20 @@ + Date: Fri, 25 Aug 2023 02:32:51 +0530 Subject: [PATCH 042/196] adds custom id for provider controlers, fixes subquery --- app/controllers/api/messaging.php | 121 +++++++++++++++--- app/init.php | 10 +- .../Messaging/MessagingServerTest.php | 13 +- 3 files changed, 122 insertions(+), 22 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 753abc8432..c08d772ef4 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -2,11 +2,15 @@ use Appwrite\Event\Event; use Appwrite\Extend\Exception; +use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Database\Validator\Queries\Providers; use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Helpers\ID; +use Utopia\Database\Helpers\Permission; +use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime; @@ -96,13 +100,22 @@ App::post('/v1/messaging/providers/mailgun') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Mailgun API Key.') ->param('domain', '', new Text(0), 'Mailgun Domain.') + ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ + ->action(function (string $id, string $name, string $apiKey, string $domain, Document $user, Database $dbForProject, Response $response) { + $id = $id == 'unique()' ? ID::unique() : $id; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'name' => $name, 'provider' => 'mailgun', 'type' => 'email', @@ -184,12 +197,21 @@ App::post('/v1/messaging/providers/sendgrid') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Sendgrid API key.') + ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $name, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ + ->action(function (string $id, string $name, string $apiKey, Document $user, Database $dbForProject, Response $response) { + $id = $id == 'unique()' ? ID::unique() : $id; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'name' => $name, 'provider' => 'sendgrid', 'type' => 'email', @@ -265,13 +287,22 @@ App::post('/v1/messaging/providers/msg91') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') + ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ + ->action(function (string $id, string $name, string $senderId, string $authKey, Document $user, Database $dbForProject, Response $response) { + $id = $id == 'unique()' ? ID::unique() : $id; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'name' => $name, 'provider' => 'msg91', 'type' => 'sms', @@ -353,13 +384,22 @@ App::post('/v1/messaging/providers/telesign') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') + ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $name, string $username, string $password, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ + ->action(function (string $id, string $name, string $username, string $password, Document $user, Database $dbForProject, Response $response) { + $id = $id == 'unique()' ? ID::unique() : $id; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'name' => $name, 'provider' => 'telesign', 'type' => 'sms', @@ -441,13 +481,22 @@ App::post('/v1/messaging/providers/textmagic') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('username', '', new Text(0), 'Textmagic username.') ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') + ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ + ->action(function (string $id, string $name, string $username, string $apiKey, Document $user, Database $dbForProject, Response $response) { + $id = $id == 'unique()' ? ID::unique() : $id; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'name' => $name, 'provider' => 'text-magic', 'type' => 'sms', @@ -529,13 +578,22 @@ App::post('/v1/messaging/providers/twilio') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') + ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ + ->action(function (string $id, string $name, string $accountSid, string $authToken, Document $user, Database $dbForProject, Response $response) { + $id = $id == 'unique()' ? ID::unique() : $id; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'name' => $name, 'provider' => 'twilio', 'type' => 'sms', @@ -617,13 +675,22 @@ App::post('/v1/messaging/providers/vonage') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') + ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ + ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Document $user, Database $dbForProject, Response $response) { + $id = $id == 'unique()' ? ID::unique() : $id; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'name' => $name, 'provider' => 'vonage', 'type' => 'sms', @@ -708,12 +775,21 @@ App::post('/v1/messaging/providers/fcm') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('serverKey', '', new Text(0), 'FCM Server Key.') + ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $name, string $serverKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ + ->action(function (string $id, string $name, string $serverKey, Document $user, Database $dbForProject, Response $response) { +$id = $id == 'unique()' ? ID::unique() : $id; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'name' => $name, 'provider' => 'fcm', 'type' => 'push', @@ -784,16 +860,25 @@ App::post('/v1/messaging/providers/apns') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('authKey', '', new Text(0), 'APNS authentication key.') ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') ->param('teamId', '', new Text(0), 'APNS team ID.') ->param('bundleId', '', new Text(0), 'APNS bundle ID.') ->param('endpoint', '', new Text(0), 'APNS endpoint.') + ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $provider = $dbForProject->createDocument('providers', new Document([ + ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Document $user, Database $dbForProject, Response $response) { + $id = $id == 'unique()' ? ID::unique() : $id; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $id, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'name' => $name, 'provider' => 'apns', 'type' => 'push', diff --git a/app/init.php b/app/init.php index a71df23bf0..0b5b75ee92 100644 --- a/app/init.php +++ b/app/init.php @@ -569,7 +569,10 @@ Database::addFilter( Query::limit(APP_LIMIT_SUBQUERY), ])) ); - return $database->find('topics', [Query::equal('$id', $topicIds)]); + if (\count($topicIds) > 0) { + return $database->find('topics', [Query::equal('$id', $topicIds)]); + } + return []; } ); @@ -586,7 +589,10 @@ Database::addFilter( Query::limit(APP_LIMIT_SUBQUERY), ])) ); - return $database->find('targets', [Query::equal('$id', $targetIds)]); + if (\count($targetIds) > 0) { + return $database->find('targets', [Query::equal('$id', $targetIds)]); + } + return []; } ); diff --git a/tests/e2e/Services/Messaging/MessagingServerTest.php b/tests/e2e/Services/Messaging/MessagingServerTest.php index 7b93ab29ac..0724b6dd2c 100644 --- a/tests/e2e/Services/Messaging/MessagingServerTest.php +++ b/tests/e2e/Services/Messaging/MessagingServerTest.php @@ -16,44 +16,53 @@ class MessagingServerTest extends Scope { $providersParams = [ 'sendgrid' => [ + 'id' => 'unique()', 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', ], 'mailgun' => [ + 'id' => 'unique()', 'name' => 'Mailgun1', 'apiKey' => 'my-apikey', 'domain' => 'my-domain', ], 'twilio' => [ + 'id' => 'unique()', 'name' => 'Twilio1', 'accountSid' => 'my-accountSid', 'authToken' => 'my-authToken', ], 'telesign' => [ + 'id' => 'unique()', 'name' => 'Telesign1', 'username' => 'my-username', 'password' => 'my-password', ], 'textmagic' => [ + 'id' => 'unique()', 'name' => 'Textmagic1', 'username' => 'my-username', 'apiKey' => 'my-apikey', ], 'msg91' => [ + 'id' => 'unique()', 'name' => 'Ms91-1', 'senderId' => 'my-senderid', 'authKey' => 'my-authkey', ], 'vonage' => [ + 'id' => 'unique()', 'name' => 'Vonage1', 'apiKey' => 'my-apikey', 'apiSecret' => 'my-apisecret', ], 'fcm' => [ + 'id' => 'unique()', 'name' => 'FCM1', 'serverKey' => 'my-serverkey', ], 'apns' => [ + 'id' => 'unique()', 'name' => 'APNS1', 'authKey' => 'my-authkey', 'authKeyId' => 'my-authkeyid', @@ -65,11 +74,11 @@ class MessagingServerTest extends Scope $providers = []; foreach (\array_keys($providersParams) as $key) { - $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/' . $key, [ + $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/' . $key, \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], - ], $providersParams[$key]); + ],$this->getHeaders()), $providersParams[$key]); \array_push($providers, $response['body']); $this->assertEquals(201, $response['headers']['status-code']); $this->assertEquals($providersParams[$key]['name'], $response['body']['name']); From 048e8e81ba3ae59a2152ddad58ade4f3cdcc4107 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 25 Aug 2023 02:59:06 +0530 Subject: [PATCH 043/196] removes permission from provider controllers --- app/controllers/api/messaging.php | 90 ++++--------------- .../Messaging/MessagingServerTest.php | 5 +- 2 files changed, 20 insertions(+), 75 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index c08d772ef4..f391eef5ba 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -104,19 +104,13 @@ App::post('/v1/messaging/providers/mailgun') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Mailgun API Key.') ->param('domain', '', new Text(0), 'Mailgun Domain.') - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $apiKey, string $domain, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { $id = $id == 'unique()' ? ID::unique() : $id; $provider = $dbForProject->createDocument('providers', new Document([ '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'name' => $name, + 'name' => $name, 'provider' => 'mailgun', 'type' => 'email', 'credentials' => [ @@ -200,19 +194,13 @@ App::post('/v1/messaging/providers/sendgrid') ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Sendgrid API key.') - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $apiKey, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, string $apiKey, Database $dbForProject, Response $response) { $id = $id == 'unique()' ? ID::unique() : $id; $provider = $dbForProject->createDocument('providers', new Document([ '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'name' => $name, + 'name' => $name, 'provider' => 'sendgrid', 'type' => 'email', 'credentials' => [ @@ -291,19 +279,13 @@ App::post('/v1/messaging/providers/msg91') ->param('name', '', new Text(128), 'Provider name.') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $senderId, string $authKey, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { $id = $id == 'unique()' ? ID::unique() : $id; $provider = $dbForProject->createDocument('providers', new Document([ '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'name' => $name, + 'name' => $name, 'provider' => 'msg91', 'type' => 'sms', 'credentials' => [ @@ -388,19 +370,13 @@ App::post('/v1/messaging/providers/telesign') ->param('name', '', new Text(128), 'Provider name.') ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $username, string $password, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, string $username, string $password, Database $dbForProject, Response $response) { $id = $id == 'unique()' ? ID::unique() : $id; $provider = $dbForProject->createDocument('providers', new Document([ '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'name' => $name, + 'name' => $name, 'provider' => 'telesign', 'type' => 'sms', 'credentials' => [ @@ -485,19 +461,13 @@ App::post('/v1/messaging/providers/textmagic') ->param('name', '', new Text(128), 'Provider name.') ->param('username', '', new Text(0), 'Textmagic username.') ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $username, string $apiKey, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { $id = $id == 'unique()' ? ID::unique() : $id; $provider = $dbForProject->createDocument('providers', new Document([ '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'name' => $name, + 'name' => $name, 'provider' => 'text-magic', 'type' => 'sms', 'credentials' => [ @@ -582,19 +552,13 @@ App::post('/v1/messaging/providers/twilio') ->param('name', '', new Text(128), 'Provider name.') ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $accountSid, string $authToken, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { $id = $id == 'unique()' ? ID::unique() : $id; $provider = $dbForProject->createDocument('providers', new Document([ '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'name' => $name, + 'name' => $name, 'provider' => 'twilio', 'type' => 'sms', 'credentials' => [ @@ -679,19 +643,13 @@ App::post('/v1/messaging/providers/vonage') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { $id = $id == 'unique()' ? ID::unique() : $id; $provider = $dbForProject->createDocument('providers', new Document([ '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'name' => $name, + 'name' => $name, 'provider' => 'vonage', 'type' => 'sms', 'credentials' => [ @@ -778,19 +736,13 @@ App::post('/v1/messaging/providers/fcm') ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('serverKey', '', new Text(0), 'FCM Server Key.') - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $serverKey, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, string $serverKey, Database $dbForProject, Response $response) { $id = $id == 'unique()' ? ID::unique() : $id; $provider = $dbForProject->createDocument('providers', new Document([ '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'name' => $name, + 'name' => $name, 'provider' => 'fcm', 'type' => 'push', 'credentials' => [ @@ -867,19 +819,13 @@ App::post('/v1/messaging/providers/apns') ->param('teamId', '', new Text(0), 'APNS team ID.') ->param('bundleId', '', new Text(0), 'APNS bundle ID.') ->param('endpoint', '', new Text(0), 'APNS endpoint.') - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { $id = $id == 'unique()' ? ID::unique() : $id; $provider = $dbForProject->createDocument('providers', new Document([ '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'name' => $name, + 'name' => $name, 'provider' => 'apns', 'type' => 'push', 'credentials' => [ diff --git a/tests/e2e/Services/Messaging/MessagingServerTest.php b/tests/e2e/Services/Messaging/MessagingServerTest.php index 0724b6dd2c..74855bc4a6 100644 --- a/tests/e2e/Services/Messaging/MessagingServerTest.php +++ b/tests/e2e/Services/Messaging/MessagingServerTest.php @@ -5,12 +5,12 @@ namespace Tests\E2E\Services\Messaging; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\SideConsole; +use Tests\E2E\Scopes\SideServer; class MessagingServerTest extends Scope { use ProjectCustom; - use SideConsole; + use SideServer; public function testCreateProviders(): array { @@ -77,7 +77,6 @@ class MessagingServerTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/' . $key, \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], ],$this->getHeaders()), $providersParams[$key]); \array_push($providers, $response['body']); $this->assertEquals(201, $response['headers']['status-code']); From 596066606831630ed0b237eb11ee958de89074c1 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 25 Aug 2023 03:09:12 +0530 Subject: [PATCH 044/196] added messaging base test --- ...{MessagingServerTest.php => MessagingBase.php} | 15 +++++---------- .../Messaging/MessagingCustomServerTest.php | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) rename tests/e2e/Services/Messaging/{MessagingServerTest.php => MessagingBase.php} (95%) create mode 100644 tests/e2e/Services/Messaging/MessagingCustomServerTest.php diff --git a/tests/e2e/Services/Messaging/MessagingServerTest.php b/tests/e2e/Services/Messaging/MessagingBase.php similarity index 95% rename from tests/e2e/Services/Messaging/MessagingServerTest.php rename to tests/e2e/Services/Messaging/MessagingBase.php index 74855bc4a6..8a0937c0eb 100644 --- a/tests/e2e/Services/Messaging/MessagingServerTest.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -3,16 +3,10 @@ namespace Tests\E2E\Services\Messaging; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\SideServer; -class MessagingServerTest extends Scope +trait MessagingBase { - use ProjectCustom; - use SideServer; - - public function testCreateProviders(): array + public function testCreateProviders(): array { $providersParams = [ 'sendgrid' => [ @@ -77,7 +71,8 @@ class MessagingServerTest extends Scope $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/' . $key, \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - ],$this->getHeaders()), $providersParams[$key]); + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $providersParams[$key]); \array_push($providers, $response['body']); $this->assertEquals(201, $response['headers']['status-code']); $this->assertEquals($providersParams[$key]['name'], $response['body']['name']); @@ -195,4 +190,4 @@ class MessagingServerTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } } -} +} \ No newline at end of file diff --git a/tests/e2e/Services/Messaging/MessagingCustomServerTest.php b/tests/e2e/Services/Messaging/MessagingCustomServerTest.php new file mode 100644 index 0000000000..c126df3261 --- /dev/null +++ b/tests/e2e/Services/Messaging/MessagingCustomServerTest.php @@ -0,0 +1,15 @@ + Date: Fri, 25 Aug 2023 04:36:41 +0530 Subject: [PATCH 045/196] adds test cases for topic controller --- app/config/roles.php | 4 +- app/controllers/api/messaging.php | 48 +++++----- tests/e2e/Scopes/ProjectCustom.php | 2 + .../e2e/Services/Messaging/MessagingBase.php | 90 ++++++++++++++++++- .../Messaging/MessagingConsoleClientTest.php | 15 ++++ .../Messaging/MessagingCustomClientTest.php | 15 ++++ 6 files changed, 144 insertions(+), 30 deletions(-) create mode 100644 tests/e2e/Services/Messaging/MessagingConsoleClientTest.php create mode 100644 tests/e2e/Services/Messaging/MessagingCustomClientTest.php diff --git a/app/config/roles.php b/app/config/roles.php index 4bc85f7a28..4666268d0c 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -25,7 +25,9 @@ $member = [ 'providers.write', 'providers.read', 'messages.write', - 'messages.read' + 'messages.read', + 'topics.write', + 'topics.read' ]; $admins = [ diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index a0bf2d2ead..4f14903f0c 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -936,7 +936,7 @@ App::get('/v1/messaging/topics') ->desc('List topics.') ->groups(['api', 'messaging']) ->label('scope', 'topics.read') - ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'listTopics') ->label('sdk.description', '/docs/references/messaging/list-topics.md') @@ -970,7 +970,7 @@ App::get('/v1/messaging/topics') $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ 'total' => $dbForProject->count('topics', $filterQueries, APP_LIMIT_COUNT), - 'indexes' => $dbForProject->find('topics', $queries), + 'topics' => $dbForProject->find('topics', $queries), ]), Response::MODEL_TOPIC_LIST); }); @@ -978,7 +978,7 @@ App::get('/v1/messaging/topics/:id') ->desc('Get a topic.') ->groups(['api', 'messaging']) ->label('scope', 'topics.read') - ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'getTopic') ->label('sdk.description', '/docs/references/messaging/get-topic.md') @@ -1007,21 +1007,21 @@ App::post('/v1/messaging/topics') ->label('audits.event', 'topics.create') ->label('audits.resource', 'topics/{response.$id}') ->label('scope', 'topics.write') - ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createTopic') ->label('sdk.description', '/docs/references/messaging/create-topic.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TOPIC) - ->param('id', '', new CustomId(), 'Topic ID. Choose a custom Topic ID or a new Topic ID.') + ->param('topicId', '', new CustomId(), 'Topic ID. Choose a custom Topic ID or a new Topic ID.') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Topic Name.') ->param('description', '', new Text(2048), 'Topic Description.', true) - ->inject('user') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $providerId, string $name, string $description, Document $user, Database $dbForProject, Response $response) { + ->action(function (string $topicId, string $providerId, string $name, string $description, Database $dbForProject, Response $response) { + $topicId = $topicId == 'unique()' ? ID::unique() : $topicId; $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1029,16 +1029,10 @@ App::post('/v1/messaging/topics') } $topic = new Document([ - '$id' => $id, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], + '$id' => $topicId, 'providerId' => $providerId, 'providerInternalId' => $provider->getInternalId(), 'name' => $name, - ]); if ($description) { @@ -1052,26 +1046,26 @@ App::post('/v1/messaging/topics') ->dynamic($topic, Response::MODEL_TOPIC); }); -App::patch('/v1/messaging/topics/:id') +App::patch('/v1/messaging/topics/:topicId') ->desc('Update a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'topics.update') ->label('audits.resource', 'topics/{response.$id}') ->label('scope', 'topics.write') - ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateTopic') ->label('sdk.description', '/docs/references/messaging/update-topic.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TOPIC) - ->param('id', '', new UID(), 'Topic ID.') + ->param('topicId', '', new UID(), 'Topic ID.') ->param('name', '', new Text(128), 'Topic Name.', true) ->param('description', null, new Text(128), 'Topic Description.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $description, Database $dbForProject, Response $response) { - $topic = $dbForProject->getDocument('topics', $id); + ->action(function (string $topicId, string $name, string $description, Database $dbForProject, Response $response) { + $topic = $dbForProject->getDocument('topics', $topicId); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); @@ -1085,36 +1079,36 @@ App::patch('/v1/messaging/topics/:id') $topic->setAttribute('description', $description); } - $topic = $dbForProject->updateDocument('topics', $id, $topic); + $topic = $dbForProject->updateDocument('topics', $topicId, $topic); $response ->dynamic($topic, Response::MODEL_TOPIC); }); -App::delete('/v1/messaging/topics/:id') +App::delete('/v1/messaging/topics/:topicId') ->desc('Delete a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'topics.delete') - ->label('audits.resource', 'topics/{request.id}') + ->label('audits.resource', 'topics/{request.topicId}') ->label('scope', 'topics.write') - ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'deleteTopic') ->label('sdk.description', '/docs/references/messaging/delete-topic.md') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('id', '', new UID(), 'Topic ID.') + ->param('topicId', '', new UID(), 'Topic ID.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, Database $dbForProject, Response $response) { - $topic = $dbForProject->getDocument('topics', $id); + ->action(function (string $topicId, Database $dbForProject, Response $response) { + $topic = $dbForProject->getDocument('topics', $topicId); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); } - $topic = $dbForProject->deleteDocument('topics', $id); + $topic = $dbForProject->deleteDocument('topics', $topicId); $response->noContent(); }); diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index 2a1b0a8039..140c3b8137 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -87,6 +87,8 @@ trait ProjectCustom 'providers.write', 'messages.read', 'messages.write', + 'topics.write', + 'topics.read' ], ]); diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 8a0937c0eb..5303fbb5c9 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -6,7 +6,7 @@ use Tests\E2E\Client; trait MessagingBase { - public function testCreateProviders(): array + public function testCreateProviders(): array { $providersParams = [ 'sendgrid' => [ @@ -190,4 +190,90 @@ trait MessagingBase $this->assertEquals(204, $response['headers']['status-code']); } } -} \ No newline at end of file + + public function testCreateTopic(): string + { + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'id' => 'unique()', + 'name' => 'Sengrid1', + 'apiKey' => 'my-apikey', + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + $response = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => 'unique()', + 'name' => 'my-app', + 'description' => 'web app' + ]); + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertEquals('my-app', $response['body']['name']); + + return $response['body']['$id']; + } + + /** + * @depends testCreateTopic + */ + public function testUpdateTopic(string $topicId): string + { + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/topics/' . $topicId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'name' => 'android-app', + 'description' => 'updated-description' + ]); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('android-app', $response['body']['name']); + $this->assertEquals('updated-description', $response['body']['description']); + return $topicId; + } + + public function testListTopic() + { + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(1, \count($response['body']['topics'])); + } + + /** + * @depends testUpdateTopic + */ + public function testGetTopic(string $topicId) + { + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' .$topicId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('android-app', $response['body']['name']); + $this->assertEquals('updated-description', $response['body']['description']); + } + + /** + * @depends testUpdateTopic + */ + public function testDeleteTopic(string $topicId) + { + $response = $this->client->call(Client::METHOD_DELETE, '/messaging/topics/' .$topicId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(204, $response['headers']['status-code']); + } +} diff --git a/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php b/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php new file mode 100644 index 0000000000..8250c0229a --- /dev/null +++ b/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php @@ -0,0 +1,15 @@ + Date: Fri, 25 Aug 2023 04:43:40 +0530 Subject: [PATCH 046/196] changes id to providerId for provider create controllers --- app/controllers/api/messaging.php | 74 +++++++++---------- .../e2e/Services/Messaging/MessagingBase.php | 20 ++--- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index f391eef5ba..d86b8247b4 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -56,7 +56,7 @@ App::get('/v1/messaging/providers') $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), - 'indexes' => $dbForProject->find('providers', $queries), + 'providers' => $dbForProject->find('providers', $queries), ]), Response::MODEL_PROVIDER_LIST); }); @@ -100,16 +100,16 @@ App::post('/v1/messaging/providers/mailgun') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Mailgun API Key.') ->param('domain', '', new Text(0), 'Mailgun Domain.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $id = $id == 'unique()' ? ID::unique() : $id; + ->action(function (string $providerId, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $id, + '$id' => $providerId, 'name' => $name, 'provider' => 'mailgun', 'type' => 'email', @@ -191,15 +191,15 @@ App::post('/v1/messaging/providers/sendgrid') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Sendgrid API key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $apiKey, Database $dbForProject, Response $response) { - $id = $id == 'unique()' ? ID::unique() : $id; + ->action(function (string $providerId, string $name, string $apiKey, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $id, + '$id' => $providerId, 'name' => $name, 'provider' => 'sendgrid', 'type' => 'email', @@ -275,16 +275,16 @@ App::post('/v1/messaging/providers/msg91') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $id = $id == 'unique()' ? ID::unique() : $id; + ->action(function (string $providerId, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $id, + '$id' => $providerId, 'name' => $name, 'provider' => 'msg91', 'type' => 'sms', @@ -366,16 +366,16 @@ App::post('/v1/messaging/providers/telesign') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $username, string $password, Database $dbForProject, Response $response) { - $id = $id == 'unique()' ? ID::unique() : $id; + ->action(function (string $providerId, string $name, string $username, string $password, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $id, + '$id' => $providerId, 'name' => $name, 'provider' => 'telesign', 'type' => 'sms', @@ -457,16 +457,16 @@ App::post('/v1/messaging/providers/textmagic') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('username', '', new Text(0), 'Textmagic username.') ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { - $id = $id == 'unique()' ? ID::unique() : $id; + ->action(function (string $providerId, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $id, + '$id' => $providerId, 'name' => $name, 'provider' => 'text-magic', 'type' => 'sms', @@ -548,16 +548,16 @@ App::post('/v1/messaging/providers/twilio') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $id = $id == 'unique()' ? ID::unique() : $id; + ->action(function (string $providerId, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $id, + '$id' => $providerId, 'name' => $name, 'provider' => 'twilio', 'type' => 'sms', @@ -639,16 +639,16 @@ App::post('/v1/messaging/providers/vonage') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $id = $id == 'unique()' ? ID::unique() : $id; + ->action(function (string $providerId, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $id, + '$id' => $providerId, 'name' => $name, 'provider' => 'vonage', 'type' => 'sms', @@ -733,15 +733,15 @@ App::post('/v1/messaging/providers/fcm') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('serverKey', '', new Text(0), 'FCM Server Key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $serverKey, Database $dbForProject, Response $response) { -$id = $id == 'unique()' ? ID::unique() : $id; + ->action(function (string $providerId, string $name, string $serverKey, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $id, + '$id' => $providerId, 'name' => $name, 'provider' => 'fcm', 'type' => 'push', @@ -812,7 +812,7 @@ App::post('/v1/messaging/providers/apns') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('authKey', '', new Text(0), 'APNS authentication key.') ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') @@ -821,10 +821,10 @@ App::post('/v1/messaging/providers/apns') ->param('endpoint', '', new Text(0), 'APNS endpoint.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $id = $id == 'unique()' ? ID::unique() : $id; + ->action(function (string $providerId, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $id, + '$id' => $providerId, 'name' => $name, 'provider' => 'apns', 'type' => 'push', diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 8a0937c0eb..0bea95ac1a 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -10,53 +10,53 @@ trait MessagingBase { $providersParams = [ 'sendgrid' => [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', ], 'mailgun' => [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'Mailgun1', 'apiKey' => 'my-apikey', 'domain' => 'my-domain', ], 'twilio' => [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'Twilio1', 'accountSid' => 'my-accountSid', 'authToken' => 'my-authToken', ], 'telesign' => [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'Telesign1', 'username' => 'my-username', 'password' => 'my-password', ], 'textmagic' => [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'Textmagic1', 'username' => 'my-username', 'apiKey' => 'my-apikey', ], 'msg91' => [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'Ms91-1', 'senderId' => 'my-senderid', 'authKey' => 'my-authkey', ], 'vonage' => [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'Vonage1', 'apiKey' => 'my-apikey', 'apiSecret' => 'my-apisecret', ], 'fcm' => [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'FCM1', 'serverKey' => 'my-serverkey', ], 'apns' => [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'APNS1', 'authKey' => 'my-authkey', 'authKeyId' => 'my-authkeyid', @@ -159,7 +159,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(\count($providers), $response['body']['total']); + $this->assertEquals(\count($providers), \count($response['body']['providers'])); } /** From 9be0592dabab506f177ea5cf8a0e95d3ec95f5e2 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 25 Aug 2023 04:46:15 +0530 Subject: [PATCH 047/196] lint fix --- app/controllers/api/messaging.php | 94 +++++++++---------- app/init.php | 21 +++-- .../e2e/Services/Messaging/MessagingBase.php | 4 +- .../Messaging/MessagingCustomServerTest.php | 1 - 4 files changed, 60 insertions(+), 60 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index d86b8247b4..ef69cdc808 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -29,7 +29,7 @@ App::get('/v1/messaging/providers') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER_LIST) - ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) ->inject('dbForProject') ->inject('response') ->action(function (array $queries, Database $dbForProject, Response $response) { @@ -107,10 +107,10 @@ App::post('/v1/messaging/providers/mailgun') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $providerId, - 'name' => $name, + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $providerId, + 'name' => $name, 'provider' => 'mailgun', 'type' => 'email', 'credentials' => [ @@ -151,7 +151,7 @@ App::patch('/v1/messaging/providers/:id/mailgun') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'mailgun') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -197,10 +197,10 @@ App::post('/v1/messaging/providers/sendgrid') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, string $apiKey, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $providerId, - 'name' => $name, + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $providerId, + 'name' => $name, 'provider' => 'sendgrid', 'type' => 'email', 'credentials' => [ @@ -239,7 +239,7 @@ App::patch('/v1/messaging/providers/:id/sendgrid') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'sendgrid') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -275,17 +275,17 @@ App::post('/v1/messaging/providers/msg91') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $providerId, - 'name' => $name, + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $providerId, + 'name' => $name, 'provider' => 'msg91', 'type' => 'sms', 'credentials' => [ @@ -326,7 +326,7 @@ App::patch('/v1/messaging/providers/:id/msg91') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'msg91') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -373,10 +373,10 @@ App::post('/v1/messaging/providers/telesign') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, string $username, string $password, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $providerId, - 'name' => $name, + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $providerId, + 'name' => $name, 'provider' => 'telesign', 'type' => 'sms', 'credentials' => [ @@ -417,7 +417,7 @@ App::patch('/v1/messaging/providers/:id/telesign') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'telesign') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -464,10 +464,10 @@ App::post('/v1/messaging/providers/textmagic') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $providerId, - 'name' => $name, + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $providerId, + 'name' => $name, 'provider' => 'text-magic', 'type' => 'sms', 'credentials' => [ @@ -508,7 +508,7 @@ App::patch('/v1/messaging/providers/:id/textmagic') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'text-magic') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -555,10 +555,10 @@ App::post('/v1/messaging/providers/twilio') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $providerId, - 'name' => $name, + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $providerId, + 'name' => $name, 'provider' => 'twilio', 'type' => 'sms', 'credentials' => [ @@ -599,7 +599,7 @@ App::patch('/v1/messaging/providers/:id/twilio') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'twilio') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -646,10 +646,10 @@ App::post('/v1/messaging/providers/vonage') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $providerId, - 'name' => $name, + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $providerId, + 'name' => $name, 'provider' => 'vonage', 'type' => 'sms', 'credentials' => [ @@ -690,7 +690,7 @@ App::patch('/v1/messaging/providers/:id/vonage') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'vonage') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -739,10 +739,10 @@ App::post('/v1/messaging/providers/fcm') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, string $serverKey, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $providerId, - 'name' => $name, + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $providerId, + 'name' => $name, 'provider' => 'fcm', 'type' => 'push', 'credentials' => [ @@ -781,7 +781,7 @@ App::patch('/v1/messaging/providers/:id/fcm') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'fcm') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { @@ -822,10 +822,10 @@ App::post('/v1/messaging/providers/apns') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ - '$id' => $providerId, - 'name' => $name, + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = $dbForProject->createDocument('providers', new Document([ + '$id' => $providerId, + 'name' => $name, 'provider' => 'apns', 'type' => 'push', 'credentials' => [ @@ -872,7 +872,7 @@ App::patch('/v1/messaging/providers/:id/apns') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'apns') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } if ($name) { diff --git a/app/init.php b/app/init.php index 0b5b75ee92..57d99dac83 100644 --- a/app/init.php +++ b/app/init.php @@ -544,11 +544,10 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { $provider = Authorization::skip(fn () => $database ->getDocument( - 'providers', - $document->getAttribute('providerId'), + 'providers', + $document->getAttribute('providerId'), [Query::select(['type'])] - ) - ); + )); if ($provider) { return $provider->getAttribute('type'); } @@ -563,12 +562,13 @@ Database::addFilter( }, function (mixed $value, Document $document, Database $database) { $topicIds = Authorization::skip(fn () => \array_map( - fn ($document) => $document->getAttribute('topicId'), $database + fn ($document) => $document->getAttribute('topicId'), + $database ->find('subscribers', [ Query::equal('targetInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), - ])) - ); + ]) + )); if (\count($topicIds) > 0) { return $database->find('topics', [Query::equal('$id', $topicIds)]); } @@ -583,12 +583,13 @@ Database::addFilter( }, function (mixed $value, Document $document, Database $database) { $targetIds = Authorization::skip(fn () => \array_map( - fn ($document) => $document->getAttribute('targetId'), $database + fn ($document) => $document->getAttribute('targetId'), + $database ->find('subscribers', [ Query::equal('topicInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), - ])) - ); + ]) + )); if (\count($targetIds) > 0) { return $database->find('targets', [Query::equal('$id', $targetIds)]); } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 0bea95ac1a..c460d2b5d3 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -6,7 +6,7 @@ use Tests\E2E\Client; trait MessagingBase { - public function testCreateProviders(): array + public function testCreateProviders(): array { $providersParams = [ 'sendgrid' => [ @@ -190,4 +190,4 @@ trait MessagingBase $this->assertEquals(204, $response['headers']['status-code']); } } -} \ No newline at end of file +} diff --git a/tests/e2e/Services/Messaging/MessagingCustomServerTest.php b/tests/e2e/Services/Messaging/MessagingCustomServerTest.php index c126df3261..19e0113364 100644 --- a/tests/e2e/Services/Messaging/MessagingCustomServerTest.php +++ b/tests/e2e/Services/Messaging/MessagingCustomServerTest.php @@ -11,5 +11,4 @@ class MessagingCustomServerTest extends Scope use MessagingBase; use ProjectCustom; use SideServer; - } From de6bcc1861e22547acda7ad76ce3796638f067c3 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 25 Aug 2023 14:40:48 +0530 Subject: [PATCH 048/196] fixes test --- tests/e2e/Services/Messaging/MessagingBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 1fac9b8f7e..bc675a9603 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -198,7 +198,7 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'id' => 'unique()', + 'providerId' => 'unique()', 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', ]); From c59887e8fb26326e96ffed847cc19dfe79ab6be3 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 25 Aug 2023 15:55:04 +0530 Subject: [PATCH 049/196] fixes issue in sub queries --- app/config/collections.php | 22 ++------------------ app/init.php | 22 +------------------- tests/e2e/Services/Users/UsersBase.php | 28 ++++++++++---------------- 3 files changed, 14 insertions(+), 58 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index f066c38c70..d7f6a6601c 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1673,7 +1673,7 @@ $commonCollections = [ 'required' => false, 'default' => null, 'array' => true, - 'filters' => ['subQueryTargets'], + 'filters' => ['subQueryTopicTargets'], ] ], 'indexes' => [ @@ -1861,17 +1861,6 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], - [ - '$id' => ID::custom('topics'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 16384, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => true, - 'filters' => ['subQueryTopics'], - ] ], 'indexes' => [ [ @@ -1901,14 +1890,7 @@ $commonCollections = [ 'attributes' => ['providerInternalId'], 'lengths' => [], 'orders' => [], - ], - [ - '$id' => ID::custom('_key_providerType'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerType'], - 'lengths' => [], - 'orders' => [], - ], + ] ], ], ]; diff --git a/app/init.php b/app/init.php index 57d99dac83..eed61f2eeb 100644 --- a/app/init.php +++ b/app/init.php @@ -555,29 +555,9 @@ Database::addFilter( } ); -Database::addFilter( - 'subQueryTopics', - function (mixed $value) { - return null; - }, - function (mixed $value, Document $document, Database $database) { - $topicIds = Authorization::skip(fn () => \array_map( - fn ($document) => $document->getAttribute('topicId'), - $database - ->find('subscribers', [ - Query::equal('targetInternalId', [$document->getInternalId()]), - Query::limit(APP_LIMIT_SUBQUERY), - ]) - )); - if (\count($topicIds) > 0) { - return $database->find('topics', [Query::equal('$id', $topicIds)]); - } - return []; - } -); Database::addFilter( - 'subQueryTargets', + 'subQueryTopicTargets', function (mixed $value) { return null; }, diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index 947a3a5cd9..923eb35adf 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -1216,11 +1216,11 @@ trait UsersBase */ public function testCreateUserTarget(array $data): array { - $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [ + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ + ], $this->getHeaders()), [ + 'providerId' => 'unique()', 'name' => 'Sengrid1', 'apiKey' => 'my-apikey' ]); @@ -1228,8 +1228,7 @@ trait UsersBase $response = $this->client->call(Client::METHOD_POST, '/users/' . $data['userId'] . '/targets', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), [ + ], $this->getHeaders()), [ 'targetId' => ID::unique(), 'providerId' => $provider['body']['$id'], 'identifier' => 'my-token', @@ -1248,8 +1247,7 @@ trait UsersBase $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/targets/' . $data['$id'] . '/identifier', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), [ + ], $this->getHeaders()), [ 'identifier' => 'my-updated-token', ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -1258,17 +1256,16 @@ trait UsersBase } /** - * @depends testGetUser + * @depends testUpdateUserTarget */ public function testListUserTarget(array $data) { $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ])); + ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(1, $response['body']['total']); + $this->assertEquals(1, \count($response['body']['targets'])); } /** @@ -1279,8 +1276,7 @@ trait UsersBase $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets/' . $data['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ])); + ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($data['$id'], $response['body']['$id']); } @@ -1293,14 +1289,12 @@ trait UsersBase $response = $this->client->call(Client::METHOD_DELETE, '/users/' . $data['userId'] . '/targets/' . $data['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ])); + ], $this->getHeaders())); $this->assertEquals(204, $response['headers']['status-code']); $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ])); + ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(0, $response['body']['total']); } From d7c85622607e7066bb76c2ea67eb823fd028c95e Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 25 Aug 2023 16:02:46 +0530 Subject: [PATCH 050/196] removes target controllers from account service --- app/controllers/api/account.php | 194 ------------------ .../Account/AccountCustomClientTest.php | 112 ---------- 2 files changed, 306 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index efcef85b68..fecbf51d17 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1825,29 +1825,6 @@ App::get('/v1/account/logs') ]), Response::MODEL_LOG_LIST); }); -App::get('/v1/account/targets') - ->desc('List Account Targets') - ->groups(['api', 'account']) - ->label('scope', 'account') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) - ->label('sdk.namespace', 'account') - ->label('sdk.method', 'listTargets') - ->label('sdk.description', '/docs/references/account/list-targets.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_TARGET_LIST) - ->inject('user') - ->inject('response') - ->action(function (Document $user, Response $response) { - - $targets = $user->getAttribute('targets', []); - - $response->dynamic(new Document([ - 'targets' => $targets, - 'total' => \count($targets), - ]), Response::MODEL_TARGET_LIST); - }); - App::get('/v1/account/sessions/:sessionId') ->desc('Get Session') ->groups(['api', 'account']) @@ -1892,33 +1869,6 @@ App::get('/v1/account/sessions/:sessionId') throw new Exception(Exception::USER_SESSION_NOT_FOUND); }); -App::get('/v1/account/targets/:targetId') - ->desc('Get Target') - ->groups(['api', 'account']) - ->label('scope', 'account') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) - ->label('sdk.namespace', 'account') - ->label('sdk.method', 'getTarget') - ->label('sdk.description', '/docs/references/account/get-Target.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_TARGET) - ->label('sdk.offline.model', '/account/targets') - ->label('sdk.offline.key', '{targetId}') - ->param('targetId', '', new UID(), 'Target ID.') - ->inject('user') - ->inject('response') - ->action(function (string $targetId, Document $user, Response $response) { - - $target = $user->find('$id', $targetId, 'targets'); - - if (empty($target)) { - throw new Exception(Exception::USER_TARGET_NOT_FOUND); - } - - $response->dynamic($target, Response::MODEL_TARGET); - }); - App::patch('/v1/account/name') ->desc('Update Name') ->groups(['api', 'account']) @@ -2999,147 +2949,3 @@ App::put('/v1/account/verification/phone') $response->dynamic($verificationDocument, Response::MODEL_TOKEN); }); - -App::post('/v1/account/targets') - ->desc('Create Account\'s Target') - ->groups(['api', 'account']) - ->label('event', 'users.[userId].targets.[targetId].create') - ->label('audits.event', 'targets.create') - ->label('audits.resource', 'user/{response.userId}') - ->label('audits.userId', '{response.userId}') - ->label('scope', 'targets.write') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) - ->label('sdk.namespace', 'account') - ->label('sdk.method', 'createTarget') - ->label('sdk.description', '/docs/references/account/create-target.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_TARGET) - ->param('targetId', '', new UID(), 'Target ID.') - ->param('providerId', '', new UID(), 'Provider ID.') - ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') - ->inject('user') - ->inject('response') - ->inject('dbForProject') - ->inject('events') - ->action(function (string $targetId, string $providerId, string $identifier, Document $user, Response $response, Database $dbForProject, Event $events) { - $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); - - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - - $target = $dbForProject->getDocument('targets', $targetId); - - if (!$target->isEmpty()) { - throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); - } - - $target = $dbForProject->createDocument('targets', new Document([ - '$id' => $targetId, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'providerId' => $providerId, - 'providerInternalId' => $provider->getInternalId(), - 'providerType' => null, - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), - 'identifier' => $identifier, - ])); - $dbForProject->deleteCachedDocument('users', $user->getId()); - $events - ->setParam('userId', $user->getId()) - ->setParam('targetId', $targetId); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($target, Response::MODEL_TARGET); - }); - -App::patch('/v1/account/targets/:targetId/identifier') - ->desc('Update account\'s target identifier') - ->groups(['api', 'account']) - ->label('event', 'users.[userId].targets.[targetId].update') - ->label('audits.event', 'targets.update') - ->label('audits.resource', 'user/{response.userId}') - ->label('audits.userId', '{response.userId}') - ->label('scope', 'targets.write') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) - ->label('sdk.namespace', 'account') - ->label('sdk.method', 'updateTargetIdentifier') - ->label('sdk.description', '/docs/references/account/update-target-identifier.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_TARGET) - ->param('targetId', '', new UID(), 'Target ID.') - ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') - ->inject('user') - ->inject('response') - ->inject('dbForProject') - ->inject('events') - ->action(function (string $targetId, string $identifier, Document $user, Response $response, Database $dbForProject, Event $events) { - - $target = $dbForProject->getDocument('targets', $targetId); - - if ($target->isEmpty()) { - throw new Exception(Exception::USER_TARGET_NOT_FOUND); - } - - // Update the target identifier here - $target->setAttribute('identifier', $identifier); - - $target = $dbForProject->updateDocument('targets', $target->getId(), $target); - $dbForProject->deleteCachedDocument('users', $user->getId()); - - $events - ->setParam('userId', $user->getId()) - ->setParam('targetId', $targetId); - - $response - ->dynamic($target, Response::MODEL_TARGET); - }); - -App::delete('/v1/account/targets/:targetId') - ->desc('Delete account\'s target') - ->groups(['api', 'account']) - ->label('event', 'users.[userId].targets.[targetId].delete') - ->label('audits.event', 'targets.delete') - ->label('audits.resource', 'user/{response.userId}') - ->label('audits.userId', '{response.userId}') - ->label('scope', 'targets.write') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) - ->label('sdk.namespace', 'account') - ->label('sdk.method', 'deleteTarget') - ->label('sdk.description', '/docs/references/account/delete-target.md') - ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_NONE) - ->param('targetId', '', new UID(), 'Target ID.') - ->inject('user') - ->inject('response') - ->inject('dbForProject') - ->inject('events') - ->action(function (string $targetId, Document $user, Response $response, Database $dbForProject, Event $events) { - - $target = $dbForProject->getDocument('targets', $targetId); - - if ($target->isEmpty()) { - throw new Exception(Exception::USER_TARGET_NOT_FOUND); - } - - $target = $dbForProject->deleteDocument('targets', $target->getId()); - $dbForProject->deleteCachedDocument('users', $user->getId()); - $user = $dbForProject->getDocument('users', $user->getId()); - - // clone user object to send to workers - $clone = clone $user; - - $events - ->setParam('userId', $user->getId()) - ->setParam('targetId', $targetId) - ->setPayload($response->output($clone, Response::MODEL_USER)); - - $response->noContent(); - }); diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 6dce5d8f59..d272605e58 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -116,118 +116,6 @@ class AccountCustomClientTest extends Scope return []; } - /** - * @depends testCreateAccountSession - */ - public function testCreateAccountTarget(array $data): array - { - $session = $data['session'] ?? ''; - $apiKey = $this->getProject()['apiKey']; - - $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $apiKey, - ], [ - 'name' => 'Sengrid1', - 'apiKey' => 'my-apikey' - ]); - $this->assertEquals(201, $provider['headers']['status-code']); - $response = $this->client->call(Client::METHOD_POST, '/account/targets', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), [ - 'targetId' => ID::unique(), - 'providerId' => $provider['body']['$id'], - 'identifier' => 'my-token', - ]); - $this->assertEquals(201, $response['headers']['status-code']); - $this->assertEquals($provider['body']['$id'], $response['body']['providerId']); - $this->assertEquals('my-token', $response['body']['identifier']); - return ['target' => $response['body'], 'session' => $session]; - } - - /** - * @depends testCreateAccountTarget - */ - public function testUpdateAccountTarget(array $data): array - { - $session = $data['session'] ?? ''; - $target = $data['target']; - $response = $this->client->call(Client::METHOD_PATCH, '/account/targets/' . $target['$id'] . '/identifier', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), [ - 'identifier' => 'my-updated-token', - ]); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('my-updated-token', $response['body']['identifier']); - return $data; - } - - /** - * @depends testCreateAccountSession - */ - public function testListAccountTarget(array $data) - { - $session = $data['session'] ?? ''; - $response = $this->client->call(Client::METHOD_GET, '/account/targets', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(1, $response['body']['total']); - } - - /** - * @depends testCreateAccountTarget - */ - public function testGetAccountTarget(array $data) - { - $session = $data['session'] ?? ''; - $target = $data['target']; - - $response = $this->client->call(Client::METHOD_GET, '/account/targets/' . $target['$id'], array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals($data['target']['$id'], $response['body']['$id']); - } - - /** - * @depends testUpdateAccountTarget - */ - public function testDeleteAccountTarget(array $data) - { - $session = $data['session'] ?? ''; - $target = $data['target']; - - $response = $this->client->call(Client::METHOD_DELETE, '/account/targets/' . $target['$id'], array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); - $this->assertEquals(204, $response['headers']['status-code']); - $response = $this->client->call(Client::METHOD_GET, '/account/targets', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(0, $response['body']['total']); - } - public function testBlockedAccount(): array { $email = uniqid() . 'user@localhost.test'; From 2c4e90d6608dec167688a18edf4732e4acc11d31 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 25 Aug 2023 19:48:21 +0530 Subject: [PATCH 051/196] removes unnecessary test case --- .../Account/AccountCustomClientTest.php | 131 ------------------ 1 file changed, 131 deletions(-) diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index d272605e58..d225496a65 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -1093,135 +1093,4 @@ class AccountCustomClientTest extends Scope return $data; } - - /** - * @depends testCreateAccountSession - */ - public function testGetAccountLogs($data): array - { - sleep(10); - $session = $data['session'] ?? ''; - $sessionId = $data['sessionId'] ?? ''; - $userId = $data['id'] ?? ''; - /** - * Test for SUCCESS - */ - $response = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); - $this->assertEquals($response['headers']['status-code'], 200); - $this->assertIsArray($response['body']['logs']); - $this->assertNotEmpty($response['body']['logs']); - $this->assertCount(5, $response['body']['logs']); - $this->assertIsNumeric($response['body']['total']); - $this->assertContains($response['body']['logs'][1]['event'], ["targets.create"]); - $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); - $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['logs'][1]['time'])); - - $this->assertEquals('Windows', $response['body']['logs'][1]['osName']); - $this->assertEquals('WIN', $response['body']['logs'][1]['osCode']); - $this->assertEquals('10', $response['body']['logs'][1]['osVersion']); - - $this->assertEquals('browser', $response['body']['logs'][1]['clientType']); - $this->assertEquals('Chrome', $response['body']['logs'][1]['clientName']); - $this->assertEquals('CH', $response['body']['logs'][1]['clientCode']); - $this->assertEquals('70.0', $response['body']['logs'][1]['clientVersion']); - $this->assertEquals('Blink', $response['body']['logs'][1]['clientEngine']); - - $this->assertEquals('desktop', $response['body']['logs'][1]['deviceName']); - $this->assertEquals('', $response['body']['logs'][1]['deviceBrand']); - $this->assertEquals('', $response['body']['logs'][1]['deviceModel']); - $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); - - $this->assertEquals('--', $response['body']['logs'][1]['countryCode']); - $this->assertEquals('Unknown', $response['body']['logs'][1]['countryName']); - - $this->assertContains($response['body']['logs'][2]['event'], ["session.create"]); - $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); - $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['logs'][2]['time'])); - - $this->assertEquals('Windows', $response['body']['logs'][2]['osName']); - $this->assertEquals('WIN', $response['body']['logs'][2]['osCode']); - $this->assertEquals('10', $response['body']['logs'][2]['osVersion']); - - $this->assertEquals('browser', $response['body']['logs'][2]['clientType']); - $this->assertEquals('Chrome', $response['body']['logs'][2]['clientName']); - $this->assertEquals('CH', $response['body']['logs'][2]['clientCode']); - $this->assertEquals('70.0', $response['body']['logs'][2]['clientVersion']); - $this->assertEquals('Blink', $response['body']['logs'][2]['clientEngine']); - - $this->assertEquals('desktop', $response['body']['logs'][2]['deviceName']); - $this->assertEquals('', $response['body']['logs'][2]['deviceBrand']); - $this->assertEquals('', $response['body']['logs'][2]['deviceModel']); - $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); - - $this->assertEquals('--', $response['body']['logs'][2]['countryCode']); - $this->assertEquals('Unknown', $response['body']['logs'][2]['countryName']); - - $responseLimit = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), [ - 'queries' => [ 'limit(1)' ], - ]); - - $this->assertEquals($responseLimit['headers']['status-code'], 200); - $this->assertIsArray($responseLimit['body']['logs']); - $this->assertNotEmpty($responseLimit['body']['logs']); - $this->assertCount(1, $responseLimit['body']['logs']); - $this->assertIsNumeric($responseLimit['body']['total']); - - $this->assertEquals($response['body']['logs'][0], $responseLimit['body']['logs'][0]); - - $responseOffset = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), [ - 'queries' => [ 'offset(1)' ], - ]); - - $this->assertEquals($responseOffset['headers']['status-code'], 200); - $this->assertIsArray($responseOffset['body']['logs']); - $this->assertNotEmpty($responseOffset['body']['logs']); - $this->assertCount(4, $responseOffset['body']['logs']); - $this->assertIsNumeric($responseOffset['body']['total']); - - $this->assertEquals($response['body']['logs'][1], $responseOffset['body']['logs'][0]); - - $responseLimitOffset = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), [ - 'queries' => [ 'limit(1)', 'offset(1)' ], - ]); - - $this->assertEquals($responseLimitOffset['headers']['status-code'], 200); - $this->assertIsArray($responseLimitOffset['body']['logs']); - $this->assertNotEmpty($responseLimitOffset['body']['logs']); - $this->assertCount(1, $responseLimitOffset['body']['logs']); - $this->assertIsNumeric($responseLimitOffset['body']['total']); - - $this->assertEquals($response['body']['logs'][1], $responseLimitOffset['body']['logs'][0]); - /** - * Test for FAILURE - */ - $response = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ])); - - $this->assertEquals($response['headers']['status-code'], 401); - - return $data; - } } From 264f0bd5ddd93124df0c6877dfa0b51c57cf78c3 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 28 Aug 2023 20:41:05 +0530 Subject: [PATCH 052/196] adds subscriber controllers --- app/config/errors.php | 19 +- app/config/roles.php | 4 +- app/controllers/api/messaging.php | 181 +++++++++++++++++- src/Appwrite/Extend/Exception.php | 5 + tests/e2e/Scopes/ProjectCustom.php | 4 +- .../e2e/Services/Messaging/MessagingBase.php | 82 +++++++- 6 files changed, 276 insertions(+), 19 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 97b5f0661c..98c2918146 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -712,7 +712,24 @@ return [ /** Topic Errors */ Exception::TOPIC_NOT_FOUND => [ 'name' => Exception::TOPIC_NOT_FOUND, - 'description' => 'Provider with the request ID could not be found.', + 'description' => 'Topic with the request ID could not be found.', 'code' => 404, ], + Exception::TOPIC_ALREADY_EXISTS => [ + 'name' => Exception::TOPIC_ALREADY_EXISTS, + 'description' => 'Topic with the request ID already exists.', + 'code' => 409, + ], + + /** Subscriber Errors */ + Exception::SUBSCRIBER_NOT_FOUND => [ + 'name' => Exception::SUBSCRIBER_NOT_FOUND, + 'description' => 'Subscriber with the request ID could not be found.', + 'code' => 404, + ], + Exception::SUBSCRIBER_ALREADY_EXISTS => [ + 'name' => Exception::SUBSCRIBER_ALREADY_EXISTS, + 'description' => 'Subscriber with the request ID already exists.', + 'code' => 409, + ], ]; diff --git a/app/config/roles.php b/app/config/roles.php index 4666268d0c..30dbdd528d 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -27,7 +27,9 @@ $member = [ 'messages.write', 'messages.read', 'topics.write', - 'topics.read' + 'topics.read', + 'subscribers.write', + 'subscribers.read' ]; $admins = [ diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index a4cd2d8ef9..766641a852 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -9,6 +9,7 @@ use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -974,7 +975,7 @@ App::get('/v1/messaging/topics') ]), Response::MODEL_TOPIC_LIST); }); -App::get('/v1/messaging/topics/:id') +App::get('/v1/messaging/topics/:topicId') ->desc('Get a topic.') ->groups(['api', 'messaging']) ->label('scope', 'topics.read') @@ -985,17 +986,17 @@ App::get('/v1/messaging/topics/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TOPIC) - ->param('id', '', new UID(), 'Topic ID.') + ->param('topicId', '', new UID(), 'Topic ID.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, Database $dbForProject, Response $response) { - $topic = $dbForProject->getDocument('topics', $id); + ->action(function (string $topicId, Database $dbForProject, Response $response) { + $topic = $dbForProject->getDocument('topics', $topicId); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); } - $topic = $dbForProject->getDocument('topics', $id); + $topic = $dbForProject->getDocument('topics', $topicId); $response ->dynamic($topic, Response::MODEL_TOPIC); @@ -1039,11 +1040,14 @@ App::post('/v1/messaging/topics') $topic->setAttribute('description', $description); } - $topic = $dbForProject->createDocument('topics', $topic); - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($topic, Response::MODEL_TOPIC); + try{ + $topic = $dbForProject->createDocument('topics', $topic); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($topic, Response::MODEL_TOPIC); + } catch(DuplicateException) { + throw new Exception(Exception::TOPIC_ALREADY_EXISTS); + } }); App::patch('/v1/messaging/topics/:topicId') @@ -1112,6 +1116,163 @@ App::delete('/v1/messaging/topics/:topicId') $response->noContent(); }); +App::get('/v1/messaging/topics/:topicId/subscribers') + ->desc('List topic\'s subscribers.') + ->groups(['api', 'messaging']) + ->label('scope', 'subscribers.read') + ->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', 'listSubscribers') + ->label('sdk.description', '/docs/references/messaging/list-subscribers.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_SUBSCRIBER_LIST) + ->param('topicId', '', new UID(), 'Topic ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $topicId, Database $dbForProject, Response $response) { + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); + + if ($topic->isEmpty()) { + throw new Exception(Exception::TOPIC_NOT_FOUND); + } + + $subscribers = $dbForProject->find('subscribers', [ + Query::equal('topicInternalId', [$topic->getInternalId()]) + ]); + + $response + ->dynamic(new Document([ + 'subscribers' => $subscribers, + 'total' => \count($subscribers), + ]), Response::MODEL_SUBSCRIBER_LIST); + }); + +App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') + ->desc('Get a topic\'s subscriber.') + ->groups(['api', 'messaging']) + ->label('scope', 'subscribers.read') + ->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', 'getSubscriber') + ->label('sdk.description', '/docs/references/messaging/get-subscriber.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_SUBSCRIBER) + ->param('topicId', '', new UID(), 'Topic ID.') + ->param('subscriberId', '', new UID(), 'Subscriber ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $topicId, string $subscriberId, Database $dbForProject, Response $response) { + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); + + if ($topic->isEmpty()) { + throw new Exception(Exception::TOPIC_NOT_FOUND); + } + + $subscriber = $dbForProject->getDocument('subscribers', $subscriberId); + + if ($subscriber->isEmpty() || $subscriber->getAttribute('topicId')!==$topicId) { + throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); + } + + $response + ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); + }); + +App::post('/v1/messaging/topics/:topicId/subscribers') + ->desc('Adds a Subscriber to a Topic.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'subscribers.create') + ->label('audits.resource', 'subscribers/{response.$id}') + ->label('scope', 'subscribers.write') + ->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', 'addSubscriber') + ->label('sdk.description', '/docs/references/messaging/add-subscriber.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_SUBSCRIBER) + ->param('subscriberId', '', new CustomId(), 'Subscriber ID. Choose a custom Topic ID or a new Topic ID.') + ->param('topicId', '', new UID(), 'Topic ID.') + ->param('targetId', '', new UID(), 'Target ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $subscriberId, string $topicId, string $targetId, Database $dbForProject, Response $response) { + $subscriberId = $subscriberId == 'unique()' ? ID::unique() : $subscriberId; + + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); + + if ($topic->isEmpty()) { + throw new Exception(Exception::TOPIC_NOT_FOUND); + } + + $target = $dbForProject->getDocument('targets', $targetId); + + if ($target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + $subscriber = new Document([ + '$id' => $subscriberId, + '$permissions' => [ + Permission::read(Role::user($target->getAttribute('userId'))), + Permission::delete(Role::user($target->getAttribute('userId'))), + ], + 'topicId' => $topicId, + 'topicInternalId' => $topic->getInternalId(), + 'targetId' => $targetId, + 'targetInternalId' => $target->getInternalId(), + ]); + + try { + $subscriber = $dbForProject->createDocument('subscribers', $subscriber); + $dbForProject->deleteCachedDocument('topics', $topicId); + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); + } catch(DuplicateException) { + throw new Exception(Exception::SUBSCRIBER_ALREADY_EXISTS); + } + }); + +App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') + ->desc('Delete a Subscriber from a Topic.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'subscribers.delete') + ->label('audits.resource', 'subscribers/{request.subscriberId}') + ->label('scope', 'subscribers.write') + ->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') + ->label('sdk.description', '/docs/references/messaging/delete-subscriber.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('topicId', '', new UID(), 'Topic ID.') + ->param('subscriberId', '', new UID(), 'Subscriber ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $topicId, string $subscriberId, Database $dbForProject, Response $response) { + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); + + if ($topic->isEmpty()) { + throw new Exception(Exception::TOPIC_NOT_FOUND); + } + + $subscriber = $dbForProject->getDocument('subscribers', $subscriberId); + + if ($subscriber->isEmpty() || $subscriber->getAttribute('topicId') !== $topicId) { + throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); + } + $subscriber = $dbForProject->deleteDocument('subscribers', $subscriberId); + $dbForProject->deleteCachedDocument('topics', $topicId); + + $response + ->setStatusCode(Response::STATUS_CODE_NOCONTENT) + ->noContent(); + }); + App::post('/v1/messaging/messages/email') ->desc('Send an email.') ->groups(['api', 'messaging']) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 4b5cac24a8..46a362406b 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -219,6 +219,11 @@ class Exception extends \Exception /** Topic */ public const TOPIC_NOT_FOUND = 'topic_not_found'; + public const TOPIC_ALREADY_EXISTS = 'topic_already_exists'; + + /** Subscriber */ + public const SUBSCRIBER_NOT_FOUND = 'subscriber_not_found'; + public const SUBSCRIBER_ALREADY_EXISTS = 'subscriber_already_exists'; protected $type = ''; protected $errors = []; diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index 140c3b8137..668a0f086f 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -88,7 +88,9 @@ trait ProjectCustom 'messages.read', 'messages.write', 'topics.write', - 'topics.read' + 'topics.read', + 'subscribers.write', + 'subscribers.read' ], ]); diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index bc675a9603..9a11e257eb 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -3,6 +3,7 @@ namespace Tests\E2E\Services\Messaging; use Tests\E2E\Client; +use Utopia\Database\Helpers\ID; trait MessagingBase { @@ -191,7 +192,7 @@ trait MessagingBase } } - public function testCreateTopic(): string + public function testCreateTopic(): array { $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', \array_merge([ 'content-type' => 'application/json', @@ -199,7 +200,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'providerId' => 'unique()', - 'name' => 'Sengrid1', + 'name' => 'Sendgrid1', 'apiKey' => 'my-apikey', ]); $this->assertEquals(201, $provider['headers']['status-code']); @@ -216,15 +217,15 @@ trait MessagingBase $this->assertEquals(201, $response['headers']['status-code']); $this->assertEquals('my-app', $response['body']['name']); - return $response['body']['$id']; + return $response['body']; } /** * @depends testCreateTopic */ - public function testUpdateTopic(string $topicId): string + public function testUpdateTopic(array $topic): string { - $response = $this->client->call(Client::METHOD_PATCH, '/messaging/topics/' . $topicId, [ + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/topics/' . $topic['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -235,7 +236,7 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('android-app', $response['body']['name']); $this->assertEquals('updated-description', $response['body']['description']); - return $topicId; + return $response['body']['$id']; } public function testListTopic() @@ -264,6 +265,75 @@ trait MessagingBase $this->assertEquals('updated-description', $response['body']['description']); } + /** + * @depends testCreateTopic + */ + public function testCreateSubscriber (array $topic) { + $userId = $this->getUser()['$id']; + $target = $this->client->call(Client::METHOD_POST, '/users/' . $userId . '/targets', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'targetId' => ID::unique(), + 'providerId' => $topic['providerId'], + 'identifier' => 'my-token', + ]); + $this->assertEquals(201, $target['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => 'unique()', + 'targetId' => $target['body']['$id'], + ]); + $this->assertEquals(201, $response['headers']['status-code']); + return [ + 'topicId' => $topic['$id'], + 'targetId' => $target['body']['$id'], + 'subscriberId' => $response['body']['$id'] + ]; + } + + /** + * @depends testCreateSubscriber + */ + public function testGetSubscriber(array $data) { + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'] . '/subscriber/' . $data['subscriberId'], \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($data['topicId'], $response['body']['topicId']); + $this->assertEquals($data['targetId'], $response['body']['targetId']); + } + + /** + * @depends testCreateSubscriber + */ + public function testListSubscribers(array $data) { + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(1, $response['body']['total']); + $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); + } + + /** + * @depends testCreateSubscriber + */ + public function testDeleteSubscriber(array $data) + { + $response = $this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $data['topicId'] .'/subscriber/' .$data['subscriberId'], \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + $this->assertEquals(204, $response['headers']['status-code']); + } + /** * @depends testUpdateTopic */ From 379f7b9aa2347ae77ecbacf1391e25697652f4d4 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 28 Aug 2023 20:41:47 +0530 Subject: [PATCH 053/196] fixes subquery attribute in collection config --- app/config/collections.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/collections.php b/app/config/collections.php index d7f6a6601c..626676259b 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1672,7 +1672,7 @@ $commonCollections = [ 'signed' => true, 'required' => false, 'default' => null, - 'array' => true, + 'array' => false, 'filters' => ['subQueryTopicTargets'], ] ], From 1d6276eb9fb8e7516fd0be22ef442e581181ff96 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 28 Aug 2023 20:43:18 +0530 Subject: [PATCH 054/196] lint fix --- app/controllers/api/messaging.php | 16 ++++++++-------- tests/e2e/Services/Messaging/MessagingBase.php | 15 +++++++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 766641a852..049453324d 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1040,12 +1040,12 @@ App::post('/v1/messaging/topics') $topic->setAttribute('description', $description); } - try{ + try { $topic = $dbForProject->createDocument('topics', $topic); $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($topic, Response::MODEL_TOPIC); - } catch(DuplicateException) { + } catch (DuplicateException) { throw new Exception(Exception::TOPIC_ALREADY_EXISTS); } }); @@ -1140,13 +1140,13 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $subscribers = $dbForProject->find('subscribers', [ Query::equal('topicInternalId', [$topic->getInternalId()]) ]); - + $response ->dynamic(new Document([ 'subscribers' => $subscribers, 'total' => \count($subscribers), ]), Response::MODEL_SUBSCRIBER_LIST); - }); + }); App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->desc('Get a topic\'s subscriber.') @@ -1169,10 +1169,10 @@ App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); } - + $subscriber = $dbForProject->getDocument('subscribers', $subscriberId); - if ($subscriber->isEmpty() || $subscriber->getAttribute('topicId')!==$topicId) { + if ($subscriber->isEmpty() || $subscriber->getAttribute('topicId') !== $topicId) { throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } @@ -1200,7 +1200,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->inject('response') ->action(function (string $subscriberId, string $topicId, string $targetId, Database $dbForProject, Response $response) { $subscriberId = $subscriberId == 'unique()' ? ID::unique() : $subscriberId; - + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { @@ -1231,7 +1231,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); - } catch(DuplicateException) { + } catch (DuplicateException) { throw new Exception(Exception::SUBSCRIBER_ALREADY_EXISTS); } }); diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 9a11e257eb..b97557d3ec 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -268,7 +268,8 @@ trait MessagingBase /** * @depends testCreateTopic */ - public function testCreateSubscriber (array $topic) { + public function testCreateSubscriber(array $topic) + { $userId = $this->getUser()['$id']; $target = $this->client->call(Client::METHOD_POST, '/users/' . $userId . '/targets', array_merge([ 'content-type' => 'application/json', @@ -290,8 +291,8 @@ trait MessagingBase ]); $this->assertEquals(201, $response['headers']['status-code']); return [ - 'topicId' => $topic['$id'], - 'targetId' => $target['body']['$id'], + 'topicId' => $topic['$id'], + 'targetId' => $target['body']['$id'], 'subscriberId' => $response['body']['$id'] ]; } @@ -299,7 +300,8 @@ trait MessagingBase /** * @depends testCreateSubscriber */ - public function testGetSubscriber(array $data) { + public function testGetSubscriber(array $data) + { $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'] . '/subscriber/' . $data['subscriberId'], \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -312,7 +314,8 @@ trait MessagingBase /** * @depends testCreateSubscriber */ - public function testListSubscribers(array $data) { + public function testListSubscribers(array $data) + { $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'] . '/subscribers', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -327,7 +330,7 @@ trait MessagingBase */ public function testDeleteSubscriber(array $data) { - $response = $this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $data['topicId'] .'/subscriber/' .$data['subscriberId'], \array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $data['topicId'] . '/subscriber/' . $data['subscriberId'], \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); From c2c70d68e9b624e22adc79ff960dd1a36962fd92 Mon Sep 17 00:00:00 2001 From: wess Date: Mon, 28 Aug 2023 16:27:55 -0400 Subject: [PATCH 055/196] Working on messaging tests with worker --- app/workers/messaging.php | 46 +++++++++------ composer.lock | 56 +++++++++---------- docker-compose.yml | 14 ++--- phpunit.xml | 2 +- .../Account/AccountCustomClientTest.php | 11 ++++ 5 files changed, 75 insertions(+), 54 deletions(-) diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 84af6fa802..1a58029c07 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -79,11 +79,25 @@ class MessagingV1 extends Worker public function run(): void { - $providerId = $this->args['providerId']; - $providerRecord = - $this - ->getConsoleDB() - ->getDocument('providers', $providerId); + $messageId = $this->args['messageId']; + $messageRecord = + $this + ->getConsoleDB() + ->getDocument('messages', $messageId); + + $providerId = $messageRecord['providerId']; + + $providerRecord = + $this + ->getConsoleDB() + ->getDocument('providers', $providerId); + + $message = match ($providerRecord->getAttribute('type')) { + 'sms' => $this->buildSMSMessage($messageRecord->getArrayCopy()), + 'push' => $this->buildPushMessage($messageRecord->getArrayCopy()), + 'email' => $this->buildEmailMessage($messageRecord->getArrayCopy()), + default => null + }; $provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed. 'sms' => $this->sms($providerRecord), @@ -92,25 +106,21 @@ class MessagingV1 extends Worker default => null }; + var_dump($provider); + die; + // Query for the provider // switch on provider name // call function passing needed credentials returns required provider. - $messageId = $this->args['messageId']; - $messageRecord = - $this - ->getConsoleDB() - ->getDocument('messages', $messageId); - - $message = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($messageRecord->getArrayCopy()), - 'push' => $this->buildPushMessage($messageRecord->getArrayCopy()), - 'email' => $this->buildEmailMessage($messageRecord->getArrayCopy()), - default => null - }; - $provider->send($message); + try { + $provider->send($message); + } catch (\Exception $error) { + throw new Exception('Error sending message: ' . $error->getMessage(), 500); + } + } public function shutdown(): void diff --git a/composer.lock b/composer.lock index f2b39d8414..ca4eff1d7d 100644 --- a/composer.lock +++ b/composer.lock @@ -1183,16 +1183,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { @@ -1201,7 +1201,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1246,7 +1246,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" }, "funding": [ { @@ -1262,7 +1262,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "utopia-php/abuse", @@ -5024,16 +5024,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -5048,7 +5048,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5086,7 +5086,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" }, "funding": [ { @@ -5102,20 +5102,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { @@ -5130,7 +5130,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5169,7 +5169,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" }, "funding": [ { @@ -5185,7 +5185,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-07-28T09:04:16+00:00" }, { "name": "textalk/websocket", @@ -5288,16 +5288,16 @@ }, { "name": "twig/twig", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "5cf942bbab3df42afa918caeba947f1b690af64b" + "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/5cf942bbab3df42afa918caeba947f1b690af64b", - "reference": "5cf942bbab3df42afa918caeba947f1b690af64b", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", + "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", "shasum": "" }, "require": { @@ -5307,7 +5307,7 @@ }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" + "symfony/phpunit-bridge": "^5.4.9|^6.3" }, "type": "library", "autoload": { @@ -5343,7 +5343,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.7.0" + "source": "https://github.com/twigphp/Twig/tree/v3.7.1" }, "funding": [ { @@ -5355,7 +5355,7 @@ "type": "tidelift" } ], - "time": "2023-07-26T07:16:09+00:00" + "time": "2023-08-28T11:09:02+00:00" } ], "aliases": [ diff --git a/docker-compose.yml b/docker-compose.yml index 16b5937704..79c7abd7fa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -732,13 +732,13 @@ services: - _APP_CONNECTIONS_QUEUE - _APP_REGION - appwrite-assistant: - container_name: appwrite-assistant - image: appwrite/assistant:0.1.0 - networks: - - appwrite - environment: - - OPENAI_API_KEY + # appwrite-assistant: + # container_name: appwrite-assistant + # image: appwrite/assistant:0.1.0 + # networks: + # - appwrite + # environment: + # - OPENAI_API_KEY openruntimes-executor: container_name: openruntimes-executor diff --git a/phpunit.xml b/phpunit.xml index cffe166336..cca546e9ad 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -6,7 +6,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="false" + stopOnFailure="true" > diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index d225496a65..796c723ee6 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -12,6 +12,7 @@ use Tests\E2E\Scopes\SideClient; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; +use Utopia\Messaging\Adapters\SMS\Mock as MockProvider; use function sleep; @@ -767,6 +768,16 @@ class AccountCustomClientTest extends Scope } + public function testCreateMockSMS(): MockProvider + { + + $smsMockProvider = new MockProvider('blah', 'blah'); + + $this->assertNotEquals(null, $smsMockProvider); + + return $smsMockProvider; + } + public function testCreatePhone(): array { $number = '+123456789'; From e53af019da46c367546ed6bc789f28143a9ff7f2 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 29 Aug 2023 21:43:21 +0530 Subject: [PATCH 056/196] Revert "Working on messaging tests with worker" This reverts commit c2c70d68e9b624e22adc79ff960dd1a36962fd92. --- app/workers/messaging.php | 46 ++++++--------- composer.lock | 56 +++++++++---------- docker-compose.yml | 14 ++--- phpunit.xml | 2 +- .../Account/AccountCustomClientTest.php | 11 ---- 5 files changed, 54 insertions(+), 75 deletions(-) diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 1a58029c07..84af6fa802 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -79,25 +79,11 @@ class MessagingV1 extends Worker public function run(): void { - $messageId = $this->args['messageId']; - $messageRecord = - $this - ->getConsoleDB() - ->getDocument('messages', $messageId); - - $providerId = $messageRecord['providerId']; - - $providerRecord = - $this - ->getConsoleDB() - ->getDocument('providers', $providerId); - - $message = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($messageRecord->getArrayCopy()), - 'push' => $this->buildPushMessage($messageRecord->getArrayCopy()), - 'email' => $this->buildEmailMessage($messageRecord->getArrayCopy()), - default => null - }; + $providerId = $this->args['providerId']; + $providerRecord = + $this + ->getConsoleDB() + ->getDocument('providers', $providerId); $provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed. 'sms' => $this->sms($providerRecord), @@ -106,21 +92,25 @@ class MessagingV1 extends Worker default => null }; - var_dump($provider); - die; - // Query for the provider // switch on provider name // call function passing needed credentials returns required provider. + $messageId = $this->args['messageId']; + $messageRecord = + $this + ->getConsoleDB() + ->getDocument('messages', $messageId); + + $message = match ($providerRecord->getAttribute('type')) { + 'sms' => $this->buildSMSMessage($messageRecord->getArrayCopy()), + 'push' => $this->buildPushMessage($messageRecord->getArrayCopy()), + 'email' => $this->buildEmailMessage($messageRecord->getArrayCopy()), + default => null + }; - try { - $provider->send($message); - } catch (\Exception $error) { - throw new Exception('Error sending message: ' . $error->getMessage(), 500); - } - + $provider->send($message); } public function shutdown(): void diff --git a/composer.lock b/composer.lock index ca4eff1d7d..f2b39d8414 100644 --- a/composer.lock +++ b/composer.lock @@ -1183,16 +1183,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.28.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "shasum": "" }, "require": { @@ -1201,7 +1201,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.28-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1246,7 +1246,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" }, "funding": [ { @@ -1262,7 +1262,7 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "utopia-php/abuse", @@ -5024,16 +5024,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.28.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "shasum": "" }, "require": { @@ -5048,7 +5048,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.28-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5086,7 +5086,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" }, "funding": [ { @@ -5102,20 +5102,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "shasum": "" }, "require": { @@ -5130,7 +5130,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.28-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5169,7 +5169,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" }, "funding": [ { @@ -5185,7 +5185,7 @@ "type": "tidelift" } ], - "time": "2023-07-28T09:04:16+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "textalk/websocket", @@ -5288,16 +5288,16 @@ }, { "name": "twig/twig", - "version": "v3.7.1", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" + "reference": "5cf942bbab3df42afa918caeba947f1b690af64b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/5cf942bbab3df42afa918caeba947f1b690af64b", + "reference": "5cf942bbab3df42afa918caeba947f1b690af64b", "shasum": "" }, "require": { @@ -5307,7 +5307,7 @@ }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3" + "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" }, "type": "library", "autoload": { @@ -5343,7 +5343,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.7.1" + "source": "https://github.com/twigphp/Twig/tree/v3.7.0" }, "funding": [ { @@ -5355,7 +5355,7 @@ "type": "tidelift" } ], - "time": "2023-08-28T11:09:02+00:00" + "time": "2023-07-26T07:16:09+00:00" } ], "aliases": [ diff --git a/docker-compose.yml b/docker-compose.yml index 79c7abd7fa..16b5937704 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -732,13 +732,13 @@ services: - _APP_CONNECTIONS_QUEUE - _APP_REGION - # appwrite-assistant: - # container_name: appwrite-assistant - # image: appwrite/assistant:0.1.0 - # networks: - # - appwrite - # environment: - # - OPENAI_API_KEY + appwrite-assistant: + container_name: appwrite-assistant + image: appwrite/assistant:0.1.0 + networks: + - appwrite + environment: + - OPENAI_API_KEY openruntimes-executor: container_name: openruntimes-executor diff --git a/phpunit.xml b/phpunit.xml index cca546e9ad..cffe166336 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -6,7 +6,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="true" + stopOnFailure="false" > diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 796c723ee6..d225496a65 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -12,7 +12,6 @@ use Tests\E2E\Scopes\SideClient; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; -use Utopia\Messaging\Adapters\SMS\Mock as MockProvider; use function sleep; @@ -768,16 +767,6 @@ class AccountCustomClientTest extends Scope } - public function testCreateMockSMS(): MockProvider - { - - $smsMockProvider = new MockProvider('blah', 'blah'); - - $this->assertNotEquals(null, $smsMockProvider); - - return $smsMockProvider; - } - public function testCreatePhone(): array { $number = '+123456789'; From 112c7a5133c7acff3659c52f63ea38e4a037677e Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 29 Aug 2023 22:29:48 +0530 Subject: [PATCH 057/196] adds default attribute for providers --- app/config/collections.php | 11 ++ app/config/errors.php | 9 +- app/controllers/api/messaging.php | 221 ++++++++++++++++++++++++++---- src/Appwrite/Extend/Exception.php | 1 + 4 files changed, 211 insertions(+), 31 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 626676259b..92e732007f 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1444,6 +1444,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('default'), + 'type' => Database::VAR_BOOLEAN, + 'signed' => true, + 'size' => 0, + 'format' => '', + 'filters' => [], + 'required' => false, + 'default' => false, + 'array' => false, + ], [ '$id' => ID::custom('credentials'), 'type' => Database::VAR_STRING, diff --git a/app/config/errors.php b/app/config/errors.php index b4b2429f31..49ba9bc1a2 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -700,12 +700,17 @@ return [ /** Provider Errors */ Exception::PROVIDER_NOT_FOUND => [ 'name' => Exception::PROVIDER_NOT_FOUND, - 'description' => 'Provider with the request ID could not be found.', + 'description' => 'Provider with the requested ID could not be found.', 'code' => 404, ], + Exception::PROVIDER_ALREADY_EXISTS => [ + 'name' => Exception::PROVIDER_ALREADY_EXISTS, + 'description' => 'Provider with the requested ID already exists.', + 'code' => 409, + ], Exception::PROVIDER_INCORRECT_TYPE => [ 'name' => Exception::PROVIDER_INCORRECT_TYPE, - 'description' => 'Provider with the request ID is of incorrect type: ', + 'description' => 'Provider with the requested ID is of incorrect type: ', 'code' => 400, ] ]; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index ef69cdc808..e91eb48fb7 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -8,14 +8,14 @@ use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; -use Utopia\Database\Helpers\Permission; -use Utopia\Database\Helpers\Role; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime; use Utopia\Database\Validator\UID; use Utopia\Validator\ArrayList; +use Utopia\Validator\Boolean; use Utopia\Validator\Text; App::get('/v1/messaging/providers') @@ -102,22 +102,41 @@ App::post('/v1/messaging/providers/mailgun') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.') ->param('domain', '', new Text(0), 'Mailgun Domain.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, string $apiKey, string $domain, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ + + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'mailgun', 'type' => 'email', + 'default' => $default, 'credentials' => [ 'apiKey' => $apiKey, 'domain' => $domain, ], - ])); + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -193,20 +212,38 @@ App::post('/v1/messaging/providers/sendgrid') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, string $apiKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'sendgrid', 'type' => 'email', + 'default' => $default, 'credentials' => [ 'apiKey' => $apiKey, ], - ])); + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -277,22 +314,40 @@ App::post('/v1/messaging/providers/msg91') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, string $senderId, string $authKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'msg91', 'type' => 'sms', + 'default' => $default, 'credentials' => [ 'senderId' => $senderId, 'authKey' => $authKey, ], - ])); + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -368,22 +423,40 @@ App::post('/v1/messaging/providers/telesign') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $username, string $password, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, string $username, string $password, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'telesign', 'type' => 'sms', + 'default' => $default, 'credentials' => [ 'username' => $username, 'password' => $password, ], - ])); + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -459,22 +532,40 @@ App::post('/v1/messaging/providers/textmagic') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('username', '', new Text(0), 'Textmagic username.') ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, string $username, string $apiKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'text-magic', 'type' => 'sms', + 'default' => $default, 'credentials' => [ 'username' => $username, 'apiKey' => $apiKey, ], - ])); + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -550,22 +641,40 @@ App::post('/v1/messaging/providers/twilio') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, string $accountSid, string $authToken, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'twilio', 'type' => 'sms', + 'default' => $default, 'credentials' => [ 'accountSid' => $accountSid, 'authToken' => $authToken, ], - ])); + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -641,22 +750,40 @@ App::post('/v1/messaging/providers/vonage') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'vonage', 'type' => 'sms', + 'default' => $default, 'credentials' => [ 'apiKey' => $apiKey, 'apiSecret' => $apiSecret, ], - ])); + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -735,20 +862,38 @@ App::post('/v1/messaging/providers/fcm') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('serverKey', '', new Text(0), 'FCM Server Key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, string $serverKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'fcm', 'type' => 'push', + 'default' => $default, 'credentials' => [ 'serverKey' => $serverKey, ], - ])); + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -814,6 +959,7 @@ App::post('/v1/messaging/providers/apns') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('authKey', '', new Text(0), 'APNS authentication key.') ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') ->param('teamId', '', new Text(0), 'APNS team ID.') @@ -821,13 +967,14 @@ App::post('/v1/messaging/providers/apns') ->param('endpoint', '', new Text(0), 'APNS endpoint.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = $dbForProject->createDocument('providers', new Document([ + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'apns', 'type' => 'push', + 'default' => $default, 'credentials' => [ 'authKey' => $authKey, 'authKeyId' => $authKeyId, @@ -835,7 +982,23 @@ App::post('/v1/messaging/providers/apns') 'bundleId' => $bundleId, 'endpoint' => $endpoint, ], - ])); + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 5ab806b254..6f7725ec09 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -215,6 +215,7 @@ class Exception extends \Exception /** Provider */ public const PROVIDER_NOT_FOUND = 'provider_not_found'; + public const PROVIDER_ALREADY_EXISTS = 'provider_already_exists'; public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; protected $type = ''; From 32b48a3c7c088faf42bacb70ba7e43101e561244 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 31 Aug 2023 18:22:36 +0530 Subject: [PATCH 058/196] removes user id from subscriber model --- src/Appwrite/Utopia/Response/Model/Subscriber.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index a9682cf0a6..8e4ef74d74 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -21,12 +21,6 @@ class Subscriber extends Model 'default' => '', 'example' => '259125845563242502', ]) - ->addRule('userId', [ - 'type' => self::TYPE_STRING, - 'description' => 'User ID.', - 'default' => '', - 'example' => '259125845563242502', - ]) ->addRule('targetId', [ 'type' => self::TYPE_STRING, 'description' => 'Target ID.', From ea324262e76efa150997096dd2889b65cadb76f5 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 5 Sep 2023 01:33:50 +0530 Subject: [PATCH 059/196] updated messaging collectin --- app/config/collections.php | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 15effbf5ae..0a51a2c1bb 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1335,24 +1335,13 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], - [ - '$id' => ID::custom('type'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 128, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('data'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => 16384, 'signed' => true, - 'required' => false, + 'required' => true, 'default' => null, 'array' => false, 'filters' => ['json'], @@ -1396,7 +1385,7 @@ $commonCollections = [ 'format' => '', 'size' => 0, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -1407,7 +1396,7 @@ $commonCollections = [ 'format' => '', 'size' => 0, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => false, 'array' => false, 'filters' => [], From 1a791f46e6dab3dbaee1a836b82ca82f44420022 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 5 Sep 2023 13:33:22 +0530 Subject: [PATCH 060/196] adds default in provider response model --- src/Appwrite/Utopia/Response/Model/Provider.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index 6dd12a4d7a..0cbc233fc3 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -33,6 +33,12 @@ class Provider extends Model 'default' => '', 'example' => 'mailgun', ]) + ->addRule('default', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Default provider or not.', + 'default' => '', + 'example' => true, + ]) ->addRule('type', [ 'type' => self::TYPE_STRING, 'description' => 'Type of provider.', From 78a53aee37a9aa754ffc366c7f054f321f306edc Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 5 Sep 2023 22:40:48 +0530 Subject: [PATCH 061/196] adds messaging event and updates messaging worker --- app/controllers/api/account.php | 61 +++++-- app/controllers/api/messaging.php | 97 ++++++++++ app/controllers/api/teams.php | 29 ++- app/init.php | 4 +- app/workers/messaging.php | 83 ++++----- composer.lock | 171 ++++++------------ docker-compose.yml | 7 +- src/Appwrite/Event/Messaging.php | 56 ++++++ src/Appwrite/Event/Phone.php | 80 -------- .../Account/AccountCustomClientTest.php | 22 ++- 10 files changed, 337 insertions(+), 273 deletions(-) create mode 100644 src/Appwrite/Event/Messaging.php delete mode 100644 src/Appwrite/Event/Phone.php diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index efc81cb370..1d73fac7c5 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -8,7 +8,6 @@ use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; use Appwrite\Event\Event; use Appwrite\Event\Mail; -use Appwrite\Event\Phone as EventPhone; use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; use Utopia\Validator\Host; @@ -45,6 +44,7 @@ use Utopia\Validator\WhiteList; use Appwrite\Auth\Validator\PasswordHistory; use Appwrite\Auth\Validator\PasswordDictionary; use Appwrite\Auth\Validator\PersonalData; +use Appwrite\Event\Messaging; $oauthDefaultSuccess = '/auth/oauth2/success'; $oauthDefaultFailure = '/auth/oauth2/failure'; @@ -1227,6 +1227,7 @@ App::post('/v1/account/sessions/phone') ->label('abuse-key', 'url:{url},email:{param-phone}') ->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') + ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('request') ->inject('response') ->inject('user') @@ -1235,9 +1236,12 @@ App::post('/v1/account/sessions/phone') ->inject('events') ->inject('messaging') ->inject('locale') - ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, EventPhone $messaging, Locale $locale) { - - if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { + ->action(function (string $userId, string $phone, string $from, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, Messaging $messaging, Locale $locale) { + $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ + Query::equal('default', [true, false]), + Query::equal('type', ['sms']) + ])); + if ($provider === false || $provider->isEmpty()) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -1322,11 +1326,22 @@ App::post('/v1/account/sessions/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); - $messaging - ->setRecipient($phone) - ->setMessage($message) - ->trigger(); + $messageDoc = $dbForProject->createDocument('messages', new Document([ + 'to' => [$phone], + 'data' => [ + 'content' => $message, + 'from' => $from, + ], + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'deliveryTime' => Datetime::now(), + ])); + $messaging + ->setMessage($messageDoc) + ->setProject($project) + ->trigger(); + $events->setPayload( $response->output( $token->setAttribute('secret', $secret), @@ -2872,6 +2887,7 @@ App::post('/v1/account/verification/phone') ->label('sdk.response.model', Response::MODEL_TOKEN) ->label('abuse-limit', 10) ->label('abuse-key', 'userId:{userId}') + ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('request') ->inject('response') ->inject('user') @@ -2880,10 +2896,13 @@ App::post('/v1/account/verification/phone') ->inject('messaging') ->inject('project') ->inject('locale') - ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events, EventPhone $messaging, Document $project, Locale $locale) { - - if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { - throw new Exception(Exception::GENERAL_PHONE_DISABLED); + ->action(function (string $from, Request $request, Response $response, Document $user, Database $dbForProject, Event $events, Messaging $messaging, Document $project, Locale $locale) { + $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ + Query::equal('default', [true, false]), + Query::equal('type', ['sms']) + ])); + if ($provider === false || $provider->isEmpty()) { + throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } if (empty($user->getAttribute('phone'))) { @@ -2928,11 +2947,21 @@ App::post('/v1/account/verification/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); + $messageDoc = $dbForProject->createDocument('messages', new Document([ + 'to' => [$user->getAttribute('phone')], + 'data' => [ + 'content' => $message, + 'from' => $from, + ], + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'deliveryTime' => Datetime::now(), + ])); + $messaging - ->setRecipient($user->getAttribute('phone')) - ->setMessage($message) - ->trigger() - ; + ->setMessage($messageDoc) + ->setProject($project) + ->trigger(); $events ->setParam('userId', $user->getId()) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index e91eb48fb7..e4302883c1 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -16,7 +16,9 @@ use Utopia\Database\Validator\Datetime; use Utopia\Database\Validator\UID; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; +use Utopia\Validator\JSON; use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; App::get('/v1/messaging/providers') ->desc('List Providers') @@ -1065,6 +1067,101 @@ App::patch('/v1/messaging/providers/:id/apns') ->dynamic($provider, Response::MODEL_PROVIDER); }); +/** + * General Purpose Provider + */ +App::post('/v1/messaging/providers/general') + ->desc('Create General Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createGeneralProvider') + ->label('sdk.description', '/docs/references/messaging/create-general-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('provider', '', new Text(128), 'Provider Internal Name') + ->param('name', '', new Text(128), 'Provider name.') + ->param('type', '', new WhiteList(['push', 'email', 'sms']), 'Provider type.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('credentials', '', new JSON(), 'Provider credentials object.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $provider, string $name, string $type, bool $default, array $credentials, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => $provider, + 'type' => $type, + 'default' => $default, + 'credentials' => $credentials, + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/general') + ->desc('Update General Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderGeneral') + ->label('sdk.description', '/docs/references/messaging/update-provider-general.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('credentials', '', new JSON(), 'Provider credentials.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, array $credentials, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if (!empty($credentials)) { + $provider->setAttribute('credentials', $credentials); + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + App::delete('/v1/messaging/providers/:id') ->desc('Delete Provider') ->groups(['api', 'messaging']) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index c5dd3eed12..c453eaaea1 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -6,7 +6,7 @@ use Appwrite\Detector\Detector; use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Event\Mail; -use Appwrite\Event\Phone as EventPhone; +use Appwrite\Event\Messaging; use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; use Utopia\Validator\Host; @@ -380,6 +380,7 @@ App::post('/v1/teams/:teamId/memberships') ->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](/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['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) + ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('response') ->inject('project') ->inject('user') @@ -388,7 +389,7 @@ App::post('/v1/teams/:teamId/memberships') ->inject('mails') ->inject('messaging') ->inject('events') - ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, EventPhone $messaging, Event $events) { + ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, string $from, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, Messaging $messaging, Event $events) { if (empty($userId) && empty($email) && empty($phone)) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'At least one of userId, email, or phone is required'); @@ -625,6 +626,15 @@ App::post('/v1/teams/:teamId/memberships') ->trigger() ; } elseif (!empty($phone)) { + $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ + Query::equal('default', [true, false]), + Query::equal('type', ['sms']) + ])); + + if ($provider === false || $provider->isEmpty()) { + throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); + } + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl'); $customTemplate = $project->getAttribute('templates', [])['sms.invitation-' . $locale->default] ?? []; @@ -635,9 +645,20 @@ App::post('/v1/teams/:teamId/memberships') $message = $message->setParam('{{token}}', $url); $message = $message->render(); + $messageDoc = $dbForProject->createDocument('messages', new Document([ + 'to' => [$phone], + 'data' => [ + 'content' => $message, + 'from' => $from, + ], + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'deliveryTime' => Datetime::now(), + ])); + $messaging - ->setRecipient($phone) - ->setMessage($message) + ->setMessage($messageDoc) + ->setProject($project) ->trigger(); } } diff --git a/app/init.php b/app/init.php index 55757e3d28..6d90ea6dd9 100644 --- a/app/init.php +++ b/app/init.php @@ -25,7 +25,7 @@ use Appwrite\Event\Audit; use Appwrite\Event\Database as EventDatabase; use Appwrite\Event\Event; use Appwrite\Event\Mail; -use Appwrite\Event\Phone; +use Appwrite\Event\Messaging; use Appwrite\Event\Delete; use Appwrite\GraphQL\Schema; use Appwrite\Network\Validator\Email; @@ -948,7 +948,7 @@ App::setResource('audits', fn() => new Audit()); App::setResource('mails', fn() => new Mail()); App::setResource('deletes', fn() => new Delete()); App::setResource('database', fn() => new EventDatabase()); -App::setResource('messaging', fn() => new Phone()); +App::setResource('messaging', fn() => new Messaging()); App::setResource('queue', function (Group $pools) { return $pools->get('queue')->pop()->getResource(); }, ['pools']); diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 84af6fa802..ad0e5bcc4b 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -2,7 +2,9 @@ use Appwrite\Resque\Worker; use Utopia\CLI\Console; +use Utopia\Database\Document; use Utopia\Messaging\Adapters\SMS as SMSAdapter; +use Utopia\Messaging\Adapters\SMS\Mock; use Utopia\Messaging\Adapters\SMS\Msg91; use Utopia\Messaging\Adapters\SMS\Telesign; use Utopia\Messaging\Adapters\SMS\TextMagic; @@ -14,6 +16,9 @@ use Utopia\Messaging\Adapters\Push\FCM; use Utopia\Messaging\Adapters\Email as EmailAdapter; use Utopia\Messaging\Adapters\Email\Mailgun; use Utopia\Messaging\Adapters\Email\SendGrid; +use Utopia\Messaging\Messages\Email; +use Utopia\Messaging\Messages\Push; +use Utopia\Messaging\Messages\SMS; require_once __DIR__ . '/../init.php'; @@ -38,6 +43,7 @@ class MessagingV1 extends Worker { $credentials = $record->getAttribute('credentials'); return match ($record->getAttribute('provider')) { + 'mock' => new Mock('username', 'password'), 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), 'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']), 'telesign' => new Telesign($credentials['username'], $credentials['password']), @@ -79,11 +85,13 @@ class MessagingV1 extends Worker public function run(): void { - $providerId = $this->args['providerId']; - $providerRecord = - $this - ->getConsoleDB() - ->getDocument('providers', $providerId); + $project = new Document($this->args['project']); + + $dbForProject = $this->getProjectDB($project); + $message = new Document($this->args['message']); + + $providerId = $message->getAttribute('providerId'); + $providerRecord =$dbForProject->getDocument('providers', $providerId); $provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed. 'sms' => $this->sms($providerRecord), @@ -96,19 +104,13 @@ class MessagingV1 extends Worker // switch on provider name // call function passing needed credentials returns required provider. - $messageId = $this->args['messageId']; - $messageRecord = - $this - ->getConsoleDB() - ->getDocument('messages', $messageId); - $message = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($messageRecord->getArrayCopy()), - 'push' => $this->buildPushMessage($messageRecord->getArrayCopy()), - 'email' => $this->buildEmailMessage($messageRecord->getArrayCopy()), + 'sms' => $this->buildSMSMessage($message->getArrayCopy()), + 'push' => $this->buildPushMessage($message->getArrayCopy()), + 'email' => $this->buildEmailMessage($message->getArrayCopy()), default => null }; - + $provider->send($message); } @@ -117,46 +119,37 @@ class MessagingV1 extends Worker { } - private function buildEmailMessage($data): array + private function buildEmailMessage($data): Email { - $from = $data['from']; + $from = $data['data']['from']; $to = $data['to']; - $subject = $data['subject']; - $body = $data['content']; - - return [ - 'from' => $from, - 'to' => $to, - 'subject' => $subject, - 'body' => $body, - ]; + $subject = $data['data']['subject']; + $content = $data['data']['content']; + $html = $data['data']['html']; + return new Email(to: $to, subject: $subject, content: $content, from: $from, html: $html); } - private function buildSMSMessage($data): array + private function buildSMSMessage($data): SMS { - $from = $data['from']; $to = $data['to']; - $body = $data['content']; + $content = $data['data']['content']; + $from = $data['data']['from']; - return [ - 'from' => $from, - 'to' => $to, - 'body' => $body - ]; + return new SMS($to, $content, $from); } - private function buildPushMessage($data): array + private function buildPushMessage($data): Push { $to = $data['to']; - $title = $data['title']; - $body = $data['body']; - $data = $data['data']; - - return [ - 'to' => $to, - 'title' => $title, - 'body' => $body, - 'data' => $data - ]; + $title = $data['data']['title']; + $body = $data['data']['body']; + $data = $data['data']['data']; + $action = $data['data']['action']; + $sound = $data['data']['sound']; + $icon = $data['data']['icon']; + $color = $data['data']['color']; + $tag = $data['data']['tag']; + $badge = $data['data']['badge']; + return new Push($to, $title, $body, $data, $action, $sound, $icon, $color, $tag, $badge); } } diff --git a/composer.lock b/composer.lock index aeff7ad9d6..8eb26d06d7 100644 --- a/composer.lock +++ b/composer.lock @@ -386,79 +386,6 @@ }, "time": "2023-04-18T15:34:23+00:00" }, - { - "name": "composer/package-versions-deprecated", - "version": "1.11.99.5", - "source": { - "type": "git", - "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d", - "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1.0 || ^2.0", - "php": "^7 || ^8" - }, - "replace": { - "ocramius/package-versions": "1.11.99" - }, - "require-dev": { - "composer/composer": "^1.9.3 || ^2.0@dev", - "ext-zip": "^1.13", - "phpunit/phpunit": "^6.5 || ^7" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "support": { - "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-01-17T14:14:24+00:00" - }, { "name": "dragonmantank/cron-expression", "version": "v3.3.2", @@ -914,24 +841,28 @@ }, { "name": "jean85/pretty-package-versions", - "version": "1.6.0", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "1e0104b46f045868f11942aea058cd7186d6c303" + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/1e0104b46f045868f11942aea058cd7186d6c303", - "reference": "1e0104b46f045868f11942aea058cd7186d6c303", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", "shasum": "" }, "require": { - "composer/package-versions-deprecated": "^1.8.0", - "php": "^7.0|^8.0" + "composer-runtime-api": "^2.0.0", + "php": "^7.1|^8.0" }, "require-dev": { - "phpunit/phpunit": "^6.0|^8.5|^9.2" + "friendsofphp/php-cs-fixer": "^2.17", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7.5|^8.5|^9.4", + "vimeo/psalm": "^4.3" }, "type": "library", "extra": { @@ -954,7 +885,7 @@ "email": "alessandro.lai85@gmail.com" } ], - "description": "A wrapper for ocramius/package-versions to get pretty versions strings", + "description": "A library to get pretty versions strings of installed dependencies", "keywords": [ "composer", "package", @@ -963,9 +894,9 @@ ], "support": { "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/1.6.0" + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" }, - "time": "2021-02-04T16:20:16+00:00" + "time": "2021-10-08T21:21:46+00:00" }, { "name": "laravel/pint", @@ -1188,34 +1119,35 @@ }, { "name": "mongodb/mongodb", - "version": "1.8.0", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/mongodb/mongo-php-library.git", - "reference": "953dbc19443aa9314c44b7217a16873347e6840d" + "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/953dbc19443aa9314c44b7217a16873347e6840d", - "reference": "953dbc19443aa9314c44b7217a16873347e6840d", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b0bbd657f84219212487d01a8ffe93a789e1e488", + "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488", "shasum": "" }, "require": { "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.8.1", - "jean85/pretty-package-versions": "^1.2", - "php": "^7.0 || ^8.0", + "ext-mongodb": "^1.11.0", + "jean85/pretty-package-versions": "^1.2 || ^2.0.1", + "php": "^7.1 || ^8.0", "symfony/polyfill-php80": "^1.19" }, "require-dev": { - "squizlabs/php_codesniffer": "^3.5, <3.5.5", - "symfony/phpunit-bridge": "5.x-dev" + "doctrine/coding-standard": "^9.0", + "squizlabs/php_codesniffer": "^3.6", + "symfony/phpunit-bridge": "^5.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { @@ -1250,9 +1182,9 @@ ], "support": { "issues": "https://github.com/mongodb/mongo-php-library/issues", - "source": "https://github.com/mongodb/mongo-php-library/tree/1.8.0" + "source": "https://github.com/mongodb/mongo-php-library/tree/1.10.0" }, - "time": "2020-11-25T12:26:02+00:00" + "time": "2021-10-20T22:22:37+00:00" }, { "name": "mustangostang/spyc", @@ -2220,16 +2152,16 @@ }, { "name": "utopia-php/database", - "version": "0.43.0", + "version": "0.43.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "fb96fc6c94d5efcd43913c34bece62daba76a5e9" + "reference": "cc0247f4f0c402b39f663bf9f77b29d69b95f9d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/fb96fc6c94d5efcd43913c34bece62daba76a5e9", - "reference": "fb96fc6c94d5efcd43913c34bece62daba76a5e9", + "url": "https://api.github.com/repos/utopia-php/database/zipball/cc0247f4f0c402b39f663bf9f77b29d69b95f9d6", + "reference": "cc0247f4f0c402b39f663bf9f77b29d69b95f9d6", "shasum": "" }, "require": { @@ -2238,12 +2170,11 @@ "php": ">=8.0", "utopia-php/cache": "0.8.*", "utopia-php/framework": "0.*.*", - "utopia-php/mongo": "0.2.*" + "utopia-php/mongo": "0.3.*" }, "require-dev": { "fakerphp/faker": "^1.14", "laravel/pint": "1.4.*", - "mongodb/mongodb": "1.8.0", "pcov/clobber": "^2.0", "phpstan/phpstan": "1.10.*", "phpunit/phpunit": "^9.4", @@ -2271,9 +2202,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.43.0" + "source": "https://github.com/utopia-php/database/tree/0.43.1" }, - "time": "2023-08-29T10:18:39+00:00" + "time": "2023-09-01T20:38:36+00:00" }, { "name": "utopia-php/domains", @@ -2589,12 +2520,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "36aee6ae3c601b796364e35be083b909e02bef66" + "reference": "4ebebe97d80bb1de10d362c2464ba28717d333ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/36aee6ae3c601b796364e35be083b909e02bef66", - "reference": "36aee6ae3c601b796364e35be083b909e02bef66", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/4ebebe97d80bb1de10d362c2464ba28717d333ac", + "reference": "4ebebe97d80bb1de10d362c2464ba28717d333ac", "shasum": "" }, "require": { @@ -2629,7 +2560,7 @@ "issues": "https://github.com/utopia-php/messaging/issues", "source": "https://github.com/utopia-php/messaging/tree/feat-push" }, - "time": "2023-08-30T18:32:54+00:00" + "time": "2023-09-01T14:13:03+00:00" }, { "name": "utopia-php/migration", @@ -2691,21 +2622,21 @@ }, { "name": "utopia-php/mongo", - "version": "0.2.0", + "version": "0.3.1", "source": { "type": "git", "url": "https://github.com/utopia-php/mongo.git", - "reference": "b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09" + "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/mongo/zipball/b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09", - "reference": "b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09", + "url": "https://api.github.com/repos/utopia-php/mongo/zipball/52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", + "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", "shasum": "" }, "require": { "ext-mongodb": "*", - "mongodb/mongodb": "1.8.0", + "mongodb/mongodb": "1.10.0", "php": ">=8.0" }, "require-dev": { @@ -2745,9 +2676,9 @@ ], "support": { "issues": "https://github.com/utopia-php/mongo/issues", - "source": "https://github.com/utopia-php/mongo/tree/0.2.0" + "source": "https://github.com/utopia-php/mongo/tree/0.3.1" }, - "time": "2023-03-22T10:44:29+00:00" + "time": "2023-09-01T17:25:28+00:00" }, { "name": "utopia-php/orchestration", @@ -3460,16 +3391,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.34.1", + "version": "0.34.2", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "81538d10abacd81350c265b516c72ef315116013" + "reference": "06ea25aace27790e42d57fdbc7ccf97e0b31a6ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/81538d10abacd81350c265b516c72ef315116013", - "reference": "81538d10abacd81350c265b516c72ef315116013", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/06ea25aace27790e42d57fdbc7ccf97e0b31a6ba", + "reference": "06ea25aace27790e42d57fdbc7ccf97e0b31a6ba", "shasum": "" }, "require": { @@ -3505,9 +3436,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.34.1" + "source": "https://github.com/appwrite/sdk-generator/tree/0.34.2" }, - "time": "2023-08-30T07:57:31+00:00" + "time": "2023-08-31T14:10:33+00:00" }, { "name": "doctrine/deprecations", diff --git a/docker-compose.yml b/docker-compose.yml index b27c3581af..fe1237c95f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -544,8 +544,11 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_SMS_PROVIDER - - _APP_SMS_FROM + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php new file mode 100644 index 0000000000..db60d2ee23 --- /dev/null +++ b/src/Appwrite/Event/Messaging.php @@ -0,0 +1,56 @@ +message = $message; + + return $this; + } + + /** + * Returns set message for the messaging event. + * + * @return Document + */ + public function getMessage(): Document + { + return $this->message; + } + + /** + * Executes the event and sends it to the messaging worker. + * + * @return string|bool + * @throws \InvalidArgumentException + */ + public function trigger(): string|bool + { + return Resque::enqueue($this->queue, $this->class, [ + 'project' => $this->project, + 'user' => $this->user, + 'message' => $this->message, + ]); + } +} diff --git a/src/Appwrite/Event/Phone.php b/src/Appwrite/Event/Phone.php deleted file mode 100644 index 8baa5120c9..0000000000 --- a/src/Appwrite/Event/Phone.php +++ /dev/null @@ -1,80 +0,0 @@ -recipient = $recipient; - - return $this; - } - - /** - * Returns set recipient for this messaging event. - * - * @return string - */ - public function getRecipient(): string - { - return $this->recipient; - } - - /** - * Sets url for the messaging event. - * - * @param string $message - * @return self - */ - public function setMessage(string $message): self - { - $this->message = $message; - - return $this; - } - - /** - * Returns set url for the messaging event. - * - * @return string - */ - public function getMessage(): string - { - return $this->message; - } - - /** - * Executes the event and sends it to the messaging worker. - * - * @return string|bool - * @throws \InvalidArgumentException - */ - public function trigger(): string|bool - { - return Resque::enqueue($this->queue, $this->class, [ - 'project' => $this->project, - 'user' => $this->user, - 'payload' => $this->payload, - 'recipient' => $this->recipient, - 'message' => $this->message, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) - ]); - } -} diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 1441ab7f98..55ad0ddae3 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -2,8 +2,6 @@ namespace Tests\E2E\Services\Account; -use Appwrite\Extend\Exception; -use Appwrite\SMS\Adapter\Mock; use Appwrite\Tests\Retry; use Tests\E2E\Client; use Tests\E2E\Scopes\Scope; @@ -745,7 +743,22 @@ class AccountCustomClientTest extends Scope public function testCreatePhone(): array { $number = '+123456789'; - + $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/general' , \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => 'unique()', + 'name' => 'Mock', + 'provider' => 'mock', + 'type' => 'sms', + 'credentials' => [ + 'username' => 'username', + 'password' => 'password', + ], + 'default' => true, + ]); + $this->assertEquals(201, $response['headers']['status-code']); /** * Test for SUCCESS */ @@ -756,6 +769,7 @@ class AccountCustomClientTest extends Scope ]), [ 'userId' => ID::unique(), 'phone' => $number, + 'from' => $number, ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -999,7 +1013,7 @@ class AccountCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); + ]), ['from' => 'Appwrite']); $this->assertEquals(201, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); From 38d81c058b134466f8d5d85e2642b33f0470ace7 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 5 Sep 2023 23:10:33 +0530 Subject: [PATCH 062/196] lint fix --- app/controllers/api/account.php | 6 +++--- app/controllers/api/teams.php | 2 +- app/workers/messaging.php | 4 ++-- src/Appwrite/Event/Messaging.php | 2 +- tests/e2e/Services/Account/AccountCustomClientTest.php | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 1d73fac7c5..4b91af093f 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1238,7 +1238,7 @@ App::post('/v1/account/sessions/phone') ->inject('locale') ->action(function (string $userId, string $phone, string $from, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, Messaging $messaging, Locale $locale) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true, false]), + Query::equal('default', [true, false]), Query::equal('type', ['sms']) ])); if ($provider === false || $provider->isEmpty()) { @@ -1341,7 +1341,7 @@ App::post('/v1/account/sessions/phone') ->setMessage($messageDoc) ->setProject($project) ->trigger(); - + $events->setPayload( $response->output( $token->setAttribute('secret', $secret), @@ -2898,7 +2898,7 @@ App::post('/v1/account/verification/phone') ->inject('locale') ->action(function (string $from, Request $request, Response $response, Document $user, Database $dbForProject, Event $events, Messaging $messaging, Document $project, Locale $locale) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true, false]), + Query::equal('default', [true, false]), Query::equal('type', ['sms']) ])); if ($provider === false || $provider->isEmpty()) { diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index c453eaaea1..9588cb9c12 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -627,7 +627,7 @@ App::post('/v1/teams/:teamId/memberships') ; } elseif (!empty($phone)) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true, false]), + Query::equal('default', [true, false]), Query::equal('type', ['sms']) ])); diff --git a/app/workers/messaging.php b/app/workers/messaging.php index ad0e5bcc4b..079ff3397b 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -91,7 +91,7 @@ class MessagingV1 extends Worker $message = new Document($this->args['message']); $providerId = $message->getAttribute('providerId'); - $providerRecord =$dbForProject->getDocument('providers', $providerId); + $providerRecord = $dbForProject->getDocument('providers', $providerId); $provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed. 'sms' => $this->sms($providerRecord), @@ -110,7 +110,7 @@ class MessagingV1 extends Worker 'email' => $this->buildEmailMessage($message->getArrayCopy()), default => null }; - + $provider->send($message); } diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index db60d2ee23..9616f93a21 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -13,7 +13,7 @@ class Messaging extends Event { parent::__construct(Event::MESSAGING_QUEUE_NAME, Event::MESSAGING_CLASS_NAME); } - + /** diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 55ad0ddae3..9f922d63e2 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -743,7 +743,7 @@ class AccountCustomClientTest extends Scope public function testCreatePhone(): array { $number = '+123456789'; - $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/general' , \array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/general', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], From 039e717d721d9c740f95ab32f682511bb5527604 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 6 Sep 2023 15:40:56 +0530 Subject: [PATCH 063/196] fixes in send email endpoint --- app/controllers/api/messaging.php | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index e4302883c1..d5ff8784e6 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1,7 +1,9 @@ label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('providerId', '', new Text(128), 'Email Provider ID.') - ->param('to', [], new ArrayList(new Text(0)), 'Email Recepient.', true) - ->param('subject', null, new Text(0), 'Email Subject.', true) - ->param('content', null, new Text(0), 'Email Content.', true) - ->param('from', null, new Text(0), 'Email from.', false) - ->param('html', null, new Text(0), 'Is content of type HTML', false) - ->param('deliveryTime', null, new Datetime(), 'Delivery time of the message', false) + ->param('to', [], new ArrayList(new Text(0)), 'Email Recepient.') + ->param('subject', '', new Text(0), 'Email Subject.') + ->param('content', '', new Text(0), 'Email Content.') + ->param('from', '', new Text(0), 'Email from.') + ->param('html', false, new Boolean(false), 'Is content of type HTML', true) + ->param('deliveryTime', '', new DatetimeValidator(), 'Delivery time of the message', true) ->inject('dbForProject') - ->inject('events') + ->inject('project') + ->inject('messaging') ->inject('response') - ->action(function (string $providerId, string $to, string $subject, string $content, string $from, string $html, DateTime $deliveryTime, Database $dbForProject, Event $eventsInstance, Response $response) { + ->action(function (string $providerId, array $to, string $subject, string $content, string $from, string $html, string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1228,6 +1231,8 @@ App::post('/v1/messaging/messages/email') 'data' => [ 'subject' => $subject, 'content' => $content, + 'from' => $from, + 'html' => $html ], 'deliveryTime' => $deliveryTime, 'deliveryError' => null, @@ -1236,7 +1241,10 @@ App::post('/v1/messaging/messages/email') 'search' => null, ])); - $eventsInstance->setParam('messageId', $message->getId()); + $messaging + ->setMessage($message) + ->setProject($project) + ->trigger(); $response ->setStatusCode(Response::STATUS_CODE_CREATED) From 15773a35617057700c064a1a71ffe2c86bfc6a1c Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 6 Sep 2023 16:30:46 +0530 Subject: [PATCH 064/196] sets the correct response for send email --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index d5ff8784e6..f71219f010 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1248,5 +1248,5 @@ App::post('/v1/messaging/messages/email') $response ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_MESSAGE); + ->dynamic($message, Response::MODEL_MESSAGE); }); From ee0f789e372e94992c9d239edbd42f8d2de86b97 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Sat, 9 Sep 2023 01:18:26 +0530 Subject: [PATCH 065/196] udpates deliveryError to be an array type --- app/config/collections.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index f0acc33345..a316b02290 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1521,11 +1521,11 @@ $commonCollections = [ '$id' => ID::custom('deliveryError'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 2048, + 'size' => 16834, 'signed' => true, 'required' => false, 'default' => null, - 'array' => false, + 'array' => true, 'filters' => [], ], [ From f4f1aa4b5b09bd37a767662c9915b34ac8783f52 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Mon, 11 Sep 2023 19:27:45 +0530 Subject: [PATCH 066/196] review changes and adds missing subqueries --- app/config/collections.php | 88 ++++++++++++++++++++++++++++++-------- app/init.php | 41 ++++++++++++++++++ 2 files changed, 110 insertions(+), 19 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index a316b02290..398db4929f 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1437,22 +1437,61 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => ['json', 'encrypt'], - ] + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 65535, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ '$id' => ID::custom('_key_provider'), 'type' => Database::INDEX_KEY, 'attributes' => ['provider'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => ID::custom('_key_name'), 'type' => Database::INDEX_FULLTEXT, 'attributes' => ['name'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_type'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['type'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_default'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['default'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_default_type'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['default, type'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_search'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['search'], + 'lengths' => [], + 'orders' => [], ] ], ], @@ -1488,7 +1527,7 @@ $commonCollections = [ '$id' => ID::custom('data'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 16384, + 'size' => 65535, 'signed' => true, 'required' => true, 'default' => null, @@ -1499,7 +1538,7 @@ $commonCollections = [ '$id' => ID::custom('to'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 16834, + 'size' => 65535, 'signed' => true, 'required' => true, 'default' => null, @@ -1518,10 +1557,10 @@ $commonCollections = [ 'filters' => ['datetime'], ], [ - '$id' => ID::custom('deliveryError'), + '$id' => ID::custom('deliveryErrors'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 16834, + 'size' => 65535, 'signed' => true, 'required' => false, 'default' => null, @@ -1567,14 +1606,14 @@ $commonCollections = [ '$id' => ID::custom('_key_providerId'), 'type' => Database::INDEX_KEY, 'attributes' => ['providerId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => ID::custom('_key_providerInternalId'), 'type' => Database::INDEX_KEY, 'attributes' => ['providerInternalId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ @@ -1646,21 +1685,32 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => ['subQueryTopicTargets'], - ] + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ '$id' => ID::custom('_key_providerId'), 'type' => Database::INDEX_KEY, 'attributes' => ['providerId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => ID::custom('_key_providerInternalId'), 'type' => Database::INDEX_KEY, 'attributes' => ['providerInternalId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ @@ -1671,12 +1721,12 @@ $commonCollections = [ 'orders' => [], ], [ - '$id' => ID::custom('_key_description'), + '$id' => ID::custom('_key_search'), 'type' => Database::INDEX_FULLTEXT, - 'attributes' => ['description'], + 'attributes' => ['name'], 'lengths' => [], - 'orders' => [], - ], + 'orders' => [Database::ORDER_ASC], + ] ], ], @@ -1826,7 +1876,7 @@ $commonCollections = [ '$id' => ID::custom('identifier'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => Database::LENGTH_KEY, + 'size' => 2048, 'signed' => true, 'required' => true, 'default' => null, @@ -1839,14 +1889,14 @@ $commonCollections = [ '$id' => ID::custom('_key_userId'), 'type' => Database::INDEX_KEY, 'attributes' => ['userId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => ID::custom('_key_userInternalId'), 'type' => Database::INDEX_KEY, 'attributes' => ['userInternalId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ diff --git a/app/init.php b/app/init.php index f2d7bc7db4..0df1280051 100644 --- a/app/init.php +++ b/app/init.php @@ -543,6 +543,47 @@ Database::addFilter( ])); } ); + +Database::addFilter( + 'subQueryProviderType', + function (mixed $value) { + return null; + }, + function (mixed $value, Document $document, Database $database) { + $provider = Authorization::skip(fn () => $database + ->getDocument( + 'providers', + $document->getAttribute('providerId'), + [Query::select(['type'])] + )); + if ($provider) { + return $provider->getAttribute('type'); + } + return null; + } +); + + +Database::addFilter( + 'subQueryTopicTargets', + function (mixed $value) { + return null; + }, + function (mixed $value, Document $document, Database $database) { + $targetIds = Authorization::skip(fn () => \array_map( + fn ($document) => $document->getAttribute('targetId'), + $database + ->find('subscribers', [ + Query::equal('topicInternalId', [$document->getInternalId()]), + Query::limit(APP_LIMIT_SUBQUERY), + ]) + )); + if (\count($targetIds) > 0) { + return $database->find('targets', [Query::equal('$id', $targetIds)]); + } + return []; + } +); /** * DB Formats */ From 2ecf9ee98a7801390f0873a1b549f46224dbf3aa Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Mon, 11 Sep 2023 19:53:48 +0530 Subject: [PATCH 067/196] udpates send email endpoint according to collection changes --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index f71219f010..5355b56721 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1235,7 +1235,7 @@ App::post('/v1/messaging/messages/email') 'html' => $html ], 'deliveryTime' => $deliveryTime, - 'deliveryError' => null, + 'deliveryErrors' => null, 'deliveredTo' => null, 'delivered' => false, 'search' => null, From a59cfb64614e730bc8f62e48e25124b7450a1149 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Mon, 11 Sep 2023 20:30:21 +0530 Subject: [PATCH 068/196] review changes --- app/config/messagingProviders.php | 300 ------------------ src/Appwrite/Utopia/Response.php | 6 +- .../Utopia/Response/Model/Message.php | 15 +- .../Utopia/Response/Model/Project.php | 2 +- .../Utopia/Response/Model/Provider.php | 6 +- 5 files changed, 8 insertions(+), 321 deletions(-) delete mode 100644 app/config/messagingProviders.php diff --git a/app/config/messagingProviders.php b/app/config/messagingProviders.php deleted file mode 100644 index a33665196b..0000000000 --- a/app/config/messagingProviders.php +++ /dev/null @@ -1,300 +0,0 @@ - [ - 'mailchimp' => [ - 'name' => 'Mailchimp', - 'developers' => 'https://mailchimp.com/developer/marketing/api/', - 'icon' => 'icon-mailchimp', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'mailgun' => [ - 'name' => 'Mailgun', - 'developers' => 'https://documentation.mailgun.com/', - 'icon' => 'icon-mailgun', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'mailjet' => [ - 'name' => 'Mailjet', - 'developers' => 'https://dev.mailjet.com/', - 'icon' => 'icon-mailjet', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'postmark' => [ - 'name' => 'Postmark', - 'developers' => 'https://postmarkapp.com/developer', - 'icon' => 'icon-postmark', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sendgrid' => [ - 'name' => 'Sendgrid', - 'developers' => 'https://docs.sendgrid.com/api-reference/how-to-use-the-sendgrid-v3-api/', - 'icon' => 'icon-sendgrid', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sendinblue' => [ - 'name' => 'SendinBlue', - 'developers' => 'https://developers.sendinblue.com/', - 'icon' => 'icon-sendinblue', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'mailslurp' => [ - 'name' => 'MailSlurp', - 'developers' => 'https://www.mailslurp.com/docs/', - 'icon' => 'icon-mailslurp', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'elasticemail' => [ - 'name' => 'ElasticEmail', - 'developers' => 'https://api.elasticemail.com/public/help', - 'icon' => 'icon-elasticemail', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'ses' => [ - 'name' => 'SES', - 'developers' => 'https://docs.aws.amazon.com/ses/latest/APIReference/', - 'icon' => 'icon-ses', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - ], - 'sms' => [ - 'africastalking' => [ - 'name' => 'Africa\'s Talking', - 'developers' => 'https://developers.africastalking.com/', - 'icon' => 'icon-africastalking', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'clickatell' => [ - 'name' => 'Clickatell', - 'developers' => 'https://www.clickatell.com/developers/api-docs/', - 'icon' => 'icon-clickatell', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'infobip' => [ - 'name' => 'Infobip', - 'developers' => 'https://www.infobip.com/docs/', - 'icon' => 'icon-infobip', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'msg91' => [ - 'name' => 'Msg91', - 'developers' => 'https://docs.msg91.com/reference/overview', - 'icon' => 'icon-msg91', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'plivo' => [ - 'name' => 'Plivo', - 'developers' => 'https://developers.plivo.com/', - 'icon' => 'icon-plivo', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sinch' => [ - 'name' => 'Sinch', - 'developers' => 'https://developers.sinch.com/', - 'icon' => 'icon-sinch', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'sms77' => [ - 'name' => 'Sms77', - 'developers' => 'https://sms77.io/docs/gateway/', - 'icon' => 'icon-sms77', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'telesign' => [ - 'name' => 'Telesign', - 'developers' => 'https://developer.telesign.com/enterprise/docs', - 'icon' => 'icon-telesign', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'textmagic' => [ - 'name' => 'TextMagic', - 'developers' => 'https://www.textmagic.com/docs/api/', - 'icon' => 'icon-twilio', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'twilio' => [ - 'name' => 'Twilio', - 'developers' => 'https://www.twilio.com/docs/sms', - 'icon' => 'icon-twilio', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'twilio-notify' => [ - 'name' => 'Twilio Notify', - 'developers' => 'https://www.twilio.com/docs/notify', - 'icon' => 'icon-twilio', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'vonage' => [ - 'name' => 'Vonage', - 'developers' => 'https://developer.nexmo.com/', - 'icon' => 'icon-vonage', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - ], - 'push' => [ - 'apns' => [ - 'name' => 'APNS', - 'developers' => 'https://developer.apple.com/documentation/usernotifications', - 'icon' => 'icon-apns', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'fcm' => [ - 'name' => 'FCM', - 'developers' => 'https://firebase.google.com/docs/cloud-messaging', - 'icon' => 'icon-fcm', - 'enabled' => true, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'one_signal' => [ - 'name' => 'OneSignal', - 'developers' => 'https://documentation.onesignal.com/docs', - 'icon' => 'icon-onesignal', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'pushbullet' => [ - 'name' => 'PushBullet', - 'developers' => 'https://docs.pushbullet.com/', - 'icon' => 'icon-pushbullet', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'pusher' => [ - 'name' => 'Pusher', - 'developers' => 'https://pusher.com/docs', - 'icon' => 'icon-pusher', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'pushwoosh' => [ - 'name' => 'Pushwoosh', - 'developers' => 'https://www.pushwoosh.com/docs/', - 'icon' => 'icon-pushwoosh', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'urban_airship' => [ - 'name' => 'Urban Airship', - 'developers' => 'https://docs.airship.com/api/', - 'icon' => 'icon-urbanairship', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - 'web_push' => [ - 'name' => 'WebPush', - 'developers' => 'https://developer.mozilla.org/en-US/docs/Web/API/Push_API', - 'icon' => 'icon-webpush', - 'enabled' => false, - 'sandbox' => false, - 'form' => false, - 'beta' => false, - 'mock' => false, - ], - ] -]; diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 90a5546548..7a2a040d94 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -2,9 +2,6 @@ namespace Appwrite\Utopia; -use Appwrite\Utopia\Response\Model\Message; -use Appwrite\Utopia\Response\Model\Subscriber; -use Appwrite\Utopia\Response\Model\Topic; use Exception; use Swoole\Http\Request as SwooleRequest; use Utopia\Swoole\Response as SwooleResponse; @@ -84,6 +81,9 @@ use Appwrite\Utopia\Response\Model\HealthVersion; use Appwrite\Utopia\Response\Model\Installation; use Appwrite\Utopia\Response\Model\LocaleCode; use Appwrite\Utopia\Response\Model\Provider; +use Appwrite\Utopia\Response\Model\Message; +use Appwrite\Utopia\Response\Model\Subscriber; +use Appwrite\Utopia\Response\Model\Topic; use Appwrite\Utopia\Response\Model\ProviderRepository; use Appwrite\Utopia\Response\Model\Runtime; use Appwrite\Utopia\Response\Model\Target; diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 177058be9b..14940050fe 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -6,7 +6,7 @@ use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\DateTime; -class Message extends Model +class Message extends Any { /** * @var bool @@ -28,13 +28,6 @@ class Message extends Model 'default' => '', 'example' => '5e5ea5c16897e', ]) - ->addRule('data', [ - 'type' => self::TYPE_JSON, - 'description' => 'Message Data.', - 'default' => '', - 'required' => false, - 'example' => '', - ]) ->addRule('to', [ 'type' => self::TYPE_STRING, 'description' => 'Recipient of message.', @@ -66,12 +59,6 @@ class Message extends Model 'description' => 'Status of delivery.', 'default' => '', 'example' => true, - ]) - ->addRule('search', [ - 'type' => self::TYPE_STRING, - 'description' => 'Field that can be used for searching message.', - 'default' => '', - 'example' => 'Hello everyone', ]); } diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 885e7e9af6..5f78ff82cc 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -138,7 +138,7 @@ class Project extends Model 'default' => false, 'example' => true, ]) - ->addRule('providers', [ + ->addRule('authProviders', [ 'type' => Response::MODEL_AUTH_PROVIDER, 'description' => 'List of Auth Providers.', 'default' => [], diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index 0cbc233fc3..668db553fc 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -23,19 +23,19 @@ class Provider extends Model ]) ->addRule('name', [ 'type' => self::TYPE_STRING, - 'description' => 'The user-given name for the provider instance.', + 'description' => 'The name for the provider instance.', 'default' => '', 'example' => 'Mailgun', ]) ->addRule('provider', [ 'type' => self::TYPE_STRING, - 'description' => 'Provider name setup in Utopia.', + 'description' => 'The name of the provider service.', 'default' => '', 'example' => 'mailgun', ]) ->addRule('default', [ 'type' => self::TYPE_BOOLEAN, - 'description' => 'Default provider or not.', + 'description' => 'Is this a pre-configured provider instance?', 'default' => '', 'example' => true, ]) From 78a2f6f2467e9d45e1a46f5938d05d83d3b7e987 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Mon, 11 Sep 2023 20:36:43 +0530 Subject: [PATCH 069/196] review changes --- src/Appwrite/Utopia/Response/Model/Message.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 14940050fe..150e837853 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -32,6 +32,7 @@ class Message extends Any 'type' => self::TYPE_STRING, 'description' => 'Recipient of message.', 'default' => '', + 'array' => true, 'example' => ['user-1'], ]) ->addRule('deliveryTime', [ @@ -46,6 +47,7 @@ class Message extends Any 'description' => 'Delivery error if any.', 'required' => false, 'default' => '', + 'array' => true, 'example' => 'Provider not valid.', ]) ->addRule('deliveredTo', [ From cbea4264eaf72eb8bde43a2cd8eb24103904ad0c Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 12 Sep 2023 20:53:16 +0530 Subject: [PATCH 070/196] merge master --- .env | 68 +- .github/workflows/tests.yml | 4 +- .gitmodules | 2 +- CHANGES.md | 51 +- CONTRIBUTING.md | 6 +- Dockerfile | 73 +- README-CN.md | 6 +- README.md | 8 +- SECURITY.md | 1 + app/cli.php | 27 +- app/config/cloud/contributors.json | 1 - app/config/cloud/employees.json | 33 - app/config/cloud/heroes.json | 9 - app/config/collections.php | 1823 +++++++++++++---- app/config/errors.php | 157 +- app/config/events.php | 14 + app/config/locale/templates/email-base.tpl | 30 +- .../locale/templates/email-inner-base.tpl | 15 + app/config/locale/translations/af.json | 4 +- app/config/locale/translations/ar.json | 4 +- app/config/locale/translations/as.json | 4 +- app/config/locale/translations/az.json | 4 +- app/config/locale/translations/be.json | 4 +- app/config/locale/translations/bh.json | 4 +- app/config/locale/translations/bn.json | 4 +- app/config/locale/translations/ca.json | 4 +- app/config/locale/translations/da.json | 4 +- app/config/locale/translations/de.json | 4 +- app/config/locale/translations/el.json | 4 +- app/config/locale/translations/en.json | 4 +- app/config/locale/translations/eo.json | 4 +- app/config/locale/translations/es.json | 4 +- app/config/locale/translations/fa.json | 12 +- app/config/locale/translations/fr.json | 4 +- app/config/locale/translations/ga.json | 4 +- app/config/locale/translations/gu.json | 4 +- app/config/locale/translations/he.json | 4 +- app/config/locale/translations/hi.json | 4 +- app/config/locale/translations/hr.json | 4 +- app/config/locale/translations/hu.json | 4 +- app/config/locale/translations/id.json | 4 +- app/config/locale/translations/it.json | 4 +- app/config/locale/translations/ja.json | 4 +- app/config/locale/translations/jv.json | 4 +- app/config/locale/translations/kn.json | 4 +- app/config/locale/translations/ko.json | 4 +- app/config/locale/translations/la.json | 4 +- app/config/locale/translations/lb.json | 4 +- app/config/locale/translations/lt.json | 4 +- app/config/locale/translations/lv.json | 4 +- app/config/locale/translations/ml.json | 4 +- app/config/locale/translations/mr.json | 4 +- app/config/locale/translations/ms.json | 4 +- app/config/locale/translations/nb.json | 4 +- app/config/locale/translations/ne.json | 4 +- app/config/locale/translations/nl.json | 4 +- app/config/locale/translations/nn.json | 4 +- app/config/locale/translations/or.json | 4 +- app/config/locale/translations/pl.json | 4 +- app/config/locale/translations/pt-br.json | 4 +- app/config/locale/translations/pt-pt.json | 4 +- app/config/locale/translations/ro.json | 4 +- app/config/locale/translations/ru.json | 4 +- app/config/locale/translations/sa.json | 4 +- app/config/locale/translations/sd.json | 4 +- app/config/locale/translations/si.json | 4 +- app/config/locale/translations/sk.json | 4 +- app/config/locale/translations/sn.json | 4 +- app/config/locale/translations/sv.json | 4 +- app/config/locale/translations/ta.json | 4 +- app/config/locale/translations/te.json | 4 +- app/config/locale/translations/th.json | 4 +- app/config/locale/translations/tl.json | 4 +- app/config/locale/translations/uk.json | 4 +- app/config/locale/translations/ur.json | 4 +- app/config/locale/translations/vi.json | 4 +- app/config/locale/translations/zh-cn.json | 4 +- app/config/locale/translations/zh-tw.json | 4 +- app/config/platforms.php | 30 +- app/config/providers.php | 3 +- app/config/roles.php | 19 +- app/config/runtimes.php | 2 +- app/config/scopes.php | 21 + app/config/services.php | 39 + app/config/specs/open-api3-1.4.x-client.json | 2 +- app/config/specs/open-api3-1.4.x-console.json | 2 +- app/config/specs/open-api3-1.4.x-server.json | 2 +- app/config/specs/open-api3-latest-client.json | 2 +- .../specs/open-api3-latest-console.json | 2 +- app/config/specs/open-api3-latest-server.json | 2 +- app/config/specs/swagger2-1.4.x-client.json | 2 +- app/config/specs/swagger2-1.4.x-console.json | 2 +- app/config/specs/swagger2-1.4.x-server.json | 2 +- app/config/specs/swagger2-latest-client.json | 2 +- app/config/specs/swagger2-latest-console.json | 2 +- app/config/specs/swagger2-latest-server.json | 2 +- app/config/variables.php | 247 ++- app/controllers/api/account.php | 647 ++++-- app/controllers/api/avatars.php | 29 +- app/controllers/api/console.php | 26 +- app/controllers/api/databases.php | 848 ++++---- app/controllers/api/functions.php | 1118 +++++++--- app/controllers/api/migrations.php | 992 +++++++++ app/controllers/api/project.php | 349 +++- app/controllers/api/projects.php | 580 +++--- app/controllers/api/proxy.php | 316 +++ app/controllers/api/storage.php | 351 ++-- app/controllers/api/teams.php | 122 +- app/controllers/api/users.php | 302 ++- app/controllers/api/vcs.php | 1090 ++++++++++ app/controllers/general.php | 257 ++- app/controllers/mock.php | 32 +- app/controllers/shared/api.php | 224 +- app/controllers/web/console.php | 8 + app/controllers/web/home.php | 2 +- app/http.php | 36 +- app/init.php | 257 ++- app/realtime.php | 2 +- app/views/install/compose.phtml | 285 ++- app/worker.php | 23 +- app/workers/builds.php | 540 +++-- app/workers/certificates.php | 95 +- app/workers/deletes.php | 185 +- app/workers/functions.php | 227 +- app/workers/mails.php | 37 +- app/workers/migrations.php | 308 +++ app/workers/usage.php | 288 --- bin/upgrade | 3 + bin/usage | 3 + bin/worker-migrations | 10 + bin/worker-usage | 3 - composer.json | 17 +- composer.lock | 1030 +++++++++- docker-compose.yml | 397 ++-- .../java/account/create-anonymous-session.md | 18 + .../java/account/create-email-session.md | 22 + .../java/account/create-j-w-t.md | 18 + .../account/create-magic-u-r-l-session.md | 22 + .../java/account/create-o-auth2session.md | 21 + .../java/account/create-phone-session.md | 22 + .../java/account/create-phone-verification.md | 18 + .../java/account/create-recovery.md | 22 + .../java/account/create-verification.md | 21 + .../client-android/java/account/create.md | 23 + .../java/account/delete-identity.md | 21 + .../java/account/delete-session.md | 21 + .../java/account/delete-sessions.md | 18 + .../client-android/java/account/get-prefs.md | 18 + .../java/account/get-session.md | 21 + .../1.4.x/client-android/java/account/get.md | 18 + .../java/account/list-identities.md | 20 + .../client-android/java/account/list-logs.md | 20 + .../java/account/list-sessions.md | 18 + .../java/account/update-email.md | 22 + .../account/update-magic-u-r-l-session.md | 22 + .../java/account/update-name.md | 21 + .../java/account/update-password.md | 21 + .../java/account/update-phone-session.md | 22 + .../java/account/update-phone-verification.md | 22 + .../java/account/update-phone.md | 22 + .../java/account/update-prefs.md | 21 + .../java/account/update-recovery.md | 24 + .../java/account/update-session.md | 21 + .../java/account/update-status.md | 18 + .../java/account/update-verification.md | 22 + .../java/avatars/get-browser.md | 21 + .../java/avatars/get-credit-card.md | 21 + .../java/avatars/get-favicon.md | 21 + .../client-android/java/avatars/get-flag.md | 21 + .../client-android/java/avatars/get-image.md | 21 + .../java/avatars/get-initials.md | 20 + .../client-android/java/avatars/get-q-r.md | 21 + .../java/databases/create-document.md | 24 + .../java/databases/delete-document.md | 23 + .../java/databases/get-document.md | 23 + .../java/databases/list-documents.md | 22 + .../java/databases/update-document.md | 23 + .../java/functions/create-execution.md | 21 + .../java/functions/get-execution.md | 22 + .../java/functions/list-executions.md | 21 + .../client-android/java/graphql/mutation.md | 21 + .../client-android/java/graphql/query.md | 21 + .../1.4.x/client-android/java/locale/get.md | 18 + .../client-android/java/locale/list-codes.md | 18 + .../java/locale/list-continents.md | 18 + .../java/locale/list-countries-e-u.md | 18 + .../java/locale/list-countries-phones.md | 18 + .../java/locale/list-countries.md | 18 + .../java/locale/list-currencies.md | 18 + .../java/locale/list-languages.md | 18 + .../java/storage/create-file.md | 24 + .../java/storage/delete-file.md | 22 + .../java/storage/get-file-download.md | 22 + .../java/storage/get-file-preview.md | 22 + .../java/storage/get-file-view.md | 22 + .../client-android/java/storage/get-file.md | 22 + .../client-android/java/storage/list-files.md | 21 + .../java/storage/update-file.md | 22 + .../java/teams/create-membership.md | 23 + .../1.4.x/client-android/java/teams/create.md | 22 + .../java/teams/delete-membership.md | 22 + .../1.4.x/client-android/java/teams/delete.md | 21 + .../java/teams/get-membership.md | 22 + .../client-android/java/teams/get-prefs.md | 21 + .../1.4.x/client-android/java/teams/get.md | 21 + .../java/teams/list-memberships.md | 21 + .../1.4.x/client-android/java/teams/list.md | 20 + .../java/teams/update-membership-status.md | 24 + .../java/teams/update-membership.md | 23 + .../client-android/java/teams/update-name.md | 22 + .../client-android/java/teams/update-prefs.md | 22 + .../account/create-anonymous-session.md | 10 + .../kotlin/account/create-email-session.md | 13 + .../kotlin/account/create-j-w-t.md | 10 + .../account/create-magic-u-r-l-session.md | 13 + .../kotlin/account/create-o-auth2session.md | 12 + .../kotlin/account/create-phone-session.md | 13 + .../account/create-phone-verification.md | 10 + .../kotlin/account/create-recovery.md | 13 + .../kotlin/account/create-verification.md | 12 + .../client-android/kotlin/account/create.md | 14 + .../kotlin/account/delete-identity.md | 12 + .../kotlin/account/delete-session.md | 12 + .../kotlin/account/delete-sessions.md | 10 + .../kotlin/account/get-prefs.md | 10 + .../kotlin/account/get-session.md | 12 + .../client-android/kotlin/account/get.md | 10 + .../kotlin/account/list-identities.md | 11 + .../kotlin/account/list-logs.md | 11 + .../kotlin/account/list-sessions.md | 10 + .../kotlin/account/update-email.md | 13 + .../account/update-magic-u-r-l-session.md | 13 + .../kotlin/account/update-name.md | 12 + .../kotlin/account/update-password.md | 12 + .../kotlin/account/update-phone-session.md | 13 + .../account/update-phone-verification.md | 13 + .../kotlin/account/update-phone.md | 13 + .../kotlin/account/update-prefs.md | 12 + .../kotlin/account/update-recovery.md | 15 + .../kotlin/account/update-session.md | 12 + .../kotlin/account/update-status.md | 10 + .../kotlin/account/update-verification.md | 13 + .../kotlin/avatars/get-browser.md | 12 + .../kotlin/avatars/get-credit-card.md | 12 + .../kotlin/avatars/get-favicon.md | 12 + .../client-android/kotlin/avatars/get-flag.md | 12 + .../kotlin/avatars/get-image.md | 12 + .../kotlin/avatars/get-initials.md | 11 + .../client-android/kotlin/avatars/get-q-r.md | 12 + .../kotlin/databases/create-document.md | 15 + .../kotlin/databases/delete-document.md | 14 + .../kotlin/databases/get-document.md | 14 + .../kotlin/databases/list-documents.md | 13 + .../kotlin/databases/update-document.md | 14 + .../kotlin/functions/create-execution.md | 12 + .../kotlin/functions/get-execution.md | 13 + .../kotlin/functions/list-executions.md | 12 + .../client-android/kotlin/graphql/mutation.md | 12 + .../client-android/kotlin/graphql/query.md | 12 + .../1.4.x/client-android/kotlin/locale/get.md | 10 + .../kotlin/locale/list-codes.md | 10 + .../kotlin/locale/list-continents.md | 10 + .../kotlin/locale/list-countries-e-u.md | 10 + .../kotlin/locale/list-countries-phones.md | 10 + .../kotlin/locale/list-countries.md | 10 + .../kotlin/locale/list-currencies.md | 10 + .../kotlin/locale/list-languages.md | 10 + .../kotlin/storage/create-file.md | 15 + .../kotlin/storage/delete-file.md | 13 + .../kotlin/storage/get-file-download.md | 13 + .../kotlin/storage/get-file-preview.md | 13 + .../kotlin/storage/get-file-view.md | 13 + .../client-android/kotlin/storage/get-file.md | 13 + .../kotlin/storage/list-files.md | 12 + .../kotlin/storage/update-file.md | 13 + .../kotlin/teams/create-membership.md | 14 + .../client-android/kotlin/teams/create.md | 13 + .../kotlin/teams/delete-membership.md | 13 + .../client-android/kotlin/teams/delete.md | 12 + .../kotlin/teams/get-membership.md | 13 + .../client-android/kotlin/teams/get-prefs.md | 12 + .../1.4.x/client-android/kotlin/teams/get.md | 12 + .../kotlin/teams/list-memberships.md | 12 + .../1.4.x/client-android/kotlin/teams/list.md | 11 + .../kotlin/teams/update-membership-status.md | 15 + .../kotlin/teams/update-membership.md | 14 + .../kotlin/teams/update-name.md | 13 + .../kotlin/teams/update-prefs.md | 13 + .../account/create-anonymous-session.md | 10 + .../examples/account/create-email-session.md | 13 + .../examples/account/create-j-w-t.md | 10 + .../account/create-magic-u-r-l-session.md | 13 + .../examples/account/create-o-auth2session.md | 12 + .../examples/account/create-phone-session.md | 13 + .../account/create-phone-verification.md | 10 + .../examples/account/create-recovery.md | 13 + .../examples/account/create-verification.md | 12 + .../client-apple/examples/account/create.md | 14 + .../examples/account/delete-identity.md | 12 + .../examples/account/delete-session.md | 12 + .../examples/account/delete-sessions.md | 10 + .../examples/account/get-prefs.md | 10 + .../examples/account/get-session.md | 12 + .../client-apple/examples/account/get.md | 10 + .../examples/account/list-identities.md | 10 + .../examples/account/list-logs.md | 10 + .../examples/account/list-sessions.md | 10 + .../examples/account/update-email.md | 13 + .../account/update-magic-u-r-l-session.md | 13 + .../examples/account/update-name.md | 12 + .../examples/account/update-password.md | 12 + .../examples/account/update-phone-session.md | 13 + .../account/update-phone-verification.md | 13 + .../examples/account/update-phone.md | 13 + .../examples/account/update-prefs.md | 12 + .../examples/account/update-recovery.md | 15 + .../examples/account/update-session.md | 12 + .../examples/account/update-status.md | 10 + .../examples/account/update-verification.md | 13 + .../examples/avatars/get-browser.md | 12 + .../examples/avatars/get-credit-card.md | 12 + .../examples/avatars/get-favicon.md | 12 + .../client-apple/examples/avatars/get-flag.md | 12 + .../examples/avatars/get-image.md | 12 + .../examples/avatars/get-initials.md | 10 + .../client-apple/examples/avatars/get-q-r.md | 12 + .../examples/databases/create-document.md | 15 + .../examples/databases/delete-document.md | 14 + .../examples/databases/get-document.md | 14 + .../examples/databases/list-documents.md | 13 + .../examples/databases/update-document.md | 14 + .../examples/functions/create-execution.md | 12 + .../examples/functions/get-execution.md | 13 + .../examples/functions/list-executions.md | 12 + .../client-apple/examples/graphql/mutation.md | 12 + .../client-apple/examples/graphql/query.md | 12 + .../1.4.x/client-apple/examples/locale/get.md | 10 + .../examples/locale/list-codes.md | 10 + .../examples/locale/list-continents.md | 10 + .../examples/locale/list-countries-e-u.md | 10 + .../examples/locale/list-countries-phones.md | 10 + .../examples/locale/list-countries.md | 10 + .../examples/locale/list-currencies.md | 10 + .../examples/locale/list-languages.md | 10 + .../examples/storage/create-file.md | 14 + .../examples/storage/delete-file.md | 13 + .../examples/storage/get-file-download.md | 13 + .../examples/storage/get-file-preview.md | 13 + .../examples/storage/get-file-view.md | 13 + .../client-apple/examples/storage/get-file.md | 13 + .../examples/storage/list-files.md | 12 + .../examples/storage/update-file.md | 13 + .../examples/teams/create-membership.md | 14 + .../client-apple/examples/teams/create.md | 13 + .../examples/teams/delete-membership.md | 13 + .../client-apple/examples/teams/delete.md | 12 + .../examples/teams/get-membership.md | 13 + .../client-apple/examples/teams/get-prefs.md | 12 + .../1.4.x/client-apple/examples/teams/get.md | 12 + .../examples/teams/list-memberships.md | 12 + .../1.4.x/client-apple/examples/teams/list.md | 10 + .../teams/update-membership-status.md | 15 + .../examples/teams/update-membership.md | 14 + .../examples/teams/update-name.md | 13 + .../examples/teams/update-prefs.md | 13 + .../account/create-anonymous-session.md | 19 + .../examples/account/create-email-session.md | 22 + .../examples/account/create-j-w-t.md | 19 + .../account/create-magic-u-r-l-session.md | 22 + .../examples/account/create-o-auth2session.md | 21 + .../examples/account/create-phone-session.md | 22 + .../account/create-phone-verification.md | 19 + .../examples/account/create-recovery.md | 22 + .../examples/account/create-verification.md | 21 + .../client-flutter/examples/account/create.md | 23 + .../examples/account/delete-identity.md | 21 + .../examples/account/delete-session.md | 21 + .../examples/account/delete-sessions.md | 19 + .../examples/account/get-prefs.md | 19 + .../examples/account/get-session.md | 21 + .../client-flutter/examples/account/get.md | 19 + .../examples/account/list-identities.md | 20 + .../examples/account/list-logs.md | 20 + .../examples/account/list-sessions.md | 19 + .../examples/account/update-email.md | 22 + .../account/update-magic-u-r-l-session.md | 22 + .../examples/account/update-name.md | 21 + .../examples/account/update-password.md | 21 + .../examples/account/update-phone-session.md | 22 + .../account/update-phone-verification.md | 22 + .../examples/account/update-phone.md | 22 + .../examples/account/update-prefs.md | 21 + .../examples/account/update-recovery.md | 24 + .../examples/account/update-session.md | 21 + .../examples/account/update-status.md | 19 + .../examples/account/update-verification.md | 22 + .../examples/avatars/get-browser.md | 34 + .../examples/avatars/get-credit-card.md | 34 + .../examples/avatars/get-favicon.md | 34 + .../examples/avatars/get-flag.md | 34 + .../examples/avatars/get-image.md | 34 + .../examples/avatars/get-initials.md | 32 + .../examples/avatars/get-q-r.md | 34 + .../examples/databases/create-document.md | 24 + .../examples/databases/delete-document.md | 23 + .../examples/databases/get-document.md | 23 + .../examples/databases/list-documents.md | 22 + .../examples/databases/update-document.md | 23 + .../examples/functions/create-execution.md | 21 + .../examples/functions/get-execution.md | 22 + .../examples/functions/list-executions.md | 21 + .../examples/graphql/mutation.md | 21 + .../client-flutter/examples/graphql/query.md | 21 + .../client-flutter/examples/locale/get.md | 19 + .../examples/locale/list-codes.md | 19 + .../examples/locale/list-continents.md | 19 + .../examples/locale/list-countries-e-u.md | 19 + .../examples/locale/list-countries-phones.md | 19 + .../examples/locale/list-countries.md | 19 + .../examples/locale/list-currencies.md | 19 + .../examples/locale/list-languages.md | 19 + .../examples/storage/create-file.md | 24 + .../examples/storage/delete-file.md | 22 + .../examples/storage/get-file-download.md | 36 + .../examples/storage/get-file-preview.md | 36 + .../examples/storage/get-file-view.md | 36 + .../examples/storage/get-file.md | 22 + .../examples/storage/list-files.md | 21 + .../examples/storage/update-file.md | 22 + .../examples/teams/create-membership.md | 23 + .../client-flutter/examples/teams/create.md | 22 + .../examples/teams/delete-membership.md | 22 + .../client-flutter/examples/teams/delete.md | 21 + .../examples/teams/get-membership.md | 22 + .../examples/teams/get-prefs.md | 21 + .../client-flutter/examples/teams/get.md | 21 + .../examples/teams/list-memberships.md | 21 + .../client-flutter/examples/teams/list.md | 20 + .../teams/update-membership-status.md | 24 + .../examples/teams/update-membership.md | 23 + .../examples/teams/update-name.md | 22 + .../examples/teams/update-prefs.md | 22 + .../account/create-anonymous-session.md | 29 + .../examples/account/create-email-session.md | 32 + .../examples/account/create-j-w-t.md | 5 + .../account/create-magic-u-r-l-session.md | 12 + .../examples/account/create-phone-session.md | 12 + .../account/create-phone-verification.md | 9 + .../examples/account/create-recovery.md | 12 + .../examples/account/create-verification.md | 11 + .../client-graphql/examples/account/create.md | 24 + .../examples/account/delete-identity.md | 7 + .../examples/account/delete-session.md | 7 + .../examples/account/delete-sessions.md | 5 + .../examples/account/get-prefs.md | 5 + .../examples/account/get-session.md | 31 + .../client-graphql/examples/account/get.md | 20 + .../examples/account/list-identities.md | 17 + .../examples/account/list-logs.md | 28 + .../examples/account/list-sessions.md | 32 + .../examples/account/update-email.md | 23 + .../account/update-magic-u-r-l-session.md | 32 + .../examples/account/update-name.md | 22 + .../examples/account/update-password.md | 22 + .../examples/account/update-phone-session.md | 32 + .../account/update-phone-verification.md | 12 + .../examples/account/update-phone.md | 23 + .../examples/account/update-prefs.md | 22 + .../examples/account/update-recovery.md | 14 + .../examples/account/update-session.md | 31 + .../examples/account/update-status.md | 20 + .../examples/account/update-verification.md | 12 + .../examples/avatars/get-browser.md | 7 + .../examples/avatars/get-credit-card.md | 7 + .../examples/avatars/get-favicon.md | 7 + .../examples/avatars/get-flag.md | 7 + .../examples/avatars/get-image.md | 7 + .../examples/avatars/get-initials.md | 5 + .../examples/avatars/get-q-r.md | 7 + .../examples/databases/create-document.md | 16 + .../examples/databases/delete-document.md | 9 + .../examples/databases/get-document.md | 15 + .../examples/databases/list-documents.md | 17 + .../examples/databases/update-document.md | 15 + .../examples/functions/create-execution.md | 28 + .../examples/functions/get-execution.md | 29 + .../examples/functions/list-executions.md | 31 + .../client-graphql/examples/locale/get.md | 11 + .../examples/locale/list-codes.md | 9 + .../examples/locale/list-continents.md | 9 + .../examples/locale/list-countries-e-u.md | 9 + .../examples/locale/list-countries-phones.md | 10 + .../examples/locale/list-countries.md | 9 + .../examples/locale/list-currencies.md | 14 + .../examples/locale/list-languages.md | 10 + .../examples/storage/create-file.md | 24 + .../examples/storage/delete-file.md | 8 + .../examples/storage/get-file-download.md | 8 + .../examples/storage/get-file-preview.md | 8 + .../examples/storage/get-file-view.md | 8 + .../examples/storage/get-file.md | 18 + .../examples/storage/list-files.md | 20 + .../examples/storage/update-file.md | 18 + .../examples/teams/create-membership.md | 20 + .../client-graphql/examples/teams/create.md | 15 + .../examples/teams/delete-membership.md | 8 + .../client-graphql/examples/teams/delete.md | 7 + .../examples/teams/get-membership.md | 19 + .../examples/teams/get-prefs.md | 7 + .../client-graphql/examples/teams/get.md | 14 + .../examples/teams/list-memberships.md | 21 + .../client-graphql/examples/teams/list.md | 15 + .../teams/update-membership-status.md | 21 + .../examples/teams/update-membership.md | 20 + .../examples/teams/update-name.md | 15 + .../examples/teams/update-prefs.md | 8 + .../account/create-anonymous-session.md | 6 + .../examples/account/create-email-session.md | 10 + .../examples/account/create-j-w-t.md | 6 + .../account/create-magic-u-r-l-session.md | 11 + .../examples/account/create-o-auth2session.md | 6 + .../examples/account/create-phone-session.md | 10 + .../account/create-phone-verification.md | 7 + .../examples/account/create-recovery.md | 11 + .../examples/account/create-verification.md | 10 + .../client-rest/examples/account/create.md | 12 + .../examples/account/delete-identity.md | 7 + .../examples/account/delete-session.md | 7 + .../examples/account/delete-sessions.md | 7 + .../client-rest/examples/account/get-prefs.md | 7 + .../examples/account/get-session.md | 7 + .../1.4.x/client-rest/examples/account/get.md | 7 + .../examples/account/list-identities.md | 7 + .../client-rest/examples/account/list-logs.md | 7 + .../examples/account/list-sessions.md | 7 + .../examples/account/update-email.md | 11 + .../account/update-magic-u-r-l-session.md | 10 + .../examples/account/update-name.md | 10 + .../examples/account/update-password.md | 11 + .../examples/account/update-phone-session.md | 10 + .../account/update-phone-verification.md | 11 + .../examples/account/update-phone.md | 11 + .../examples/account/update-prefs.md | 10 + .../examples/account/update-recovery.md | 13 + .../examples/account/update-session.md | 7 + .../examples/account/update-status.md | 7 + .../examples/account/update-verification.md | 11 + .../examples/avatars/get-browser.md | 7 + .../examples/avatars/get-credit-card.md | 7 + .../examples/avatars/get-favicon.md | 7 + .../client-rest/examples/avatars/get-flag.md | 7 + .../client-rest/examples/avatars/get-image.md | 7 + .../examples/avatars/get-initials.md | 7 + .../client-rest/examples/avatars/get-q-r.md | 7 + .../examples/databases/create-document.md | 12 + .../examples/databases/delete-document.md | 7 + .../examples/databases/get-document.md | 7 + .../examples/databases/list-documents.md | 7 + .../examples/databases/update-document.md | 11 + .../examples/functions/create-execution.md | 14 + .../examples/functions/get-execution.md | 7 + .../examples/functions/list-executions.md | 7 + .../client-rest/examples/graphql/mutation.md | 11 + .../client-rest/examples/graphql/query.md | 11 + .../1.4.x/client-rest/examples/locale/get.md | 7 + .../client-rest/examples/locale/list-codes.md | 7 + .../examples/locale/list-continents.md | 7 + .../examples/locale/list-countries-e-u.md | 7 + .../examples/locale/list-countries-phones.md | 7 + .../examples/locale/list-countries.md | 7 + .../examples/locale/list-currencies.md | 7 + .../examples/locale/list-languages.md | 7 + .../examples/storage/create-file.md | 25 + .../examples/storage/delete-file.md | 7 + .../examples/storage/get-file-download.md | 7 + .../examples/storage/get-file-preview.md | 7 + .../examples/storage/get-file-view.md | 7 + .../client-rest/examples/storage/get-file.md | 7 + .../examples/storage/list-files.md | 7 + .../examples/storage/update-file.md | 11 + .../examples/teams/create-membership.md | 15 + .../client-rest/examples/teams/create.md | 12 + .../examples/teams/delete-membership.md | 7 + .../client-rest/examples/teams/delete.md | 7 + .../examples/teams/get-membership.md | 7 + .../client-rest/examples/teams/get-prefs.md | 7 + .../1.4.x/client-rest/examples/teams/get.md | 7 + .../examples/teams/list-memberships.md | 7 + .../1.4.x/client-rest/examples/teams/list.md | 7 + .../teams/update-membership-status.md | 11 + .../examples/teams/update-membership.md | 10 + .../client-rest/examples/teams/update-name.md | 10 + .../examples/teams/update-prefs.md | 10 + .../account/create-anonymous-session.md | 18 + .../examples/account/create-email-session.md | 18 + .../examples/account/create-j-w-t.md | 18 + .../account/create-magic-u-r-l-session.md | 18 + .../examples/account/create-o-auth2session.md | 14 + .../examples/account/create-phone-session.md | 18 + .../account/create-phone-verification.md | 18 + .../examples/account/create-recovery.md | 18 + .../examples/account/create-verification.md | 18 + .../client-web/examples/account/create.md | 18 + .../examples/account/delete-identity.md | 18 + .../examples/account/delete-session.md | 18 + .../examples/account/delete-sessions.md | 18 + .../client-web/examples/account/get-prefs.md | 18 + .../examples/account/get-session.md | 18 + .../1.4.x/client-web/examples/account/get.md | 18 + .../examples/account/list-identities.md | 18 + .../client-web/examples/account/list-logs.md | 18 + .../examples/account/list-sessions.md | 18 + .../examples/account/update-email.md | 18 + .../account/update-magic-u-r-l-session.md | 18 + .../examples/account/update-name.md | 18 + .../examples/account/update-password.md | 18 + .../examples/account/update-phone-session.md | 18 + .../account/update-phone-verification.md | 18 + .../examples/account/update-phone.md | 18 + .../examples/account/update-prefs.md | 18 + .../examples/account/update-recovery.md | 18 + .../examples/account/update-session.md | 18 + .../examples/account/update-status.md | 18 + .../examples/account/update-verification.md | 18 + .../examples/avatars/get-browser.md | 14 + .../examples/avatars/get-credit-card.md | 14 + .../examples/avatars/get-favicon.md | 14 + .../client-web/examples/avatars/get-flag.md | 14 + .../client-web/examples/avatars/get-image.md | 14 + .../examples/avatars/get-initials.md | 14 + .../client-web/examples/avatars/get-q-r.md | 14 + .../examples/databases/create-document.md | 18 + .../examples/databases/delete-document.md | 18 + .../examples/databases/get-document.md | 18 + .../examples/databases/list-documents.md | 18 + .../examples/databases/update-document.md | 18 + .../examples/functions/create-execution.md | 18 + .../examples/functions/get-execution.md | 18 + .../examples/functions/list-executions.md | 18 + .../client-web/examples/graphql/mutation.md | 18 + .../client-web/examples/graphql/query.md | 18 + .../1.4.x/client-web/examples/locale/get.md | 18 + .../client-web/examples/locale/list-codes.md | 18 + .../examples/locale/list-continents.md | 18 + .../examples/locale/list-countries-e-u.md | 18 + .../examples/locale/list-countries-phones.md | 18 + .../examples/locale/list-countries.md | 18 + .../examples/locale/list-currencies.md | 18 + .../examples/locale/list-languages.md | 18 + .../examples/storage/create-file.md | 18 + .../examples/storage/delete-file.md | 18 + .../examples/storage/get-file-download.md | 14 + .../examples/storage/get-file-preview.md | 14 + .../examples/storage/get-file-view.md | 14 + .../client-web/examples/storage/get-file.md | 18 + .../client-web/examples/storage/list-files.md | 18 + .../examples/storage/update-file.md | 18 + .../examples/teams/create-membership.md | 18 + .../1.4.x/client-web/examples/teams/create.md | 18 + .../examples/teams/delete-membership.md | 18 + .../1.4.x/client-web/examples/teams/delete.md | 18 + .../examples/teams/get-membership.md | 18 + .../client-web/examples/teams/get-prefs.md | 18 + .../1.4.x/client-web/examples/teams/get.md | 18 + .../examples/teams/list-memberships.md | 18 + .../1.4.x/client-web/examples/teams/list.md | 18 + .../teams/update-membership-status.md | 18 + .../examples/teams/update-membership.md | 18 + .../client-web/examples/teams/update-name.md | 18 + .../client-web/examples/teams/update-prefs.md | 18 + .../account/create-anonymous-session.md | 1 + .../examples/account/create-email-session.md | 3 + .../examples/account/create-j-w-t.md | 1 + .../account/create-magic-u-r-l-session.md | 4 + .../examples/account/create-o-auth2session.md | 5 + .../examples/account/create-phone-session.md | 3 + .../account/create-phone-verification.md | 1 + .../examples/account/create-recovery.md | 3 + .../examples/account/create-verification.md | 2 + .../console-cli/examples/account/create.md | 5 + .../examples/account/delete-identity.md | 2 + .../examples/account/delete-session.md | 2 + .../examples/account/delete-sessions.md | 1 + .../console-cli/examples/account/get-prefs.md | 1 + .../examples/account/get-session.md | 2 + .../1.4.x/console-cli/examples/account/get.md | 1 + .../examples/account/list-identities.md | 2 + .../console-cli/examples/account/list-logs.md | 2 + .../examples/account/list-sessions.md | 1 + .../examples/account/update-email.md | 3 + .../account/update-magic-u-r-l-session.md | 3 + .../examples/account/update-name.md | 2 + .../examples/account/update-password.md | 3 + .../examples/account/update-phone-session.md | 3 + .../account/update-phone-verification.md | 3 + .../examples/account/update-phone.md | 3 + .../examples/account/update-prefs.md | 2 + .../examples/account/update-recovery.md | 5 + .../examples/account/update-session.md | 2 + .../examples/account/update-status.md | 1 + .../examples/account/update-verification.md | 3 + .../console-cli/examples/assistant/chat.md | 2 + .../examples/avatars/get-browser.md | 5 + .../examples/avatars/get-credit-card.md | 5 + .../examples/avatars/get-favicon.md | 2 + .../console-cli/examples/avatars/get-flag.md | 5 + .../console-cli/examples/avatars/get-image.md | 4 + .../examples/avatars/get-initials.md | 5 + .../console-cli/examples/avatars/get-q-r.md | 5 + .../console-cli/examples/console/variables.md | 1 + .../databases/create-boolean-attribute.md | 7 + .../examples/databases/create-collection.md | 7 + .../databases/create-datetime-attribute.md | 7 + .../examples/databases/create-document.md | 6 + .../databases/create-email-attribute.md | 7 + .../databases/create-enum-attribute.md | 8 + .../databases/create-float-attribute.md | 9 + .../examples/databases/create-index.md | 7 + .../databases/create-integer-attribute.md | 9 + .../examples/databases/create-ip-attribute.md | 7 + .../create-relationship-attribute.md | 9 + .../databases/create-string-attribute.md | 9 + .../databases/create-url-attribute.md | 7 + .../console-cli/examples/databases/create.md | 4 + .../examples/databases/delete-attribute.md | 4 + .../examples/databases/delete-collection.md | 3 + .../examples/databases/delete-document.md | 4 + .../examples/databases/delete-index.md | 4 + .../console-cli/examples/databases/delete.md | 2 + .../examples/databases/get-attribute.md | 4 + .../databases/get-collection-usage.md | 4 + .../examples/databases/get-collection.md | 3 + .../examples/databases/get-database-usage.md | 3 + .../examples/databases/get-document.md | 5 + .../examples/databases/get-index.md | 4 + .../examples/databases/get-usage.md | 2 + .../console-cli/examples/databases/get.md | 2 + .../examples/databases/list-attributes.md | 4 + .../databases/list-collection-logs.md | 4 + .../examples/databases/list-collections.md | 4 + .../examples/databases/list-document-logs.md | 5 + .../examples/databases/list-documents.md | 4 + .../examples/databases/list-indexes.md | 4 + .../examples/databases/list-logs.md | 3 + .../console-cli/examples/databases/list.md | 3 + .../databases/update-boolean-attribute.md | 6 + .../examples/databases/update-collection.md | 7 + .../databases/update-datetime-attribute.md | 6 + .../examples/databases/update-document.md | 6 + .../databases/update-email-attribute.md | 6 + .../databases/update-enum-attribute.md | 7 + .../databases/update-float-attribute.md | 8 + .../databases/update-integer-attribute.md | 8 + .../examples/databases/update-ip-attribute.md | 6 + .../update-relationship-attribute.md | 5 + .../databases/update-string-attribute.md | 6 + .../databases/update-url-attribute.md | 6 + .../console-cli/examples/databases/update.md | 4 + .../examples/functions/create-build.md | 4 + .../examples/functions/create-deployment.md | 6 + .../examples/functions/create-execution.md | 7 + .../examples/functions/create-variable.md | 4 + .../console-cli/examples/functions/create.md | 21 + .../examples/functions/delete-deployment.md | 3 + .../examples/functions/delete-variable.md | 3 + .../console-cli/examples/functions/delete.md | 2 + .../examples/functions/download-deployment.md | 3 + .../examples/functions/get-deployment.md | 3 + .../examples/functions/get-execution.md | 3 + .../examples/functions/get-function-usage.md | 3 + .../examples/functions/get-usage.md | 2 + .../examples/functions/get-variable.md | 3 + .../console-cli/examples/functions/get.md | 2 + .../examples/functions/list-deployments.md | 4 + .../examples/functions/list-executions.md | 4 + .../examples/functions/list-runtimes.md | 1 + .../examples/functions/list-variables.md | 2 + .../console-cli/examples/functions/list.md | 3 + .../examples/functions/update-deployment.md | 3 + .../examples/functions/update-variable.md | 5 + .../console-cli/examples/functions/update.md | 17 + .../console-cli/examples/graphql/mutation.md | 2 + .../console-cli/examples/graphql/query.md | 2 + .../examples/health/get-antivirus.md | 1 + .../console-cli/examples/health/get-cache.md | 1 + .../console-cli/examples/health/get-d-b.md | 1 + .../examples/health/get-pub-sub.md | 1 + .../examples/health/get-queue-certificates.md | 1 + .../examples/health/get-queue-functions.md | 1 + .../examples/health/get-queue-logs.md | 1 + .../examples/health/get-queue-webhooks.md | 1 + .../console-cli/examples/health/get-queue.md | 1 + .../examples/health/get-storage-local.md | 1 + .../console-cli/examples/health/get-time.md | 1 + .../1.4.x/console-cli/examples/health/get.md | 1 + .../1.4.x/console-cli/examples/locale/get.md | 1 + .../console-cli/examples/locale/list-codes.md | 1 + .../examples/locale/list-continents.md | 1 + .../examples/locale/list-countries-e-u.md | 1 + .../examples/locale/list-countries-phones.md | 1 + .../examples/locale/list-countries.md | 1 + .../examples/locale/list-currencies.md | 1 + .../examples/locale/list-languages.md | 1 + .../migrations/create-appwrite-migration.md | 5 + .../migrations/create-firebase-migration.md | 3 + .../create-firebase-o-auth-migration.md | 3 + .../migrations/create-n-host-migration.md | 9 + .../migrations/create-supabase-migration.md | 8 + .../migrations/delete-firebase-auth.md | 1 + .../console-cli/examples/migrations/delete.md | 2 + .../migrations/get-appwrite-report.md | 5 + .../migrations/get-firebase-report-o-auth.md | 3 + .../migrations/get-firebase-report.md | 3 + .../examples/migrations/get-n-host-report.md | 9 + .../migrations/get-supabase-report.md | 8 + .../console-cli/examples/migrations/get.md | 2 + .../migrations/list-firebase-projects.md | 1 + .../console-cli/examples/migrations/list.md | 3 + .../console-cli/examples/migrations/retry.md | 2 + .../examples/project/create-variable.md | 3 + .../examples/project/delete-variable.md | 2 + .../console-cli/examples/project/get-usage.md | 2 + .../examples/project/get-variable.md | 2 + .../examples/project/list-variables.md | 1 + .../examples/project/update-variable.md | 4 + .../examples/projects/create-key.md | 5 + .../examples/projects/create-platform.md | 7 + .../examples/projects/create-webhook.md | 8 + .../console-cli/examples/projects/create.md | 14 + .../projects/delete-email-template.md | 4 + .../examples/projects/delete-key.md | 3 + .../examples/projects/delete-platform.md | 3 + .../examples/projects/delete-sms-template.md | 4 + .../examples/projects/delete-webhook.md | 3 + .../console-cli/examples/projects/delete.md | 2 + .../examples/projects/get-email-template.md | 4 + .../console-cli/examples/projects/get-key.md | 3 + .../examples/projects/get-platform.md | 3 + .../examples/projects/get-sms-template.md | 4 + .../examples/projects/get-usage.md | 3 + .../examples/projects/get-webhook.md | 3 + .../console-cli/examples/projects/get.md | 2 + .../examples/projects/list-keys.md | 2 + .../examples/projects/list-platforms.md | 2 + .../examples/projects/list-webhooks.md | 2 + .../console-cli/examples/projects/list.md | 3 + .../examples/projects/update-auth-duration.md | 3 + .../examples/projects/update-auth-limit.md | 3 + .../update-auth-password-dictionary.md | 3 + .../projects/update-auth-password-history.md | 3 + .../projects/update-auth-sessions-limit.md | 3 + .../examples/projects/update-auth-status.md | 4 + .../projects/update-email-template.md | 9 + .../examples/projects/update-key.md | 6 + .../examples/projects/update-o-auth2.md | 6 + .../projects/update-personal-data-check.md | 3 + .../examples/projects/update-platform.md | 7 + .../projects/update-service-status-all.md | 3 + .../projects/update-service-status.md | 4 + .../examples/projects/update-sms-template.md | 5 + .../projects/update-smtp-configuration.md | 11 + .../examples/projects/update-team.md | 3 + .../projects/update-webhook-signature.md | 3 + .../examples/projects/update-webhook.md | 9 + .../console-cli/examples/projects/update.md | 12 + .../console-cli/examples/proxy/create-rule.md | 4 + .../console-cli/examples/proxy/delete-rule.md | 2 + .../console-cli/examples/proxy/get-rule.md | 2 + .../console-cli/examples/proxy/list-rules.md | 3 + .../proxy/update-rule-verification.md | 2 + .../examples/storage/create-bucket.md | 11 + .../examples/storage/create-file.md | 5 + .../examples/storage/delete-bucket.md | 2 + .../examples/storage/delete-file.md | 3 + .../examples/storage/get-bucket-usage.md | 3 + .../examples/storage/get-bucket.md | 2 + .../examples/storage/get-file-download.md | 3 + .../examples/storage/get-file-preview.md | 14 + .../examples/storage/get-file-view.md | 3 + .../console-cli/examples/storage/get-file.md | 3 + .../console-cli/examples/storage/get-usage.md | 2 + .../examples/storage/list-buckets.md | 3 + .../examples/storage/list-files.md | 4 + .../examples/storage/update-bucket.md | 11 + .../examples/storage/update-file.md | 5 + .../examples/teams/create-membership.md | 8 + .../console-cli/examples/teams/create.md | 4 + .../examples/teams/delete-membership.md | 3 + .../console-cli/examples/teams/delete.md | 2 + .../examples/teams/get-membership.md | 3 + .../console-cli/examples/teams/get-prefs.md | 2 + .../1.4.x/console-cli/examples/teams/get.md | 2 + .../console-cli/examples/teams/list-logs.md | 3 + .../examples/teams/list-memberships.md | 4 + .../1.4.x/console-cli/examples/teams/list.md | 3 + .../teams/update-membership-status.md | 5 + .../examples/teams/update-membership.md | 4 + .../console-cli/examples/teams/update-name.md | 3 + .../examples/teams/update-prefs.md | 3 + .../examples/users/create-argon2user.md | 5 + .../examples/users/create-bcrypt-user.md | 5 + .../examples/users/create-m-d5user.md | 5 + .../examples/users/create-p-h-pass-user.md | 5 + .../examples/users/create-s-h-a-user.md | 6 + .../users/create-scrypt-modified-user.md | 8 + .../examples/users/create-scrypt-user.md | 10 + .../console-cli/examples/users/create.md | 6 + .../examples/users/delete-identity.md | 2 + .../examples/users/delete-session.md | 3 + .../examples/users/delete-sessions.md | 2 + .../console-cli/examples/users/delete.md | 2 + .../console-cli/examples/users/get-prefs.md | 2 + .../console-cli/examples/users/get-usage.md | 3 + .../1.4.x/console-cli/examples/users/get.md | 2 + .../examples/users/list-identities.md | 3 + .../console-cli/examples/users/list-logs.md | 3 + .../examples/users/list-memberships.md | 2 + .../examples/users/list-sessions.md | 2 + .../1.4.x/console-cli/examples/users/list.md | 3 + .../users/update-email-verification.md | 3 + .../examples/users/update-email.md | 3 + .../examples/users/update-labels.md | 3 + .../console-cli/examples/users/update-name.md | 3 + .../examples/users/update-password.md | 3 + .../users/update-phone-verification.md | 3 + .../examples/users/update-phone.md | 3 + .../examples/users/update-prefs.md | 3 + .../examples/users/update-status.md | 3 + .../vcs/create-repository-detection.md | 4 + .../examples/vcs/create-repository.md | 4 + .../examples/vcs/delete-installation.md | 2 + .../examples/vcs/get-installation.md | 2 + .../examples/vcs/get-repository.md | 3 + .../examples/vcs/list-installations.md | 3 + .../examples/vcs/list-repositories.md | 3 + .../examples/vcs/list-repository-branches.md | 3 + .../vcs/update-external-deployments.md | 4 + .../account/create-anonymous-session.md | 18 + .../examples/account/create-email-session.md | 18 + .../examples/account/create-j-w-t.md | 18 + .../account/create-magic-u-r-l-session.md | 18 + .../examples/account/create-o-auth2session.md | 14 + .../examples/account/create-phone-session.md | 18 + .../account/create-phone-verification.md | 18 + .../examples/account/create-recovery.md | 18 + .../examples/account/create-verification.md | 18 + .../console-web/examples/account/create.md | 18 + .../examples/account/delete-identity.md | 18 + .../examples/account/delete-session.md | 18 + .../examples/account/delete-sessions.md | 18 + .../console-web/examples/account/get-prefs.md | 18 + .../examples/account/get-session.md | 18 + .../1.4.x/console-web/examples/account/get.md | 18 + .../examples/account/list-identities.md | 18 + .../console-web/examples/account/list-logs.md | 18 + .../examples/account/list-sessions.md | 18 + .../examples/account/update-email.md | 18 + .../account/update-magic-u-r-l-session.md | 18 + .../examples/account/update-name.md | 18 + .../examples/account/update-password.md | 18 + .../examples/account/update-phone-session.md | 18 + .../account/update-phone-verification.md | 18 + .../examples/account/update-phone.md | 18 + .../examples/account/update-prefs.md | 18 + .../examples/account/update-recovery.md | 18 + .../examples/account/update-session.md | 18 + .../examples/account/update-status.md | 18 + .../examples/account/update-verification.md | 18 + .../console-web/examples/assistant/chat.md | 17 + .../examples/avatars/get-browser.md | 14 + .../examples/avatars/get-credit-card.md | 14 + .../examples/avatars/get-favicon.md | 14 + .../console-web/examples/avatars/get-flag.md | 14 + .../console-web/examples/avatars/get-image.md | 14 + .../examples/avatars/get-initials.md | 14 + .../console-web/examples/avatars/get-q-r.md | 14 + .../console-web/examples/console/variables.md | 18 + .../databases/create-boolean-attribute.md | 18 + .../examples/databases/create-collection.md | 18 + .../databases/create-datetime-attribute.md | 18 + .../examples/databases/create-document.md | 18 + .../databases/create-email-attribute.md | 18 + .../databases/create-enum-attribute.md | 18 + .../databases/create-float-attribute.md | 18 + .../examples/databases/create-index.md | 18 + .../databases/create-integer-attribute.md | 18 + .../examples/databases/create-ip-attribute.md | 18 + .../create-relationship-attribute.md | 18 + .../databases/create-string-attribute.md | 18 + .../databases/create-url-attribute.md | 18 + .../console-web/examples/databases/create.md | 18 + .../examples/databases/delete-attribute.md | 18 + .../examples/databases/delete-collection.md | 18 + .../examples/databases/delete-document.md | 18 + .../examples/databases/delete-index.md | 18 + .../console-web/examples/databases/delete.md | 18 + .../examples/databases/get-attribute.md | 18 + .../databases/get-collection-usage.md | 18 + .../examples/databases/get-collection.md | 18 + .../examples/databases/get-database-usage.md | 18 + .../examples/databases/get-document.md | 18 + .../examples/databases/get-index.md | 18 + .../examples/databases/get-usage.md | 18 + .../console-web/examples/databases/get.md | 18 + .../examples/databases/list-attributes.md | 18 + .../databases/list-collection-logs.md | 18 + .../examples/databases/list-collections.md | 18 + .../examples/databases/list-document-logs.md | 18 + .../examples/databases/list-documents.md | 18 + .../examples/databases/list-indexes.md | 18 + .../examples/databases/list-logs.md | 18 + .../console-web/examples/databases/list.md | 18 + .../databases/update-boolean-attribute.md | 18 + .../examples/databases/update-collection.md | 18 + .../databases/update-datetime-attribute.md | 18 + .../examples/databases/update-document.md | 18 + .../databases/update-email-attribute.md | 18 + .../databases/update-enum-attribute.md | 18 + .../databases/update-float-attribute.md | 18 + .../databases/update-integer-attribute.md | 18 + .../examples/databases/update-ip-attribute.md | 18 + .../update-relationship-attribute.md | 18 + .../databases/update-string-attribute.md | 18 + .../databases/update-url-attribute.md | 18 + .../console-web/examples/databases/update.md | 18 + .../examples/functions/create-build.md | 18 + .../examples/functions/create-deployment.md | 18 + .../examples/functions/create-execution.md | 18 + .../examples/functions/create-variable.md | 18 + .../console-web/examples/functions/create.md | 18 + .../examples/functions/delete-deployment.md | 18 + .../examples/functions/delete-variable.md | 18 + .../console-web/examples/functions/delete.md | 18 + .../examples/functions/download-deployment.md | 14 + .../examples/functions/get-deployment.md | 18 + .../examples/functions/get-execution.md | 18 + .../examples/functions/get-function-usage.md | 18 + .../examples/functions/get-usage.md | 18 + .../examples/functions/get-variable.md | 18 + .../console-web/examples/functions/get.md | 18 + .../examples/functions/list-deployments.md | 18 + .../examples/functions/list-executions.md | 18 + .../examples/functions/list-runtimes.md | 18 + .../examples/functions/list-variables.md | 18 + .../console-web/examples/functions/list.md | 18 + .../examples/functions/update-deployment.md | 18 + .../examples/functions/update-variable.md | 18 + .../console-web/examples/functions/update.md | 18 + .../console-web/examples/graphql/mutation.md | 18 + .../console-web/examples/graphql/query.md | 18 + .../examples/health/get-antivirus.md | 18 + .../console-web/examples/health/get-cache.md | 18 + .../console-web/examples/health/get-d-b.md | 18 + .../examples/health/get-pub-sub.md | 18 + .../examples/health/get-queue-certificates.md | 18 + .../examples/health/get-queue-functions.md | 18 + .../examples/health/get-queue-logs.md | 18 + .../examples/health/get-queue-webhooks.md | 18 + .../console-web/examples/health/get-queue.md | 18 + .../examples/health/get-storage-local.md | 18 + .../console-web/examples/health/get-time.md | 18 + .../1.4.x/console-web/examples/health/get.md | 18 + .../1.4.x/console-web/examples/locale/get.md | 18 + .../console-web/examples/locale/list-codes.md | 18 + .../examples/locale/list-continents.md | 18 + .../examples/locale/list-countries-e-u.md | 18 + .../examples/locale/list-countries-phones.md | 18 + .../examples/locale/list-countries.md | 18 + .../examples/locale/list-currencies.md | 18 + .../examples/locale/list-languages.md | 18 + .../migrations/create-appwrite-migration.md | 18 + .../migrations/create-firebase-migration.md | 18 + .../create-firebase-o-auth-migration.md | 18 + .../migrations/create-n-host-migration.md | 18 + .../migrations/create-supabase-migration.md | 18 + .../migrations/delete-firebase-auth.md | 17 + .../console-web/examples/migrations/delete.md | 18 + .../migrations/get-appwrite-report.md | 18 + .../migrations/get-firebase-report-o-auth.md | 18 + .../migrations/get-firebase-report.md | 18 + .../examples/migrations/get-n-host-report.md | 18 + .../migrations/get-supabase-report.md | 18 + .../console-web/examples/migrations/get.md | 18 + .../migrations/list-firebase-projects.md | 17 + .../console-web/examples/migrations/list.md | 18 + .../console-web/examples/migrations/retry.md | 18 + .../examples/project/create-variable.md | 18 + .../examples/project/delete-variable.md | 18 + .../console-web/examples/project/get-usage.md | 18 + .../examples/project/get-variable.md | 18 + .../examples/project/list-variables.md | 18 + .../examples/project/update-variable.md | 18 + .../examples/projects/create-key.md | 18 + .../examples/projects/create-platform.md | 18 + .../examples/projects/create-webhook.md | 18 + .../console-web/examples/projects/create.md | 18 + .../projects/delete-email-template.md | 18 + .../examples/projects/delete-key.md | 18 + .../examples/projects/delete-platform.md | 18 + .../examples/projects/delete-sms-template.md | 18 + .../examples/projects/delete-webhook.md | 18 + .../console-web/examples/projects/delete.md | 18 + .../examples/projects/get-email-template.md | 18 + .../console-web/examples/projects/get-key.md | 18 + .../examples/projects/get-platform.md | 18 + .../examples/projects/get-sms-template.md | 18 + .../examples/projects/get-usage.md | 18 + .../examples/projects/get-webhook.md | 18 + .../console-web/examples/projects/get.md | 18 + .../examples/projects/list-keys.md | 18 + .../examples/projects/list-platforms.md | 18 + .../examples/projects/list-webhooks.md | 18 + .../console-web/examples/projects/list.md | 18 + .../examples/projects/update-auth-duration.md | 18 + .../examples/projects/update-auth-limit.md | 18 + .../update-auth-password-dictionary.md | 18 + .../projects/update-auth-password-history.md | 18 + .../projects/update-auth-sessions-limit.md | 18 + .../examples/projects/update-auth-status.md | 18 + .../projects/update-email-template.md | 18 + .../examples/projects/update-key.md | 18 + .../examples/projects/update-o-auth2.md | 18 + .../projects/update-personal-data-check.md | 18 + .../examples/projects/update-platform.md | 18 + .../projects/update-service-status-all.md | 18 + .../projects/update-service-status.md | 18 + .../examples/projects/update-sms-template.md | 18 + .../projects/update-smtp-configuration.md | 18 + .../examples/projects/update-team.md | 18 + .../projects/update-webhook-signature.md | 18 + .../examples/projects/update-webhook.md | 18 + .../console-web/examples/projects/update.md | 18 + .../console-web/examples/proxy/create-rule.md | 18 + .../console-web/examples/proxy/delete-rule.md | 18 + .../console-web/examples/proxy/get-rule.md | 18 + .../console-web/examples/proxy/list-rules.md | 18 + .../proxy/update-rule-verification.md | 18 + .../examples/storage/create-bucket.md | 18 + .../examples/storage/create-file.md | 18 + .../examples/storage/delete-bucket.md | 18 + .../examples/storage/delete-file.md | 18 + .../examples/storage/get-bucket-usage.md | 18 + .../examples/storage/get-bucket.md | 18 + .../examples/storage/get-file-download.md | 14 + .../examples/storage/get-file-preview.md | 14 + .../examples/storage/get-file-view.md | 14 + .../console-web/examples/storage/get-file.md | 18 + .../console-web/examples/storage/get-usage.md | 18 + .../examples/storage/list-buckets.md | 18 + .../examples/storage/list-files.md | 18 + .../examples/storage/update-bucket.md | 18 + .../examples/storage/update-file.md | 18 + .../examples/teams/create-membership.md | 18 + .../console-web/examples/teams/create.md | 18 + .../examples/teams/delete-membership.md | 18 + .../console-web/examples/teams/delete.md | 18 + .../examples/teams/get-membership.md | 18 + .../console-web/examples/teams/get-prefs.md | 18 + .../1.4.x/console-web/examples/teams/get.md | 18 + .../console-web/examples/teams/list-logs.md | 18 + .../examples/teams/list-memberships.md | 18 + .../1.4.x/console-web/examples/teams/list.md | 18 + .../teams/update-membership-status.md | 18 + .../examples/teams/update-membership.md | 18 + .../console-web/examples/teams/update-name.md | 18 + .../examples/teams/update-prefs.md | 18 + .../examples/users/create-argon2user.md | 18 + .../examples/users/create-bcrypt-user.md | 18 + .../examples/users/create-m-d5user.md | 18 + .../examples/users/create-p-h-pass-user.md | 18 + .../examples/users/create-s-h-a-user.md | 18 + .../users/create-scrypt-modified-user.md | 18 + .../examples/users/create-scrypt-user.md | 18 + .../console-web/examples/users/create.md | 18 + .../examples/users/delete-identity.md | 18 + .../examples/users/delete-session.md | 18 + .../examples/users/delete-sessions.md | 18 + .../console-web/examples/users/delete.md | 18 + .../console-web/examples/users/get-prefs.md | 18 + .../console-web/examples/users/get-usage.md | 18 + .../1.4.x/console-web/examples/users/get.md | 18 + .../examples/users/list-identities.md | 18 + .../console-web/examples/users/list-logs.md | 18 + .../examples/users/list-memberships.md | 18 + .../examples/users/list-sessions.md | 18 + .../1.4.x/console-web/examples/users/list.md | 18 + .../users/update-email-verification.md | 18 + .../examples/users/update-email.md | 18 + .../examples/users/update-labels.md | 18 + .../console-web/examples/users/update-name.md | 18 + .../examples/users/update-password.md | 18 + .../users/update-phone-verification.md | 18 + .../examples/users/update-phone.md | 18 + .../examples/users/update-prefs.md | 18 + .../examples/users/update-status.md | 18 + .../vcs/create-repository-detection.md | 17 + .../examples/vcs/create-repository.md | 17 + .../examples/vcs/delete-installation.md | 17 + .../examples/vcs/get-installation.md | 17 + .../examples/vcs/get-repository.md | 17 + .../examples/vcs/list-installations.md | 17 + .../examples/vcs/list-repositories.md | 17 + .../examples/vcs/list-repository-branches.md | 17 + .../vcs/update-external-deployments.md | 17 + .../account/create-phone-verification.md | 21 + .../examples/account/create-recovery.md | 24 + .../examples/account/create-verification.md | 23 + .../examples/account/delete-identity.md | 23 + .../examples/account/delete-session.md | 23 + .../examples/account/delete-sessions.md | 21 + .../server-dart/examples/account/get-prefs.md | 21 + .../examples/account/get-session.md | 23 + .../1.4.x/server-dart/examples/account/get.md | 21 + .../examples/account/list-identities.md | 22 + .../server-dart/examples/account/list-logs.md | 22 + .../examples/account/list-sessions.md | 21 + .../examples/account/update-email.md | 24 + .../examples/account/update-name.md | 23 + .../examples/account/update-password.md | 23 + .../account/update-phone-verification.md | 24 + .../examples/account/update-phone.md | 24 + .../examples/account/update-prefs.md | 23 + .../examples/account/update-recovery.md | 26 + .../examples/account/update-session.md | 23 + .../examples/account/update-status.md | 21 + .../examples/account/update-verification.md | 24 + .../examples/avatars/get-browser.md | 23 + .../examples/avatars/get-credit-card.md | 23 + .../examples/avatars/get-favicon.md | 23 + .../server-dart/examples/avatars/get-flag.md | 23 + .../server-dart/examples/avatars/get-image.md | 23 + .../examples/avatars/get-initials.md | 22 + .../server-dart/examples/avatars/get-q-r.md | 23 + .../databases/create-boolean-attribute.md | 26 + .../examples/databases/create-collection.md | 25 + .../databases/create-datetime-attribute.md | 26 + .../examples/databases/create-document.md | 26 + .../databases/create-email-attribute.md | 26 + .../databases/create-enum-attribute.md | 27 + .../databases/create-float-attribute.md | 26 + .../examples/databases/create-index.md | 27 + .../databases/create-integer-attribute.md | 26 + .../examples/databases/create-ip-attribute.md | 26 + .../create-relationship-attribute.md | 26 + .../databases/create-string-attribute.md | 27 + .../databases/create-url-attribute.md | 26 + .../server-dart/examples/databases/create.md | 24 + .../examples/databases/delete-attribute.md | 25 + .../examples/databases/delete-collection.md | 24 + .../examples/databases/delete-document.md | 25 + .../examples/databases/delete-index.md | 25 + .../server-dart/examples/databases/delete.md | 23 + .../examples/databases/get-attribute.md | 25 + .../examples/databases/get-collection.md | 24 + .../examples/databases/get-document.md | 25 + .../examples/databases/get-index.md | 25 + .../server-dart/examples/databases/get.md | 23 + .../examples/databases/list-attributes.md | 24 + .../examples/databases/list-collections.md | 23 + .../examples/databases/list-documents.md | 24 + .../examples/databases/list-indexes.md | 24 + .../server-dart/examples/databases/list.md | 22 + .../databases/update-boolean-attribute.md | 27 + .../examples/databases/update-collection.md | 25 + .../databases/update-datetime-attribute.md | 27 + .../examples/databases/update-document.md | 25 + .../databases/update-email-attribute.md | 27 + .../databases/update-enum-attribute.md | 28 + .../databases/update-float-attribute.md | 29 + .../databases/update-integer-attribute.md | 29 + .../examples/databases/update-ip-attribute.md | 27 + .../update-relationship-attribute.md | 25 + .../databases/update-string-attribute.md | 27 + .../databases/update-url-attribute.md | 27 + .../server-dart/examples/databases/update.md | 24 + .../examples/functions/create-build.md | 25 + .../examples/functions/create-deployment.md | 25 + .../examples/functions/create-execution.md | 23 + .../examples/functions/create-variable.md | 25 + .../server-dart/examples/functions/create.md | 25 + .../examples/functions/delete-deployment.md | 24 + .../examples/functions/delete-variable.md | 24 + .../server-dart/examples/functions/delete.md | 23 + .../examples/functions/download-deployment.md | 24 + .../examples/functions/get-deployment.md | 24 + .../examples/functions/get-execution.md | 24 + .../examples/functions/get-variable.md | 24 + .../server-dart/examples/functions/get.md | 23 + .../examples/functions/list-deployments.md | 23 + .../examples/functions/list-executions.md | 23 + .../examples/functions/list-runtimes.md | 21 + .../examples/functions/list-variables.md | 23 + .../server-dart/examples/functions/list.md | 22 + .../examples/functions/update-deployment.md | 24 + .../examples/functions/update-variable.md | 25 + .../server-dart/examples/functions/update.md | 25 + .../server-dart/examples/graphql/mutation.md | 23 + .../server-dart/examples/graphql/query.md | 23 + .../examples/health/get-antivirus.md | 21 + .../server-dart/examples/health/get-cache.md | 21 + .../server-dart/examples/health/get-d-b.md | 21 + .../examples/health/get-pub-sub.md | 21 + .../examples/health/get-queue-certificates.md | 21 + .../examples/health/get-queue-functions.md | 21 + .../examples/health/get-queue-logs.md | 21 + .../examples/health/get-queue-webhooks.md | 21 + .../server-dart/examples/health/get-queue.md | 21 + .../examples/health/get-storage-local.md | 21 + .../server-dart/examples/health/get-time.md | 21 + .../1.4.x/server-dart/examples/health/get.md | 21 + .../1.4.x/server-dart/examples/locale/get.md | 21 + .../server-dart/examples/locale/list-codes.md | 21 + .../examples/locale/list-continents.md | 21 + .../examples/locale/list-countries-e-u.md | 21 + .../examples/locale/list-countries-phones.md | 21 + .../examples/locale/list-countries.md | 21 + .../examples/locale/list-currencies.md | 21 + .../examples/locale/list-languages.md | 21 + .../examples/storage/create-bucket.md | 24 + .../examples/storage/create-file.md | 26 + .../examples/storage/delete-bucket.md | 23 + .../examples/storage/delete-file.md | 24 + .../examples/storage/get-bucket.md | 23 + .../examples/storage/get-file-download.md | 24 + .../examples/storage/get-file-preview.md | 24 + .../examples/storage/get-file-view.md | 24 + .../server-dart/examples/storage/get-file.md | 24 + .../examples/storage/list-buckets.md | 22 + .../examples/storage/list-files.md | 23 + .../examples/storage/update-bucket.md | 24 + .../examples/storage/update-file.md | 24 + .../examples/teams/create-membership.md | 25 + .../server-dart/examples/teams/create.md | 24 + .../examples/teams/delete-membership.md | 24 + .../server-dart/examples/teams/delete.md | 23 + .../examples/teams/get-membership.md | 24 + .../server-dart/examples/teams/get-prefs.md | 23 + .../1.4.x/server-dart/examples/teams/get.md | 23 + .../examples/teams/list-memberships.md | 23 + .../1.4.x/server-dart/examples/teams/list.md | 22 + .../teams/update-membership-status.md | 26 + .../examples/teams/update-membership.md | 25 + .../server-dart/examples/teams/update-name.md | 24 + .../examples/teams/update-prefs.md | 24 + .../examples/users/create-argon2user.md | 25 + .../examples/users/create-bcrypt-user.md | 25 + .../examples/users/create-m-d5user.md | 25 + .../examples/users/create-p-h-pass-user.md | 25 + .../examples/users/create-s-h-a-user.md | 25 + .../users/create-scrypt-modified-user.md | 28 + .../examples/users/create-scrypt-user.md | 30 + .../server-dart/examples/users/create.md | 23 + .../examples/users/delete-identity.md | 23 + .../examples/users/delete-session.md | 24 + .../examples/users/delete-sessions.md | 23 + .../server-dart/examples/users/delete.md | 23 + .../server-dart/examples/users/get-prefs.md | 23 + .../1.4.x/server-dart/examples/users/get.md | 23 + .../examples/users/list-identities.md | 22 + .../server-dart/examples/users/list-logs.md | 23 + .../examples/users/list-memberships.md | 23 + .../examples/users/list-sessions.md | 23 + .../1.4.x/server-dart/examples/users/list.md | 22 + .../users/update-email-verification.md | 24 + .../examples/users/update-email.md | 24 + .../examples/users/update-labels.md | 24 + .../server-dart/examples/users/update-name.md | 24 + .../examples/users/update-password.md | 24 + .../users/update-phone-verification.md | 24 + .../examples/users/update-phone.md | 24 + .../examples/users/update-prefs.md | 24 + .../examples/users/update-status.md | 24 + .../account/create-phone-verification.md | 21 + .../examples/account/create-recovery.md | 21 + .../examples/account/create-verification.md | 21 + .../examples/account/delete-identity.md | 21 + .../examples/account/delete-session.md | 21 + .../examples/account/delete-sessions.md | 21 + .../server-deno/examples/account/get-prefs.md | 21 + .../examples/account/get-session.md | 21 + .../1.4.x/server-deno/examples/account/get.md | 21 + .../examples/account/list-identities.md | 21 + .../server-deno/examples/account/list-logs.md | 21 + .../examples/account/list-sessions.md | 21 + .../examples/account/update-email.md | 21 + .../examples/account/update-name.md | 21 + .../examples/account/update-password.md | 21 + .../account/update-phone-verification.md | 21 + .../examples/account/update-phone.md | 21 + .../examples/account/update-prefs.md | 21 + .../examples/account/update-recovery.md | 21 + .../examples/account/update-session.md | 21 + .../examples/account/update-status.md | 21 + .../examples/account/update-verification.md | 21 + .../examples/avatars/get-browser.md | 21 + .../examples/avatars/get-credit-card.md | 21 + .../examples/avatars/get-favicon.md | 21 + .../server-deno/examples/avatars/get-flag.md | 21 + .../server-deno/examples/avatars/get-image.md | 21 + .../examples/avatars/get-initials.md | 21 + .../server-deno/examples/avatars/get-q-r.md | 21 + .../databases/create-boolean-attribute.md | 21 + .../examples/databases/create-collection.md | 21 + .../databases/create-datetime-attribute.md | 21 + .../examples/databases/create-document.md | 21 + .../databases/create-email-attribute.md | 21 + .../databases/create-enum-attribute.md | 21 + .../databases/create-float-attribute.md | 21 + .../examples/databases/create-index.md | 21 + .../databases/create-integer-attribute.md | 21 + .../examples/databases/create-ip-attribute.md | 21 + .../create-relationship-attribute.md | 21 + .../databases/create-string-attribute.md | 21 + .../databases/create-url-attribute.md | 21 + .../server-deno/examples/databases/create.md | 21 + .../examples/databases/delete-attribute.md | 21 + .../examples/databases/delete-collection.md | 21 + .../examples/databases/delete-document.md | 21 + .../examples/databases/delete-index.md | 21 + .../server-deno/examples/databases/delete.md | 21 + .../examples/databases/get-attribute.md | 21 + .../examples/databases/get-collection.md | 21 + .../examples/databases/get-document.md | 21 + .../examples/databases/get-index.md | 21 + .../server-deno/examples/databases/get.md | 21 + .../examples/databases/list-attributes.md | 21 + .../examples/databases/list-collections.md | 21 + .../examples/databases/list-documents.md | 21 + .../examples/databases/list-indexes.md | 21 + .../server-deno/examples/databases/list.md | 21 + .../databases/update-boolean-attribute.md | 21 + .../examples/databases/update-collection.md | 21 + .../databases/update-datetime-attribute.md | 21 + .../examples/databases/update-document.md | 21 + .../databases/update-email-attribute.md | 21 + .../databases/update-enum-attribute.md | 21 + .../databases/update-float-attribute.md | 21 + .../databases/update-integer-attribute.md | 21 + .../examples/databases/update-ip-attribute.md | 21 + .../update-relationship-attribute.md | 21 + .../databases/update-string-attribute.md | 21 + .../databases/update-url-attribute.md | 21 + .../server-deno/examples/databases/update.md | 21 + .../examples/functions/create-build.md | 21 + .../examples/functions/create-deployment.md | 21 + .../examples/functions/create-execution.md | 21 + .../examples/functions/create-variable.md | 21 + .../server-deno/examples/functions/create.md | 21 + .../examples/functions/delete-deployment.md | 21 + .../examples/functions/delete-variable.md | 21 + .../server-deno/examples/functions/delete.md | 21 + .../examples/functions/download-deployment.md | 21 + .../examples/functions/get-deployment.md | 21 + .../examples/functions/get-execution.md | 21 + .../examples/functions/get-variable.md | 21 + .../server-deno/examples/functions/get.md | 21 + .../examples/functions/list-deployments.md | 21 + .../examples/functions/list-executions.md | 21 + .../examples/functions/list-runtimes.md | 21 + .../examples/functions/list-variables.md | 21 + .../server-deno/examples/functions/list.md | 21 + .../examples/functions/update-deployment.md | 21 + .../examples/functions/update-variable.md | 21 + .../server-deno/examples/functions/update.md | 21 + .../server-deno/examples/graphql/mutation.md | 21 + .../server-deno/examples/graphql/query.md | 21 + .../examples/health/get-antivirus.md | 21 + .../server-deno/examples/health/get-cache.md | 21 + .../server-deno/examples/health/get-d-b.md | 21 + .../examples/health/get-pub-sub.md | 21 + .../examples/health/get-queue-certificates.md | 21 + .../examples/health/get-queue-functions.md | 21 + .../examples/health/get-queue-logs.md | 21 + .../examples/health/get-queue-webhooks.md | 21 + .../server-deno/examples/health/get-queue.md | 21 + .../examples/health/get-storage-local.md | 21 + .../server-deno/examples/health/get-time.md | 21 + .../1.4.x/server-deno/examples/health/get.md | 21 + .../1.4.x/server-deno/examples/locale/get.md | 21 + .../server-deno/examples/locale/list-codes.md | 21 + .../examples/locale/list-continents.md | 21 + .../examples/locale/list-countries-e-u.md | 21 + .../examples/locale/list-countries-phones.md | 21 + .../examples/locale/list-countries.md | 21 + .../examples/locale/list-currencies.md | 21 + .../examples/locale/list-languages.md | 21 + .../examples/storage/create-bucket.md | 21 + .../examples/storage/create-file.md | 21 + .../examples/storage/delete-bucket.md | 21 + .../examples/storage/delete-file.md | 21 + .../examples/storage/get-bucket.md | 21 + .../examples/storage/get-file-download.md | 21 + .../examples/storage/get-file-preview.md | 21 + .../examples/storage/get-file-view.md | 21 + .../server-deno/examples/storage/get-file.md | 21 + .../examples/storage/list-buckets.md | 21 + .../examples/storage/list-files.md | 21 + .../examples/storage/update-bucket.md | 21 + .../examples/storage/update-file.md | 21 + .../examples/teams/create-membership.md | 21 + .../server-deno/examples/teams/create.md | 21 + .../examples/teams/delete-membership.md | 21 + .../server-deno/examples/teams/delete.md | 21 + .../examples/teams/get-membership.md | 21 + .../server-deno/examples/teams/get-prefs.md | 21 + .../1.4.x/server-deno/examples/teams/get.md | 21 + .../examples/teams/list-memberships.md | 21 + .../1.4.x/server-deno/examples/teams/list.md | 21 + .../teams/update-membership-status.md | 21 + .../examples/teams/update-membership.md | 21 + .../server-deno/examples/teams/update-name.md | 21 + .../examples/teams/update-prefs.md | 21 + .../examples/users/create-argon2user.md | 21 + .../examples/users/create-bcrypt-user.md | 21 + .../examples/users/create-m-d5user.md | 21 + .../examples/users/create-p-h-pass-user.md | 21 + .../examples/users/create-s-h-a-user.md | 21 + .../users/create-scrypt-modified-user.md | 21 + .../examples/users/create-scrypt-user.md | 21 + .../server-deno/examples/users/create.md | 21 + .../examples/users/delete-identity.md | 21 + .../examples/users/delete-session.md | 21 + .../examples/users/delete-sessions.md | 21 + .../server-deno/examples/users/delete.md | 21 + .../server-deno/examples/users/get-prefs.md | 21 + .../1.4.x/server-deno/examples/users/get.md | 21 + .../examples/users/list-identities.md | 21 + .../server-deno/examples/users/list-logs.md | 21 + .../examples/users/list-memberships.md | 21 + .../examples/users/list-sessions.md | 21 + .../1.4.x/server-deno/examples/users/list.md | 21 + .../users/update-email-verification.md | 21 + .../examples/users/update-email.md | 21 + .../examples/users/update-labels.md | 21 + .../server-deno/examples/users/update-name.md | 21 + .../examples/users/update-password.md | 21 + .../users/update-phone-verification.md | 21 + .../examples/users/update-phone.md | 21 + .../examples/users/update-prefs.md | 21 + .../examples/users/update-status.md | 21 + .../account/create-phone-verification.md | 12 + .../examples/account/create-recovery.md | 14 + .../examples/account/create-verification.md | 13 + .../examples/account/delete-identity.md | 13 + .../examples/account/delete-session.md | 13 + .../examples/account/delete-sessions.md | 12 + .../examples/account/get-prefs.md | 12 + .../examples/account/get-session.md | 13 + .../server-dotnet/examples/account/get.md | 12 + .../examples/account/list-identities.md | 12 + .../examples/account/list-logs.md | 12 + .../examples/account/list-sessions.md | 12 + .../examples/account/update-email.md | 14 + .../examples/account/update-name.md | 13 + .../examples/account/update-password.md | 13 + .../account/update-phone-verification.md | 14 + .../examples/account/update-phone.md | 14 + .../examples/account/update-prefs.md | 13 + .../examples/account/update-recovery.md | 16 + .../examples/account/update-session.md | 13 + .../examples/account/update-status.md | 12 + .../examples/account/update-verification.md | 14 + .../examples/avatars/get-browser.md | 13 + .../examples/avatars/get-credit-card.md | 13 + .../examples/avatars/get-favicon.md | 13 + .../examples/avatars/get-flag.md | 13 + .../examples/avatars/get-image.md | 13 + .../examples/avatars/get-initials.md | 12 + .../server-dotnet/examples/avatars/get-q-r.md | 13 + .../databases/create-boolean-attribute.md | 16 + .../examples/databases/create-collection.md | 15 + .../databases/create-datetime-attribute.md | 16 + .../examples/databases/create-document.md | 16 + .../databases/create-email-attribute.md | 16 + .../databases/create-enum-attribute.md | 17 + .../databases/create-float-attribute.md | 16 + .../examples/databases/create-index.md | 17 + .../databases/create-integer-attribute.md | 16 + .../examples/databases/create-ip-attribute.md | 16 + .../create-relationship-attribute.md | 16 + .../databases/create-string-attribute.md | 17 + .../databases/create-url-attribute.md | 16 + .../examples/databases/create.md | 14 + .../examples/databases/delete-attribute.md | 15 + .../examples/databases/delete-collection.md | 14 + .../examples/databases/delete-document.md | 15 + .../examples/databases/delete-index.md | 15 + .../examples/databases/delete.md | 13 + .../examples/databases/get-attribute.md | 15 + .../examples/databases/get-collection.md | 14 + .../examples/databases/get-document.md | 15 + .../examples/databases/get-index.md | 15 + .../server-dotnet/examples/databases/get.md | 13 + .../examples/databases/list-attributes.md | 14 + .../examples/databases/list-collections.md | 13 + .../examples/databases/list-documents.md | 14 + .../examples/databases/list-indexes.md | 14 + .../server-dotnet/examples/databases/list.md | 12 + .../databases/update-boolean-attribute.md | 17 + .../examples/databases/update-collection.md | 15 + .../databases/update-datetime-attribute.md | 17 + .../examples/databases/update-document.md | 15 + .../databases/update-email-attribute.md | 17 + .../databases/update-enum-attribute.md | 18 + .../databases/update-float-attribute.md | 19 + .../databases/update-integer-attribute.md | 19 + .../examples/databases/update-ip-attribute.md | 17 + .../update-relationship-attribute.md | 15 + .../databases/update-string-attribute.md | 17 + .../databases/update-url-attribute.md | 17 + .../examples/databases/update.md | 14 + .../examples/functions/create-build.md | 15 + .../examples/functions/create-deployment.md | 15 + .../examples/functions/create-execution.md | 13 + .../examples/functions/create-variable.md | 15 + .../examples/functions/create.md | 15 + .../examples/functions/delete-deployment.md | 14 + .../examples/functions/delete-variable.md | 14 + .../examples/functions/delete.md | 13 + .../examples/functions/download-deployment.md | 14 + .../examples/functions/get-deployment.md | 14 + .../examples/functions/get-execution.md | 14 + .../examples/functions/get-variable.md | 14 + .../server-dotnet/examples/functions/get.md | 13 + .../examples/functions/list-deployments.md | 13 + .../examples/functions/list-executions.md | 13 + .../examples/functions/list-runtimes.md | 12 + .../examples/functions/list-variables.md | 13 + .../server-dotnet/examples/functions/list.md | 12 + .../examples/functions/update-deployment.md | 14 + .../examples/functions/update-variable.md | 15 + .../examples/functions/update.md | 15 + .../examples/graphql/mutation.md | 13 + .../server-dotnet/examples/graphql/query.md | 13 + .../examples/health/get-antivirus.md | 12 + .../examples/health/get-cache.md | 12 + .../server-dotnet/examples/health/get-d-b.md | 12 + .../examples/health/get-pub-sub.md | 12 + .../examples/health/get-queue-certificates.md | 12 + .../examples/health/get-queue-functions.md | 12 + .../examples/health/get-queue-logs.md | 12 + .../examples/health/get-queue-webhooks.md | 12 + .../examples/health/get-queue.md | 12 + .../examples/health/get-storage-local.md | 12 + .../server-dotnet/examples/health/get-time.md | 12 + .../server-dotnet/examples/health/get.md | 12 + .../server-dotnet/examples/locale/get.md | 12 + .../examples/locale/list-codes.md | 12 + .../examples/locale/list-continents.md | 12 + .../examples/locale/list-countries-e-u.md | 12 + .../examples/locale/list-countries-phones.md | 12 + .../examples/locale/list-countries.md | 12 + .../examples/locale/list-currencies.md | 12 + .../examples/locale/list-languages.md | 12 + .../examples/storage/create-bucket.md | 14 + .../examples/storage/create-file.md | 15 + .../examples/storage/delete-bucket.md | 13 + .../examples/storage/delete-file.md | 14 + .../examples/storage/get-bucket.md | 13 + .../examples/storage/get-file-download.md | 14 + .../examples/storage/get-file-preview.md | 14 + .../examples/storage/get-file-view.md | 14 + .../examples/storage/get-file.md | 14 + .../examples/storage/list-buckets.md | 12 + .../examples/storage/list-files.md | 13 + .../examples/storage/update-bucket.md | 14 + .../examples/storage/update-file.md | 14 + .../examples/teams/create-membership.md | 15 + .../server-dotnet/examples/teams/create.md | 14 + .../examples/teams/delete-membership.md | 14 + .../server-dotnet/examples/teams/delete.md | 13 + .../examples/teams/get-membership.md | 14 + .../server-dotnet/examples/teams/get-prefs.md | 13 + .../1.4.x/server-dotnet/examples/teams/get.md | 13 + .../examples/teams/list-memberships.md | 13 + .../server-dotnet/examples/teams/list.md | 12 + .../teams/update-membership-status.md | 16 + .../examples/teams/update-membership.md | 15 + .../examples/teams/update-name.md | 14 + .../examples/teams/update-prefs.md | 14 + .../examples/users/create-argon2user.md | 15 + .../examples/users/create-bcrypt-user.md | 15 + .../examples/users/create-m-d5user.md | 15 + .../examples/users/create-p-h-pass-user.md | 15 + .../examples/users/create-s-h-a-user.md | 15 + .../users/create-scrypt-modified-user.md | 18 + .../examples/users/create-scrypt-user.md | 20 + .../server-dotnet/examples/users/create.md | 13 + .../examples/users/delete-identity.md | 13 + .../examples/users/delete-session.md | 14 + .../examples/users/delete-sessions.md | 13 + .../server-dotnet/examples/users/delete.md | 13 + .../server-dotnet/examples/users/get-prefs.md | 13 + .../1.4.x/server-dotnet/examples/users/get.md | 13 + .../examples/users/list-identities.md | 12 + .../server-dotnet/examples/users/list-logs.md | 13 + .../examples/users/list-memberships.md | 13 + .../examples/users/list-sessions.md | 13 + .../server-dotnet/examples/users/list.md | 12 + .../users/update-email-verification.md | 14 + .../examples/users/update-email.md | 14 + .../examples/users/update-labels.md | 14 + .../examples/users/update-name.md | 14 + .../examples/users/update-password.md | 14 + .../users/update-phone-verification.md | 14 + .../examples/users/update-phone.md | 14 + .../examples/users/update-prefs.md | 14 + .../examples/users/update-status.md | 14 + .../account/create-phone-verification.md | 9 + .../examples/account/create-recovery.md | 12 + .../examples/account/create-verification.md | 11 + .../examples/account/delete-identity.md | 7 + .../examples/account/delete-session.md | 7 + .../examples/account/delete-sessions.md | 5 + .../examples/account/get-prefs.md | 5 + .../examples/account/get-session.md | 31 + .../server-graphql/examples/account/get.md | 20 + .../examples/account/list-identities.md | 17 + .../examples/account/list-logs.md | 28 + .../examples/account/list-sessions.md | 32 + .../examples/account/update-email.md | 23 + .../examples/account/update-name.md | 22 + .../examples/account/update-password.md | 22 + .../account/update-phone-verification.md | 12 + .../examples/account/update-phone.md | 23 + .../examples/account/update-prefs.md | 22 + .../examples/account/update-recovery.md | 14 + .../examples/account/update-session.md | 31 + .../examples/account/update-status.md | 20 + .../examples/account/update-verification.md | 12 + .../examples/avatars/get-browser.md | 7 + .../examples/avatars/get-credit-card.md | 7 + .../examples/avatars/get-favicon.md | 7 + .../examples/avatars/get-flag.md | 7 + .../examples/avatars/get-image.md | 7 + .../examples/avatars/get-initials.md | 5 + .../examples/avatars/get-q-r.md | 7 + .../databases/create-boolean-attribute.md | 14 + .../examples/databases/create-collection.md | 24 + .../databases/create-datetime-attribute.md | 15 + .../examples/databases/create-document.md | 16 + .../databases/create-email-attribute.md | 15 + .../databases/create-enum-attribute.md | 17 + .../databases/create-float-attribute.md | 14 + .../examples/databases/create-index.md | 15 + .../databases/create-integer-attribute.md | 14 + .../examples/databases/create-ip-attribute.md | 15 + .../create-relationship-attribute.md | 20 + .../databases/create-string-attribute.md | 16 + .../databases/create-url-attribute.md | 15 + .../examples/databases/create.md | 12 + .../examples/databases/delete-attribute.md | 9 + .../examples/databases/delete-collection.md | 8 + .../examples/databases/delete-document.md | 9 + .../examples/databases/delete-index.md | 9 + .../examples/databases/delete.md | 7 + .../examples/databases/get-attribute.md | 9 + .../examples/databases/get-collection.md | 23 + .../examples/databases/get-document.md | 15 + .../examples/databases/get-index.md | 13 + .../server-graphql/examples/databases/get.md | 11 + .../examples/databases/list-attributes.md | 9 + .../examples/databases/list-collections.md | 25 + .../examples/databases/list-documents.md | 17 + .../examples/databases/list-indexes.md | 15 + .../server-graphql/examples/databases/list.md | 12 + .../databases/update-boolean-attribute.md | 15 + .../examples/databases/update-collection.md | 24 + .../databases/update-datetime-attribute.md | 16 + .../examples/databases/update-document.md | 15 + .../databases/update-email-attribute.md | 16 + .../databases/update-enum-attribute.md | 18 + .../databases/update-float-attribute.md | 17 + .../databases/update-integer-attribute.md | 17 + .../examples/databases/update-ip-attribute.md | 16 + .../update-relationship-attribute.md | 19 + .../databases/update-string-attribute.md | 16 + .../databases/update-url-attribute.md | 16 + .../examples/databases/update.md | 12 + .../examples/functions/create-build.md | 9 + .../examples/functions/create-deployment.md | 24 + .../examples/functions/create-execution.md | 28 + .../examples/functions/create-variable.md | 15 + .../examples/functions/create.md | 38 + .../examples/functions/delete-deployment.md | 8 + .../examples/functions/delete-variable.md | 8 + .../examples/functions/delete.md | 7 + .../examples/functions/download-deployment.md | 8 + .../examples/functions/get-deployment.md | 30 + .../examples/functions/get-execution.md | 29 + .../examples/functions/get-variable.md | 14 + .../server-graphql/examples/functions/get.md | 36 + .../examples/functions/list-deployments.md | 32 + .../examples/functions/list-executions.md | 31 + .../examples/functions/list-runtimes.md | 14 + .../examples/functions/list-variables.md | 16 + .../server-graphql/examples/functions/list.md | 37 + .../examples/functions/update-deployment.md | 37 + .../examples/functions/update-variable.md | 15 + .../examples/functions/update.md | 38 + .../examples/health/get-antivirus.md | 6 + .../examples/health/get-cache.md | 7 + .../server-graphql/examples/health/get-d-b.md | 7 + .../examples/health/get-pub-sub.md | 7 + .../examples/health/get-queue-certificates.md | 5 + .../examples/health/get-queue-functions.md | 5 + .../examples/health/get-queue-logs.md | 5 + .../examples/health/get-queue-webhooks.md | 5 + .../examples/health/get-queue.md | 7 + .../examples/health/get-storage-local.md | 7 + .../examples/health/get-time.md | 7 + .../server-graphql/examples/health/get.md | 7 + .../server-graphql/examples/locale/get.md | 11 + .../examples/locale/list-codes.md | 9 + .../examples/locale/list-continents.md | 9 + .../examples/locale/list-countries-e-u.md | 9 + .../examples/locale/list-countries-phones.md | 10 + .../examples/locale/list-countries.md | 9 + .../examples/locale/list-currencies.md | 14 + .../examples/locale/list-languages.md | 10 + .../examples/storage/create-bucket.md | 19 + .../examples/storage/create-file.md | 25 + .../examples/storage/delete-bucket.md | 7 + .../examples/storage/delete-file.md | 8 + .../examples/storage/get-bucket.md | 18 + .../examples/storage/get-file-download.md | 8 + .../examples/storage/get-file-preview.md | 8 + .../examples/storage/get-file-view.md | 8 + .../examples/storage/get-file.md | 18 + .../examples/storage/list-buckets.md | 19 + .../examples/storage/list-files.md | 20 + .../examples/storage/update-bucket.md | 19 + .../examples/storage/update-file.md | 18 + .../examples/teams/create-membership.md | 20 + .../server-graphql/examples/teams/create.md | 15 + .../examples/teams/delete-membership.md | 8 + .../server-graphql/examples/teams/delete.md | 7 + .../examples/teams/get-membership.md | 19 + .../examples/teams/get-prefs.md | 7 + .../server-graphql/examples/teams/get.md | 14 + .../examples/teams/list-memberships.md | 21 + .../server-graphql/examples/teams/list.md | 15 + .../teams/update-membership-status.md | 21 + .../examples/teams/update-membership.md | 20 + .../examples/teams/update-name.md | 15 + .../examples/teams/update-prefs.md | 8 + .../examples/users/create-argon2user.md | 24 + .../examples/users/create-bcrypt-user.md | 24 + .../examples/users/create-m-d5user.md | 24 + .../examples/users/create-p-h-pass-user.md | 24 + .../examples/users/create-s-h-a-user.md | 24 + .../users/create-scrypt-modified-user.md | 27 + .../examples/users/create-scrypt-user.md | 29 + .../server-graphql/examples/users/create.md | 22 + .../examples/users/delete-identity.md | 7 + .../examples/users/delete-session.md | 8 + .../examples/users/delete-sessions.md | 7 + .../server-graphql/examples/users/delete.md | 7 + .../examples/users/get-prefs.md | 7 + .../server-graphql/examples/users/get.md | 22 + .../examples/users/list-identities.md | 17 + .../examples/users/list-logs.md | 30 + .../examples/users/list-memberships.md | 21 + .../examples/users/list-sessions.md | 34 + .../server-graphql/examples/users/list.md | 23 + .../users/update-email-verification.md | 23 + .../examples/users/update-email.md | 23 + .../examples/users/update-labels.md | 23 + .../examples/users/update-name.md | 23 + .../examples/users/update-password.md | 23 + .../users/update-phone-verification.md | 23 + .../examples/users/update-phone.md | 23 + .../examples/users/update-prefs.md | 8 + .../examples/users/update-status.md | 23 + .../java/account/create-phone-verification.md | 19 + .../java/account/create-recovery.md | 23 + .../java/account/create-verification.md | 22 + .../java/account/delete-identity.md | 22 + .../java/account/delete-session.md | 22 + .../java/account/delete-sessions.md | 19 + .../server-kotlin/java/account/get-prefs.md | 19 + .../server-kotlin/java/account/get-session.md | 22 + .../1.4.x/server-kotlin/java/account/get.md | 19 + .../java/account/list-identities.md | 21 + .../server-kotlin/java/account/list-logs.md | 21 + .../java/account/list-sessions.md | 19 + .../java/account/update-email.md | 23 + .../server-kotlin/java/account/update-name.md | 22 + .../java/account/update-password.md | 22 + .../java/account/update-phone-verification.md | 23 + .../java/account/update-phone.md | 23 + .../java/account/update-prefs.md | 22 + .../java/account/update-recovery.md | 25 + .../java/account/update-session.md | 22 + .../java/account/update-status.md | 19 + .../java/account/update-verification.md | 23 + .../server-kotlin/java/avatars/get-browser.md | 22 + .../java/avatars/get-credit-card.md | 22 + .../server-kotlin/java/avatars/get-favicon.md | 22 + .../server-kotlin/java/avatars/get-flag.md | 22 + .../server-kotlin/java/avatars/get-image.md | 22 + .../java/avatars/get-initials.md | 21 + .../server-kotlin/java/avatars/get-q-r.md | 22 + .../databases/create-boolean-attribute.md | 25 + .../java/databases/create-collection.md | 24 + .../databases/create-datetime-attribute.md | 25 + .../java/databases/create-document.md | 25 + .../java/databases/create-email-attribute.md | 25 + .../java/databases/create-enum-attribute.md | 26 + .../java/databases/create-float-attribute.md | 25 + .../java/databases/create-index.md | 26 + .../databases/create-integer-attribute.md | 25 + .../java/databases/create-ip-attribute.md | 25 + .../create-relationship-attribute.md | 25 + .../java/databases/create-string-attribute.md | 26 + .../java/databases/create-url-attribute.md | 25 + .../server-kotlin/java/databases/create.md | 23 + .../java/databases/delete-attribute.md | 24 + .../java/databases/delete-collection.md | 23 + .../java/databases/delete-document.md | 24 + .../java/databases/delete-index.md | 24 + .../server-kotlin/java/databases/delete.md | 22 + .../java/databases/get-attribute.md | 24 + .../java/databases/get-collection.md | 23 + .../java/databases/get-document.md | 24 + .../server-kotlin/java/databases/get-index.md | 24 + .../1.4.x/server-kotlin/java/databases/get.md | 22 + .../java/databases/list-attributes.md | 23 + .../java/databases/list-collections.md | 22 + .../java/databases/list-documents.md | 23 + .../java/databases/list-indexes.md | 23 + .../server-kotlin/java/databases/list.md | 21 + .../databases/update-boolean-attribute.md | 26 + .../java/databases/update-collection.md | 24 + .../databases/update-datetime-attribute.md | 26 + .../java/databases/update-document.md | 24 + .../java/databases/update-email-attribute.md | 26 + .../java/databases/update-enum-attribute.md | 27 + .../java/databases/update-float-attribute.md | 28 + .../databases/update-integer-attribute.md | 28 + .../java/databases/update-ip-attribute.md | 26 + .../update-relationship-attribute.md | 24 + .../java/databases/update-string-attribute.md | 26 + .../java/databases/update-url-attribute.md | 26 + .../server-kotlin/java/databases/update.md | 23 + .../java/functions/create-build.md | 24 + .../java/functions/create-deployment.md | 25 + .../java/functions/create-execution.md | 22 + .../java/functions/create-variable.md | 24 + .../server-kotlin/java/functions/create.md | 24 + .../java/functions/delete-deployment.md | 23 + .../java/functions/delete-variable.md | 23 + .../server-kotlin/java/functions/delete.md | 22 + .../java/functions/download-deployment.md | 23 + .../java/functions/get-deployment.md | 23 + .../java/functions/get-execution.md | 23 + .../java/functions/get-variable.md | 23 + .../1.4.x/server-kotlin/java/functions/get.md | 22 + .../java/functions/list-deployments.md | 22 + .../java/functions/list-executions.md | 22 + .../java/functions/list-runtimes.md | 19 + .../java/functions/list-variables.md | 22 + .../server-kotlin/java/functions/list.md | 21 + .../java/functions/update-deployment.md | 23 + .../java/functions/update-variable.md | 24 + .../server-kotlin/java/functions/update.md | 24 + .../server-kotlin/java/graphql/mutation.md | 22 + .../1.4.x/server-kotlin/java/graphql/query.md | 22 + .../java/health/get-antivirus.md | 19 + .../server-kotlin/java/health/get-cache.md | 19 + .../server-kotlin/java/health/get-d-b.md | 19 + .../server-kotlin/java/health/get-pub-sub.md | 19 + .../java/health/get-queue-certificates.md | 19 + .../java/health/get-queue-functions.md | 19 + .../java/health/get-queue-logs.md | 19 + .../java/health/get-queue-webhooks.md | 19 + .../server-kotlin/java/health/get-queue.md | 19 + .../java/health/get-storage-local.md | 19 + .../server-kotlin/java/health/get-time.md | 19 + .../1.4.x/server-kotlin/java/health/get.md | 19 + .../1.4.x/server-kotlin/java/locale/get.md | 19 + .../server-kotlin/java/locale/list-codes.md | 19 + .../java/locale/list-continents.md | 19 + .../java/locale/list-countries-e-u.md | 19 + .../java/locale/list-countries-phones.md | 19 + .../java/locale/list-countries.md | 19 + .../java/locale/list-currencies.md | 19 + .../java/locale/list-languages.md | 19 + .../java/storage/create-bucket.md | 23 + .../server-kotlin/java/storage/create-file.md | 25 + .../java/storage/delete-bucket.md | 22 + .../server-kotlin/java/storage/delete-file.md | 23 + .../server-kotlin/java/storage/get-bucket.md | 22 + .../java/storage/get-file-download.md | 23 + .../java/storage/get-file-preview.md | 23 + .../java/storage/get-file-view.md | 23 + .../server-kotlin/java/storage/get-file.md | 23 + .../java/storage/list-buckets.md | 21 + .../server-kotlin/java/storage/list-files.md | 22 + .../java/storage/update-bucket.md | 23 + .../server-kotlin/java/storage/update-file.md | 23 + .../java/teams/create-membership.md | 24 + .../1.4.x/server-kotlin/java/teams/create.md | 23 + .../java/teams/delete-membership.md | 23 + .../1.4.x/server-kotlin/java/teams/delete.md | 22 + .../java/teams/get-membership.md | 23 + .../server-kotlin/java/teams/get-prefs.md | 22 + .../1.4.x/server-kotlin/java/teams/get.md | 22 + .../java/teams/list-memberships.md | 22 + .../1.4.x/server-kotlin/java/teams/list.md | 21 + .../java/teams/update-membership-status.md | 25 + .../java/teams/update-membership.md | 24 + .../server-kotlin/java/teams/update-name.md | 23 + .../server-kotlin/java/teams/update-prefs.md | 23 + .../java/users/create-argon2user.md | 24 + .../java/users/create-bcrypt-user.md | 24 + .../java/users/create-m-d5user.md | 24 + .../java/users/create-p-h-pass-user.md | 24 + .../java/users/create-s-h-a-user.md | 24 + .../java/users/create-scrypt-modified-user.md | 27 + .../java/users/create-scrypt-user.md | 29 + .../1.4.x/server-kotlin/java/users/create.md | 22 + .../java/users/delete-identity.md | 22 + .../java/users/delete-session.md | 23 + .../java/users/delete-sessions.md | 22 + .../1.4.x/server-kotlin/java/users/delete.md | 22 + .../server-kotlin/java/users/get-prefs.md | 22 + .../1.4.x/server-kotlin/java/users/get.md | 22 + .../java/users/list-identities.md | 21 + .../server-kotlin/java/users/list-logs.md | 22 + .../java/users/list-memberships.md | 22 + .../server-kotlin/java/users/list-sessions.md | 22 + .../1.4.x/server-kotlin/java/users/list.md | 21 + .../java/users/update-email-verification.md | 23 + .../server-kotlin/java/users/update-email.md | 23 + .../server-kotlin/java/users/update-labels.md | 23 + .../server-kotlin/java/users/update-name.md | 23 + .../java/users/update-password.md | 23 + .../java/users/update-phone-verification.md | 23 + .../server-kotlin/java/users/update-phone.md | 23 + .../server-kotlin/java/users/update-prefs.md | 23 + .../server-kotlin/java/users/update-status.md | 23 + .../account/create-phone-verification.md | 11 + .../kotlin/account/create-recovery.md | 14 + .../kotlin/account/create-verification.md | 13 + .../kotlin/account/delete-identity.md | 13 + .../kotlin/account/delete-session.md | 13 + .../kotlin/account/delete-sessions.md | 11 + .../server-kotlin/kotlin/account/get-prefs.md | 11 + .../kotlin/account/get-session.md | 13 + .../1.4.x/server-kotlin/kotlin/account/get.md | 11 + .../kotlin/account/list-identities.md | 12 + .../server-kotlin/kotlin/account/list-logs.md | 12 + .../kotlin/account/list-sessions.md | 11 + .../kotlin/account/update-email.md | 14 + .../kotlin/account/update-name.md | 13 + .../kotlin/account/update-password.md | 13 + .../account/update-phone-verification.md | 14 + .../kotlin/account/update-phone.md | 14 + .../kotlin/account/update-prefs.md | 13 + .../kotlin/account/update-recovery.md | 16 + .../kotlin/account/update-session.md | 13 + .../kotlin/account/update-status.md | 11 + .../kotlin/account/update-verification.md | 14 + .../kotlin/avatars/get-browser.md | 13 + .../kotlin/avatars/get-credit-card.md | 13 + .../kotlin/avatars/get-favicon.md | 13 + .../server-kotlin/kotlin/avatars/get-flag.md | 13 + .../server-kotlin/kotlin/avatars/get-image.md | 13 + .../kotlin/avatars/get-initials.md | 12 + .../server-kotlin/kotlin/avatars/get-q-r.md | 13 + .../databases/create-boolean-attribute.md | 16 + .../kotlin/databases/create-collection.md | 15 + .../databases/create-datetime-attribute.md | 16 + .../kotlin/databases/create-document.md | 16 + .../databases/create-email-attribute.md | 16 + .../kotlin/databases/create-enum-attribute.md | 17 + .../databases/create-float-attribute.md | 16 + .../kotlin/databases/create-index.md | 17 + .../databases/create-integer-attribute.md | 16 + .../kotlin/databases/create-ip-attribute.md | 16 + .../create-relationship-attribute.md | 16 + .../databases/create-string-attribute.md | 17 + .../kotlin/databases/create-url-attribute.md | 16 + .../server-kotlin/kotlin/databases/create.md | 14 + .../kotlin/databases/delete-attribute.md | 15 + .../kotlin/databases/delete-collection.md | 14 + .../kotlin/databases/delete-document.md | 15 + .../kotlin/databases/delete-index.md | 15 + .../server-kotlin/kotlin/databases/delete.md | 13 + .../kotlin/databases/get-attribute.md | 15 + .../kotlin/databases/get-collection.md | 14 + .../kotlin/databases/get-document.md | 15 + .../kotlin/databases/get-index.md | 15 + .../server-kotlin/kotlin/databases/get.md | 13 + .../kotlin/databases/list-attributes.md | 14 + .../kotlin/databases/list-collections.md | 13 + .../kotlin/databases/list-documents.md | 14 + .../kotlin/databases/list-indexes.md | 14 + .../server-kotlin/kotlin/databases/list.md | 12 + .../databases/update-boolean-attribute.md | 17 + .../kotlin/databases/update-collection.md | 15 + .../databases/update-datetime-attribute.md | 17 + .../kotlin/databases/update-document.md | 15 + .../databases/update-email-attribute.md | 17 + .../kotlin/databases/update-enum-attribute.md | 18 + .../databases/update-float-attribute.md | 19 + .../databases/update-integer-attribute.md | 19 + .../kotlin/databases/update-ip-attribute.md | 17 + .../update-relationship-attribute.md | 15 + .../databases/update-string-attribute.md | 17 + .../kotlin/databases/update-url-attribute.md | 17 + .../server-kotlin/kotlin/databases/update.md | 14 + .../kotlin/functions/create-build.md | 15 + .../kotlin/functions/create-deployment.md | 16 + .../kotlin/functions/create-execution.md | 13 + .../kotlin/functions/create-variable.md | 15 + .../server-kotlin/kotlin/functions/create.md | 15 + .../kotlin/functions/delete-deployment.md | 14 + .../kotlin/functions/delete-variable.md | 14 + .../server-kotlin/kotlin/functions/delete.md | 13 + .../kotlin/functions/download-deployment.md | 14 + .../kotlin/functions/get-deployment.md | 14 + .../kotlin/functions/get-execution.md | 14 + .../kotlin/functions/get-variable.md | 14 + .../server-kotlin/kotlin/functions/get.md | 13 + .../kotlin/functions/list-deployments.md | 13 + .../kotlin/functions/list-executions.md | 13 + .../kotlin/functions/list-runtimes.md | 11 + .../kotlin/functions/list-variables.md | 13 + .../server-kotlin/kotlin/functions/list.md | 12 + .../kotlin/functions/update-deployment.md | 14 + .../kotlin/functions/update-variable.md | 15 + .../server-kotlin/kotlin/functions/update.md | 15 + .../server-kotlin/kotlin/graphql/mutation.md | 13 + .../server-kotlin/kotlin/graphql/query.md | 13 + .../kotlin/health/get-antivirus.md | 11 + .../server-kotlin/kotlin/health/get-cache.md | 11 + .../server-kotlin/kotlin/health/get-d-b.md | 11 + .../kotlin/health/get-pub-sub.md | 11 + .../kotlin/health/get-queue-certificates.md | 11 + .../kotlin/health/get-queue-functions.md | 11 + .../kotlin/health/get-queue-logs.md | 11 + .../kotlin/health/get-queue-webhooks.md | 11 + .../server-kotlin/kotlin/health/get-queue.md | 11 + .../kotlin/health/get-storage-local.md | 11 + .../server-kotlin/kotlin/health/get-time.md | 11 + .../1.4.x/server-kotlin/kotlin/health/get.md | 11 + .../1.4.x/server-kotlin/kotlin/locale/get.md | 11 + .../server-kotlin/kotlin/locale/list-codes.md | 11 + .../kotlin/locale/list-continents.md | 11 + .../kotlin/locale/list-countries-e-u.md | 11 + .../kotlin/locale/list-countries-phones.md | 11 + .../kotlin/locale/list-countries.md | 11 + .../kotlin/locale/list-currencies.md | 11 + .../kotlin/locale/list-languages.md | 11 + .../kotlin/storage/create-bucket.md | 14 + .../kotlin/storage/create-file.md | 16 + .../kotlin/storage/delete-bucket.md | 13 + .../kotlin/storage/delete-file.md | 14 + .../kotlin/storage/get-bucket.md | 13 + .../kotlin/storage/get-file-download.md | 14 + .../kotlin/storage/get-file-preview.md | 14 + .../kotlin/storage/get-file-view.md | 14 + .../server-kotlin/kotlin/storage/get-file.md | 14 + .../kotlin/storage/list-buckets.md | 12 + .../kotlin/storage/list-files.md | 13 + .../kotlin/storage/update-bucket.md | 14 + .../kotlin/storage/update-file.md | 14 + .../kotlin/teams/create-membership.md | 15 + .../server-kotlin/kotlin/teams/create.md | 14 + .../kotlin/teams/delete-membership.md | 14 + .../server-kotlin/kotlin/teams/delete.md | 13 + .../kotlin/teams/get-membership.md | 14 + .../server-kotlin/kotlin/teams/get-prefs.md | 13 + .../1.4.x/server-kotlin/kotlin/teams/get.md | 13 + .../kotlin/teams/list-memberships.md | 13 + .../1.4.x/server-kotlin/kotlin/teams/list.md | 12 + .../kotlin/teams/update-membership-status.md | 16 + .../kotlin/teams/update-membership.md | 15 + .../server-kotlin/kotlin/teams/update-name.md | 14 + .../kotlin/teams/update-prefs.md | 14 + .../kotlin/users/create-argon2user.md | 15 + .../kotlin/users/create-bcrypt-user.md | 15 + .../kotlin/users/create-m-d5user.md | 15 + .../kotlin/users/create-p-h-pass-user.md | 15 + .../kotlin/users/create-s-h-a-user.md | 15 + .../users/create-scrypt-modified-user.md | 18 + .../kotlin/users/create-scrypt-user.md | 20 + .../server-kotlin/kotlin/users/create.md | 13 + .../kotlin/users/delete-identity.md | 13 + .../kotlin/users/delete-session.md | 14 + .../kotlin/users/delete-sessions.md | 13 + .../server-kotlin/kotlin/users/delete.md | 13 + .../server-kotlin/kotlin/users/get-prefs.md | 13 + .../1.4.x/server-kotlin/kotlin/users/get.md | 13 + .../kotlin/users/list-identities.md | 12 + .../server-kotlin/kotlin/users/list-logs.md | 13 + .../kotlin/users/list-memberships.md | 13 + .../kotlin/users/list-sessions.md | 13 + .../1.4.x/server-kotlin/kotlin/users/list.md | 12 + .../kotlin/users/update-email-verification.md | 14 + .../kotlin/users/update-email.md | 14 + .../kotlin/users/update-labels.md | 14 + .../server-kotlin/kotlin/users/update-name.md | 14 + .../kotlin/users/update-password.md | 14 + .../kotlin/users/update-phone-verification.md | 14 + .../kotlin/users/update-phone.md | 14 + .../kotlin/users/update-prefs.md | 14 + .../kotlin/users/update-status.md | 14 + .../account/create-phone-verification.md | 20 + .../examples/account/create-recovery.md | 20 + .../examples/account/create-verification.md | 20 + .../examples/account/delete-identity.md | 20 + .../examples/account/delete-session.md | 20 + .../examples/account/delete-sessions.md | 20 + .../examples/account/get-prefs.md | 20 + .../examples/account/get-session.md | 20 + .../server-nodejs/examples/account/get.md | 20 + .../examples/account/list-identities.md | 20 + .../examples/account/list-logs.md | 20 + .../examples/account/list-sessions.md | 20 + .../examples/account/update-email.md | 20 + .../examples/account/update-name.md | 20 + .../examples/account/update-password.md | 20 + .../account/update-phone-verification.md | 20 + .../examples/account/update-phone.md | 20 + .../examples/account/update-prefs.md | 20 + .../examples/account/update-recovery.md | 20 + .../examples/account/update-session.md | 20 + .../examples/account/update-status.md | 20 + .../examples/account/update-verification.md | 20 + .../examples/avatars/get-browser.md | 20 + .../examples/avatars/get-credit-card.md | 20 + .../examples/avatars/get-favicon.md | 20 + .../examples/avatars/get-flag.md | 20 + .../examples/avatars/get-image.md | 20 + .../examples/avatars/get-initials.md | 20 + .../server-nodejs/examples/avatars/get-q-r.md | 20 + .../databases/create-boolean-attribute.md | 20 + .../examples/databases/create-collection.md | 20 + .../databases/create-datetime-attribute.md | 20 + .../examples/databases/create-document.md | 20 + .../databases/create-email-attribute.md | 20 + .../databases/create-enum-attribute.md | 20 + .../databases/create-float-attribute.md | 20 + .../examples/databases/create-index.md | 20 + .../databases/create-integer-attribute.md | 20 + .../examples/databases/create-ip-attribute.md | 20 + .../create-relationship-attribute.md | 20 + .../databases/create-string-attribute.md | 20 + .../databases/create-url-attribute.md | 20 + .../examples/databases/create.md | 20 + .../examples/databases/delete-attribute.md | 20 + .../examples/databases/delete-collection.md | 20 + .../examples/databases/delete-document.md | 20 + .../examples/databases/delete-index.md | 20 + .../examples/databases/delete.md | 20 + .../examples/databases/get-attribute.md | 20 + .../examples/databases/get-collection.md | 20 + .../examples/databases/get-document.md | 20 + .../examples/databases/get-index.md | 20 + .../server-nodejs/examples/databases/get.md | 20 + .../examples/databases/list-attributes.md | 20 + .../examples/databases/list-collections.md | 20 + .../examples/databases/list-documents.md | 20 + .../examples/databases/list-indexes.md | 20 + .../server-nodejs/examples/databases/list.md | 20 + .../databases/update-boolean-attribute.md | 20 + .../examples/databases/update-collection.md | 20 + .../databases/update-datetime-attribute.md | 20 + .../examples/databases/update-document.md | 20 + .../databases/update-email-attribute.md | 20 + .../databases/update-enum-attribute.md | 20 + .../databases/update-float-attribute.md | 20 + .../databases/update-integer-attribute.md | 20 + .../examples/databases/update-ip-attribute.md | 20 + .../update-relationship-attribute.md | 20 + .../databases/update-string-attribute.md | 20 + .../databases/update-url-attribute.md | 20 + .../examples/databases/update.md | 20 + .../examples/functions/create-build.md | 20 + .../examples/functions/create-deployment.md | 21 + .../examples/functions/create-execution.md | 20 + .../examples/functions/create-variable.md | 20 + .../examples/functions/create.md | 20 + .../examples/functions/delete-deployment.md | 20 + .../examples/functions/delete-variable.md | 20 + .../examples/functions/delete.md | 20 + .../examples/functions/download-deployment.md | 20 + .../examples/functions/get-deployment.md | 20 + .../examples/functions/get-execution.md | 20 + .../examples/functions/get-variable.md | 20 + .../server-nodejs/examples/functions/get.md | 20 + .../examples/functions/list-deployments.md | 20 + .../examples/functions/list-executions.md | 20 + .../examples/functions/list-runtimes.md | 20 + .../examples/functions/list-variables.md | 20 + .../server-nodejs/examples/functions/list.md | 20 + .../examples/functions/update-deployment.md | 20 + .../examples/functions/update-variable.md | 20 + .../examples/functions/update.md | 20 + .../examples/graphql/mutation.md | 20 + .../server-nodejs/examples/graphql/query.md | 20 + .../examples/health/get-antivirus.md | 20 + .../examples/health/get-cache.md | 20 + .../server-nodejs/examples/health/get-d-b.md | 20 + .../examples/health/get-pub-sub.md | 20 + .../examples/health/get-queue-certificates.md | 20 + .../examples/health/get-queue-functions.md | 20 + .../examples/health/get-queue-logs.md | 20 + .../examples/health/get-queue-webhooks.md | 20 + .../examples/health/get-queue.md | 20 + .../examples/health/get-storage-local.md | 20 + .../server-nodejs/examples/health/get-time.md | 20 + .../server-nodejs/examples/health/get.md | 20 + .../server-nodejs/examples/locale/get.md | 20 + .../examples/locale/list-codes.md | 20 + .../examples/locale/list-continents.md | 20 + .../examples/locale/list-countries-e-u.md | 20 + .../examples/locale/list-countries-phones.md | 20 + .../examples/locale/list-countries.md | 20 + .../examples/locale/list-currencies.md | 20 + .../examples/locale/list-languages.md | 20 + .../examples/storage/create-bucket.md | 20 + .../examples/storage/create-file.md | 21 + .../examples/storage/delete-bucket.md | 20 + .../examples/storage/delete-file.md | 20 + .../examples/storage/get-bucket.md | 20 + .../examples/storage/get-file-download.md | 20 + .../examples/storage/get-file-preview.md | 20 + .../examples/storage/get-file-view.md | 20 + .../examples/storage/get-file.md | 20 + .../examples/storage/list-buckets.md | 20 + .../examples/storage/list-files.md | 20 + .../examples/storage/update-bucket.md | 20 + .../examples/storage/update-file.md | 20 + .../examples/teams/create-membership.md | 20 + .../server-nodejs/examples/teams/create.md | 20 + .../examples/teams/delete-membership.md | 20 + .../server-nodejs/examples/teams/delete.md | 20 + .../examples/teams/get-membership.md | 20 + .../server-nodejs/examples/teams/get-prefs.md | 20 + .../1.4.x/server-nodejs/examples/teams/get.md | 20 + .../examples/teams/list-memberships.md | 20 + .../server-nodejs/examples/teams/list.md | 20 + .../teams/update-membership-status.md | 20 + .../examples/teams/update-membership.md | 20 + .../examples/teams/update-name.md | 20 + .../examples/teams/update-prefs.md | 20 + .../examples/users/create-argon2user.md | 20 + .../examples/users/create-bcrypt-user.md | 20 + .../examples/users/create-m-d5user.md | 20 + .../examples/users/create-p-h-pass-user.md | 20 + .../examples/users/create-s-h-a-user.md | 20 + .../users/create-scrypt-modified-user.md | 20 + .../examples/users/create-scrypt-user.md | 20 + .../server-nodejs/examples/users/create.md | 20 + .../examples/users/delete-identity.md | 20 + .../examples/users/delete-session.md | 20 + .../examples/users/delete-sessions.md | 20 + .../server-nodejs/examples/users/delete.md | 20 + .../server-nodejs/examples/users/get-prefs.md | 20 + .../1.4.x/server-nodejs/examples/users/get.md | 20 + .../examples/users/list-identities.md | 20 + .../server-nodejs/examples/users/list-logs.md | 20 + .../examples/users/list-memberships.md | 20 + .../examples/users/list-sessions.md | 20 + .../server-nodejs/examples/users/list.md | 20 + .../users/update-email-verification.md | 20 + .../examples/users/update-email.md | 20 + .../examples/users/update-labels.md | 20 + .../examples/users/update-name.md | 20 + .../examples/users/update-password.md | 20 + .../users/update-phone-verification.md | 20 + .../examples/users/update-phone.md | 20 + .../examples/users/update-prefs.md | 20 + .../examples/users/update-status.md | 20 + .../account/create-phone-verification.md | 16 + .../examples/account/create-recovery.md | 16 + .../examples/account/create-verification.md | 16 + .../examples/account/delete-identity.md | 16 + .../examples/account/delete-session.md | 16 + .../examples/account/delete-sessions.md | 16 + .../server-php/examples/account/get-prefs.md | 16 + .../examples/account/get-session.md | 16 + .../1.4.x/server-php/examples/account/get.md | 16 + .../examples/account/list-identities.md | 16 + .../server-php/examples/account/list-logs.md | 16 + .../examples/account/list-sessions.md | 16 + .../examples/account/update-email.md | 16 + .../examples/account/update-name.md | 16 + .../examples/account/update-password.md | 16 + .../account/update-phone-verification.md | 16 + .../examples/account/update-phone.md | 16 + .../examples/account/update-prefs.md | 16 + .../examples/account/update-recovery.md | 16 + .../examples/account/update-session.md | 16 + .../examples/account/update-status.md | 16 + .../examples/account/update-verification.md | 16 + .../examples/avatars/get-browser.md | 16 + .../examples/avatars/get-credit-card.md | 16 + .../examples/avatars/get-favicon.md | 16 + .../server-php/examples/avatars/get-flag.md | 16 + .../server-php/examples/avatars/get-image.md | 16 + .../examples/avatars/get-initials.md | 16 + .../server-php/examples/avatars/get-q-r.md | 16 + .../databases/create-boolean-attribute.md | 16 + .../examples/databases/create-collection.md | 16 + .../databases/create-datetime-attribute.md | 16 + .../examples/databases/create-document.md | 16 + .../databases/create-email-attribute.md | 16 + .../databases/create-enum-attribute.md | 16 + .../databases/create-float-attribute.md | 16 + .../examples/databases/create-index.md | 16 + .../databases/create-integer-attribute.md | 16 + .../examples/databases/create-ip-attribute.md | 16 + .../create-relationship-attribute.md | 16 + .../databases/create-string-attribute.md | 16 + .../databases/create-url-attribute.md | 16 + .../server-php/examples/databases/create.md | 16 + .../examples/databases/delete-attribute.md | 16 + .../examples/databases/delete-collection.md | 16 + .../examples/databases/delete-document.md | 16 + .../examples/databases/delete-index.md | 16 + .../server-php/examples/databases/delete.md | 16 + .../examples/databases/get-attribute.md | 16 + .../examples/databases/get-collection.md | 16 + .../examples/databases/get-document.md | 16 + .../examples/databases/get-index.md | 16 + .../server-php/examples/databases/get.md | 16 + .../examples/databases/list-attributes.md | 16 + .../examples/databases/list-collections.md | 16 + .../examples/databases/list-documents.md | 16 + .../examples/databases/list-indexes.md | 16 + .../server-php/examples/databases/list.md | 16 + .../databases/update-boolean-attribute.md | 16 + .../examples/databases/update-collection.md | 16 + .../databases/update-datetime-attribute.md | 16 + .../examples/databases/update-document.md | 16 + .../databases/update-email-attribute.md | 16 + .../databases/update-enum-attribute.md | 16 + .../databases/update-float-attribute.md | 16 + .../databases/update-integer-attribute.md | 16 + .../examples/databases/update-ip-attribute.md | 16 + .../update-relationship-attribute.md | 16 + .../databases/update-string-attribute.md | 16 + .../databases/update-url-attribute.md | 16 + .../server-php/examples/databases/update.md | 16 + .../examples/functions/create-build.md | 16 + .../examples/functions/create-deployment.md | 17 + .../examples/functions/create-execution.md | 16 + .../examples/functions/create-variable.md | 16 + .../server-php/examples/functions/create.md | 16 + .../examples/functions/delete-deployment.md | 16 + .../examples/functions/delete-variable.md | 16 + .../server-php/examples/functions/delete.md | 16 + .../examples/functions/download-deployment.md | 16 + .../examples/functions/get-deployment.md | 16 + .../examples/functions/get-execution.md | 16 + .../examples/functions/get-variable.md | 16 + .../server-php/examples/functions/get.md | 16 + .../examples/functions/list-deployments.md | 16 + .../examples/functions/list-executions.md | 16 + .../examples/functions/list-runtimes.md | 16 + .../examples/functions/list-variables.md | 16 + .../server-php/examples/functions/list.md | 16 + .../examples/functions/update-deployment.md | 16 + .../examples/functions/update-variable.md | 16 + .../server-php/examples/functions/update.md | 16 + .../server-php/examples/graphql/mutation.md | 16 + .../server-php/examples/graphql/query.md | 16 + .../examples/health/get-antivirus.md | 16 + .../server-php/examples/health/get-cache.md | 16 + .../server-php/examples/health/get-d-b.md | 16 + .../server-php/examples/health/get-pub-sub.md | 16 + .../examples/health/get-queue-certificates.md | 16 + .../examples/health/get-queue-functions.md | 16 + .../examples/health/get-queue-logs.md | 16 + .../examples/health/get-queue-webhooks.md | 16 + .../server-php/examples/health/get-queue.md | 16 + .../examples/health/get-storage-local.md | 16 + .../server-php/examples/health/get-time.md | 16 + .../1.4.x/server-php/examples/health/get.md | 16 + .../1.4.x/server-php/examples/locale/get.md | 16 + .../server-php/examples/locale/list-codes.md | 16 + .../examples/locale/list-continents.md | 16 + .../examples/locale/list-countries-e-u.md | 16 + .../examples/locale/list-countries-phones.md | 16 + .../examples/locale/list-countries.md | 16 + .../examples/locale/list-currencies.md | 16 + .../examples/locale/list-languages.md | 16 + .../examples/storage/create-bucket.md | 16 + .../examples/storage/create-file.md | 17 + .../examples/storage/delete-bucket.md | 16 + .../examples/storage/delete-file.md | 16 + .../server-php/examples/storage/get-bucket.md | 16 + .../examples/storage/get-file-download.md | 16 + .../examples/storage/get-file-preview.md | 16 + .../examples/storage/get-file-view.md | 16 + .../server-php/examples/storage/get-file.md | 16 + .../examples/storage/list-buckets.md | 16 + .../server-php/examples/storage/list-files.md | 16 + .../examples/storage/update-bucket.md | 16 + .../examples/storage/update-file.md | 16 + .../examples/teams/create-membership.md | 16 + .../1.4.x/server-php/examples/teams/create.md | 16 + .../examples/teams/delete-membership.md | 16 + .../1.4.x/server-php/examples/teams/delete.md | 16 + .../examples/teams/get-membership.md | 16 + .../server-php/examples/teams/get-prefs.md | 16 + .../1.4.x/server-php/examples/teams/get.md | 16 + .../examples/teams/list-memberships.md | 16 + .../1.4.x/server-php/examples/teams/list.md | 16 + .../teams/update-membership-status.md | 16 + .../examples/teams/update-membership.md | 16 + .../server-php/examples/teams/update-name.md | 16 + .../server-php/examples/teams/update-prefs.md | 16 + .../examples/users/create-argon2user.md | 16 + .../examples/users/create-bcrypt-user.md | 16 + .../examples/users/create-m-d5user.md | 16 + .../examples/users/create-p-h-pass-user.md | 16 + .../examples/users/create-s-h-a-user.md | 16 + .../users/create-scrypt-modified-user.md | 16 + .../examples/users/create-scrypt-user.md | 16 + .../1.4.x/server-php/examples/users/create.md | 16 + .../examples/users/delete-identity.md | 16 + .../examples/users/delete-session.md | 16 + .../examples/users/delete-sessions.md | 16 + .../1.4.x/server-php/examples/users/delete.md | 16 + .../server-php/examples/users/get-prefs.md | 16 + .../1.4.x/server-php/examples/users/get.md | 16 + .../examples/users/list-identities.md | 16 + .../server-php/examples/users/list-logs.md | 16 + .../examples/users/list-memberships.md | 16 + .../examples/users/list-sessions.md | 16 + .../1.4.x/server-php/examples/users/list.md | 16 + .../users/update-email-verification.md | 16 + .../server-php/examples/users/update-email.md | 16 + .../examples/users/update-labels.md | 16 + .../server-php/examples/users/update-name.md | 16 + .../examples/users/update-password.md | 16 + .../users/update-phone-verification.md | 16 + .../server-php/examples/users/update-phone.md | 16 + .../server-php/examples/users/update-prefs.md | 16 + .../examples/users/update-status.md | 16 + .../account/create-phone-verification.md | 14 + .../examples/account/create-recovery.md | 14 + .../examples/account/create-verification.md | 14 + .../examples/account/delete-identity.md | 14 + .../examples/account/delete-session.md | 14 + .../examples/account/delete-sessions.md | 14 + .../examples/account/get-prefs.md | 14 + .../examples/account/get-session.md | 14 + .../server-python/examples/account/get.md | 14 + .../examples/account/list-identities.md | 14 + .../examples/account/list-logs.md | 14 + .../examples/account/list-sessions.md | 14 + .../examples/account/update-email.md | 14 + .../examples/account/update-name.md | 14 + .../examples/account/update-password.md | 14 + .../account/update-phone-verification.md | 14 + .../examples/account/update-phone.md | 14 + .../examples/account/update-prefs.md | 14 + .../examples/account/update-recovery.md | 14 + .../examples/account/update-session.md | 14 + .../examples/account/update-status.md | 14 + .../examples/account/update-verification.md | 14 + .../examples/avatars/get-browser.md | 14 + .../examples/avatars/get-credit-card.md | 14 + .../examples/avatars/get-favicon.md | 14 + .../examples/avatars/get-flag.md | 14 + .../examples/avatars/get-image.md | 14 + .../examples/avatars/get-initials.md | 14 + .../server-python/examples/avatars/get-q-r.md | 14 + .../databases/create-boolean-attribute.md | 14 + .../examples/databases/create-collection.md | 14 + .../databases/create-datetime-attribute.md | 14 + .../examples/databases/create-document.md | 14 + .../databases/create-email-attribute.md | 14 + .../databases/create-enum-attribute.md | 14 + .../databases/create-float-attribute.md | 14 + .../examples/databases/create-index.md | 14 + .../databases/create-integer-attribute.md | 14 + .../examples/databases/create-ip-attribute.md | 14 + .../create-relationship-attribute.md | 14 + .../databases/create-string-attribute.md | 14 + .../databases/create-url-attribute.md | 14 + .../examples/databases/create.md | 14 + .../examples/databases/delete-attribute.md | 14 + .../examples/databases/delete-collection.md | 14 + .../examples/databases/delete-document.md | 14 + .../examples/databases/delete-index.md | 14 + .../examples/databases/delete.md | 14 + .../examples/databases/get-attribute.md | 14 + .../examples/databases/get-collection.md | 14 + .../examples/databases/get-document.md | 14 + .../examples/databases/get-index.md | 14 + .../server-python/examples/databases/get.md | 14 + .../examples/databases/list-attributes.md | 14 + .../examples/databases/list-collections.md | 14 + .../examples/databases/list-documents.md | 14 + .../examples/databases/list-indexes.md | 14 + .../server-python/examples/databases/list.md | 14 + .../databases/update-boolean-attribute.md | 14 + .../examples/databases/update-collection.md | 14 + .../databases/update-datetime-attribute.md | 14 + .../examples/databases/update-document.md | 14 + .../databases/update-email-attribute.md | 14 + .../databases/update-enum-attribute.md | 14 + .../databases/update-float-attribute.md | 14 + .../databases/update-integer-attribute.md | 14 + .../examples/databases/update-ip-attribute.md | 14 + .../update-relationship-attribute.md | 14 + .../databases/update-string-attribute.md | 14 + .../databases/update-url-attribute.md | 14 + .../examples/databases/update.md | 14 + .../examples/functions/create-build.md | 14 + .../examples/functions/create-deployment.md | 15 + .../examples/functions/create-execution.md | 14 + .../examples/functions/create-variable.md | 14 + .../examples/functions/create.md | 14 + .../examples/functions/delete-deployment.md | 14 + .../examples/functions/delete-variable.md | 14 + .../examples/functions/delete.md | 14 + .../examples/functions/download-deployment.md | 14 + .../examples/functions/get-deployment.md | 14 + .../examples/functions/get-execution.md | 14 + .../examples/functions/get-variable.md | 14 + .../server-python/examples/functions/get.md | 14 + .../examples/functions/list-deployments.md | 14 + .../examples/functions/list-executions.md | 14 + .../examples/functions/list-runtimes.md | 14 + .../examples/functions/list-variables.md | 14 + .../server-python/examples/functions/list.md | 14 + .../examples/functions/update-deployment.md | 14 + .../examples/functions/update-variable.md | 14 + .../examples/functions/update.md | 14 + .../examples/graphql/mutation.md | 14 + .../server-python/examples/graphql/query.md | 14 + .../examples/health/get-antivirus.md | 14 + .../examples/health/get-cache.md | 14 + .../server-python/examples/health/get-d-b.md | 14 + .../examples/health/get-pub-sub.md | 14 + .../examples/health/get-queue-certificates.md | 14 + .../examples/health/get-queue-functions.md | 14 + .../examples/health/get-queue-logs.md | 14 + .../examples/health/get-queue-webhooks.md | 14 + .../examples/health/get-queue.md | 14 + .../examples/health/get-storage-local.md | 14 + .../server-python/examples/health/get-time.md | 14 + .../server-python/examples/health/get.md | 14 + .../server-python/examples/locale/get.md | 14 + .../examples/locale/list-codes.md | 14 + .../examples/locale/list-continents.md | 14 + .../examples/locale/list-countries-e-u.md | 14 + .../examples/locale/list-countries-phones.md | 14 + .../examples/locale/list-countries.md | 14 + .../examples/locale/list-currencies.md | 14 + .../examples/locale/list-languages.md | 14 + .../examples/storage/create-bucket.md | 14 + .../examples/storage/create-file.md | 15 + .../examples/storage/delete-bucket.md | 14 + .../examples/storage/delete-file.md | 14 + .../examples/storage/get-bucket.md | 14 + .../examples/storage/get-file-download.md | 14 + .../examples/storage/get-file-preview.md | 14 + .../examples/storage/get-file-view.md | 14 + .../examples/storage/get-file.md | 14 + .../examples/storage/list-buckets.md | 14 + .../examples/storage/list-files.md | 14 + .../examples/storage/update-bucket.md | 14 + .../examples/storage/update-file.md | 14 + .../examples/teams/create-membership.md | 14 + .../server-python/examples/teams/create.md | 14 + .../examples/teams/delete-membership.md | 14 + .../server-python/examples/teams/delete.md | 14 + .../examples/teams/get-membership.md | 14 + .../server-python/examples/teams/get-prefs.md | 14 + .../1.4.x/server-python/examples/teams/get.md | 14 + .../examples/teams/list-memberships.md | 14 + .../server-python/examples/teams/list.md | 14 + .../teams/update-membership-status.md | 14 + .../examples/teams/update-membership.md | 14 + .../examples/teams/update-name.md | 14 + .../examples/teams/update-prefs.md | 14 + .../examples/users/create-argon2user.md | 14 + .../examples/users/create-bcrypt-user.md | 14 + .../examples/users/create-m-d5user.md | 14 + .../examples/users/create-p-h-pass-user.md | 14 + .../examples/users/create-s-h-a-user.md | 14 + .../users/create-scrypt-modified-user.md | 14 + .../examples/users/create-scrypt-user.md | 14 + .../server-python/examples/users/create.md | 14 + .../examples/users/delete-identity.md | 14 + .../examples/users/delete-session.md | 14 + .../examples/users/delete-sessions.md | 14 + .../server-python/examples/users/delete.md | 14 + .../server-python/examples/users/get-prefs.md | 14 + .../1.4.x/server-python/examples/users/get.md | 14 + .../examples/users/list-identities.md | 14 + .../server-python/examples/users/list-logs.md | 14 + .../examples/users/list-memberships.md | 14 + .../examples/users/list-sessions.md | 14 + .../server-python/examples/users/list.md | 14 + .../users/update-email-verification.md | 14 + .../examples/users/update-email.md | 14 + .../examples/users/update-labels.md | 14 + .../examples/users/update-name.md | 14 + .../examples/users/update-password.md | 14 + .../users/update-phone-verification.md | 14 + .../examples/users/update-phone.md | 14 + .../examples/users/update-prefs.md | 14 + .../examples/users/update-status.md | 14 + .../account/create-phone-verification.md | 7 + .../examples/account/create-recovery.md | 11 + .../examples/account/create-verification.md | 10 + .../examples/account/delete-identity.md | 7 + .../examples/account/delete-session.md | 7 + .../examples/account/delete-sessions.md | 7 + .../server-rest/examples/account/get-prefs.md | 7 + .../examples/account/get-session.md | 7 + .../1.4.x/server-rest/examples/account/get.md | 7 + .../examples/account/list-identities.md | 7 + .../server-rest/examples/account/list-logs.md | 7 + .../examples/account/list-sessions.md | 7 + .../examples/account/update-email.md | 11 + .../examples/account/update-name.md | 10 + .../examples/account/update-password.md | 11 + .../account/update-phone-verification.md | 11 + .../examples/account/update-phone.md | 11 + .../examples/account/update-prefs.md | 10 + .../examples/account/update-recovery.md | 13 + .../examples/account/update-session.md | 7 + .../examples/account/update-status.md | 7 + .../examples/account/update-verification.md | 11 + .../examples/avatars/get-browser.md | 8 + .../examples/avatars/get-credit-card.md | 8 + .../examples/avatars/get-favicon.md | 8 + .../server-rest/examples/avatars/get-flag.md | 8 + .../server-rest/examples/avatars/get-image.md | 8 + .../examples/avatars/get-initials.md | 8 + .../server-rest/examples/avatars/get-q-r.md | 8 + .../databases/create-boolean-attribute.md | 13 + .../examples/databases/create-collection.md | 14 + .../databases/create-datetime-attribute.md | 13 + .../examples/databases/create-document.md | 13 + .../databases/create-email-attribute.md | 13 + .../databases/create-enum-attribute.md | 14 + .../databases/create-float-attribute.md | 15 + .../examples/databases/create-index.md | 13 + .../databases/create-integer-attribute.md | 15 + .../examples/databases/create-ip-attribute.md | 13 + .../create-relationship-attribute.md | 15 + .../databases/create-string-attribute.md | 15 + .../databases/create-url-attribute.md | 13 + .../server-rest/examples/databases/create.md | 12 + .../examples/databases/delete-attribute.md | 7 + .../examples/databases/delete-collection.md | 7 + .../examples/databases/delete-document.md | 8 + .../examples/databases/delete-index.md | 7 + .../server-rest/examples/databases/delete.md | 7 + .../examples/databases/get-attribute.md | 7 + .../examples/databases/get-collection.md | 7 + .../examples/databases/get-document.md | 8 + .../examples/databases/get-index.md | 7 + .../server-rest/examples/databases/get.md | 7 + .../examples/databases/list-attributes.md | 7 + .../examples/databases/list-collections.md | 7 + .../examples/databases/list-documents.md | 8 + .../examples/databases/list-indexes.md | 7 + .../server-rest/examples/databases/list.md | 7 + .../databases/update-boolean-attribute.md | 11 + .../examples/databases/update-collection.md | 13 + .../databases/update-datetime-attribute.md | 11 + .../examples/databases/update-document.md | 12 + .../databases/update-email-attribute.md | 11 + .../databases/update-enum-attribute.md | 12 + .../databases/update-float-attribute.md | 13 + .../databases/update-integer-attribute.md | 13 + .../examples/databases/update-ip-attribute.md | 11 + .../update-relationship-attribute.md | 10 + .../databases/update-string-attribute.md | 11 + .../databases/update-url-attribute.md | 11 + .../server-rest/examples/databases/update.md | 11 + .../examples/functions/create-build.md | 7 + .../examples/functions/create-deployment.md | 30 + .../examples/functions/create-execution.md | 15 + .../examples/functions/create-variable.md | 11 + .../server-rest/examples/functions/create.md | 29 + .../examples/functions/delete-deployment.md | 7 + .../examples/functions/delete-variable.md | 7 + .../server-rest/examples/functions/delete.md | 7 + .../examples/functions/download-deployment.md | 7 + .../examples/functions/get-deployment.md | 7 + .../examples/functions/get-execution.md | 8 + .../examples/functions/get-variable.md | 7 + .../server-rest/examples/functions/get.md | 7 + .../examples/functions/list-deployments.md | 7 + .../examples/functions/list-executions.md | 8 + .../examples/functions/list-runtimes.md | 7 + .../examples/functions/list-variables.md | 7 + .../server-rest/examples/functions/list.md | 7 + .../examples/functions/update-deployment.md | 7 + .../examples/functions/update-variable.md | 11 + .../server-rest/examples/functions/update.md | 24 + .../server-rest/examples/graphql/mutation.md | 12 + .../server-rest/examples/graphql/query.md | 12 + .../examples/health/get-antivirus.md | 7 + .../server-rest/examples/health/get-cache.md | 7 + .../server-rest/examples/health/get-d-b.md | 7 + .../examples/health/get-pub-sub.md | 7 + .../examples/health/get-queue-certificates.md | 7 + .../examples/health/get-queue-functions.md | 7 + .../examples/health/get-queue-logs.md | 7 + .../examples/health/get-queue-webhooks.md | 7 + .../server-rest/examples/health/get-queue.md | 7 + .../examples/health/get-storage-local.md | 7 + .../server-rest/examples/health/get-time.md | 7 + .../1.4.x/server-rest/examples/health/get.md | 7 + .../1.4.x/server-rest/examples/locale/get.md | 8 + .../server-rest/examples/locale/list-codes.md | 8 + .../examples/locale/list-continents.md | 8 + .../examples/locale/list-countries-e-u.md | 8 + .../examples/locale/list-countries-phones.md | 8 + .../examples/locale/list-countries.md | 8 + .../examples/locale/list-currencies.md | 8 + .../examples/locale/list-languages.md | 8 + .../examples/storage/create-bucket.md | 19 + .../examples/storage/create-file.md | 26 + .../examples/storage/delete-bucket.md | 7 + .../examples/storage/delete-file.md | 8 + .../examples/storage/get-bucket.md | 7 + .../examples/storage/get-file-download.md | 8 + .../examples/storage/get-file-preview.md | 8 + .../examples/storage/get-file-view.md | 8 + .../server-rest/examples/storage/get-file.md | 8 + .../examples/storage/list-buckets.md | 7 + .../examples/storage/list-files.md | 8 + .../examples/storage/update-bucket.md | 18 + .../examples/storage/update-file.md | 12 + .../examples/teams/create-membership.md | 16 + .../server-rest/examples/teams/create.md | 13 + .../examples/teams/delete-membership.md | 8 + .../server-rest/examples/teams/delete.md | 8 + .../examples/teams/get-membership.md | 8 + .../server-rest/examples/teams/get-prefs.md | 7 + .../1.4.x/server-rest/examples/teams/get.md | 8 + .../examples/teams/list-memberships.md | 8 + .../1.4.x/server-rest/examples/teams/list.md | 8 + .../teams/update-membership-status.md | 11 + .../examples/teams/update-membership.md | 11 + .../server-rest/examples/teams/update-name.md | 11 + .../examples/teams/update-prefs.md | 10 + .../examples/users/create-argon2user.md | 13 + .../examples/users/create-bcrypt-user.md | 13 + .../examples/users/create-m-d5user.md | 13 + .../examples/users/create-p-h-pass-user.md | 13 + .../examples/users/create-s-h-a-user.md | 14 + .../users/create-scrypt-modified-user.md | 16 + .../examples/users/create-scrypt-user.md | 18 + .../server-rest/examples/users/create.md | 14 + .../examples/users/delete-identity.md | 7 + .../examples/users/delete-session.md | 7 + .../examples/users/delete-sessions.md | 7 + .../server-rest/examples/users/delete.md | 7 + .../server-rest/examples/users/get-prefs.md | 7 + .../1.4.x/server-rest/examples/users/get.md | 7 + .../examples/users/list-identities.md | 7 + .../server-rest/examples/users/list-logs.md | 7 + .../examples/users/list-memberships.md | 7 + .../examples/users/list-sessions.md | 7 + .../1.4.x/server-rest/examples/users/list.md | 7 + .../users/update-email-verification.md | 10 + .../examples/users/update-email.md | 10 + .../examples/users/update-labels.md | 10 + .../server-rest/examples/users/update-name.md | 10 + .../examples/users/update-password.md | 10 + .../users/update-phone-verification.md | 10 + .../examples/users/update-phone.md | 10 + .../examples/users/update-prefs.md | 10 + .../examples/users/update-status.md | 10 + .../account/create-phone-verification.md | 14 + .../examples/account/create-recovery.md | 14 + .../examples/account/create-verification.md | 14 + .../examples/account/delete-identity.md | 14 + .../examples/account/delete-session.md | 14 + .../examples/account/delete-sessions.md | 14 + .../server-ruby/examples/account/get-prefs.md | 14 + .../examples/account/get-session.md | 14 + .../1.4.x/server-ruby/examples/account/get.md | 14 + .../examples/account/list-identities.md | 14 + .../server-ruby/examples/account/list-logs.md | 14 + .../examples/account/list-sessions.md | 14 + .../examples/account/update-email.md | 14 + .../examples/account/update-name.md | 14 + .../examples/account/update-password.md | 14 + .../account/update-phone-verification.md | 14 + .../examples/account/update-phone.md | 14 + .../examples/account/update-prefs.md | 14 + .../examples/account/update-recovery.md | 14 + .../examples/account/update-session.md | 14 + .../examples/account/update-status.md | 14 + .../examples/account/update-verification.md | 14 + .../examples/avatars/get-browser.md | 14 + .../examples/avatars/get-credit-card.md | 14 + .../examples/avatars/get-favicon.md | 14 + .../server-ruby/examples/avatars/get-flag.md | 14 + .../server-ruby/examples/avatars/get-image.md | 14 + .../examples/avatars/get-initials.md | 14 + .../server-ruby/examples/avatars/get-q-r.md | 14 + .../databases/create-boolean-attribute.md | 14 + .../examples/databases/create-collection.md | 14 + .../databases/create-datetime-attribute.md | 14 + .../examples/databases/create-document.md | 14 + .../databases/create-email-attribute.md | 14 + .../databases/create-enum-attribute.md | 14 + .../databases/create-float-attribute.md | 14 + .../examples/databases/create-index.md | 14 + .../databases/create-integer-attribute.md | 14 + .../examples/databases/create-ip-attribute.md | 14 + .../create-relationship-attribute.md | 14 + .../databases/create-string-attribute.md | 14 + .../databases/create-url-attribute.md | 14 + .../server-ruby/examples/databases/create.md | 14 + .../examples/databases/delete-attribute.md | 14 + .../examples/databases/delete-collection.md | 14 + .../examples/databases/delete-document.md | 14 + .../examples/databases/delete-index.md | 14 + .../server-ruby/examples/databases/delete.md | 14 + .../examples/databases/get-attribute.md | 14 + .../examples/databases/get-collection.md | 14 + .../examples/databases/get-document.md | 14 + .../examples/databases/get-index.md | 14 + .../server-ruby/examples/databases/get.md | 14 + .../examples/databases/list-attributes.md | 14 + .../examples/databases/list-collections.md | 14 + .../examples/databases/list-documents.md | 14 + .../examples/databases/list-indexes.md | 14 + .../server-ruby/examples/databases/list.md | 14 + .../databases/update-boolean-attribute.md | 14 + .../examples/databases/update-collection.md | 14 + .../databases/update-datetime-attribute.md | 14 + .../examples/databases/update-document.md | 14 + .../databases/update-email-attribute.md | 14 + .../databases/update-enum-attribute.md | 14 + .../databases/update-float-attribute.md | 14 + .../databases/update-integer-attribute.md | 14 + .../examples/databases/update-ip-attribute.md | 14 + .../update-relationship-attribute.md | 14 + .../databases/update-string-attribute.md | 14 + .../databases/update-url-attribute.md | 14 + .../server-ruby/examples/databases/update.md | 14 + .../examples/functions/create-build.md | 14 + .../examples/functions/create-deployment.md | 14 + .../examples/functions/create-execution.md | 14 + .../examples/functions/create-variable.md | 14 + .../server-ruby/examples/functions/create.md | 14 + .../examples/functions/delete-deployment.md | 14 + .../examples/functions/delete-variable.md | 14 + .../server-ruby/examples/functions/delete.md | 14 + .../examples/functions/download-deployment.md | 14 + .../examples/functions/get-deployment.md | 14 + .../examples/functions/get-execution.md | 14 + .../examples/functions/get-variable.md | 14 + .../server-ruby/examples/functions/get.md | 14 + .../examples/functions/list-deployments.md | 14 + .../examples/functions/list-executions.md | 14 + .../examples/functions/list-runtimes.md | 14 + .../examples/functions/list-variables.md | 14 + .../server-ruby/examples/functions/list.md | 14 + .../examples/functions/update-deployment.md | 14 + .../examples/functions/update-variable.md | 14 + .../server-ruby/examples/functions/update.md | 14 + .../server-ruby/examples/graphql/mutation.md | 14 + .../server-ruby/examples/graphql/query.md | 14 + .../examples/health/get-antivirus.md | 14 + .../server-ruby/examples/health/get-cache.md | 14 + .../server-ruby/examples/health/get-d-b.md | 14 + .../examples/health/get-pub-sub.md | 14 + .../examples/health/get-queue-certificates.md | 14 + .../examples/health/get-queue-functions.md | 14 + .../examples/health/get-queue-logs.md | 14 + .../examples/health/get-queue-webhooks.md | 14 + .../server-ruby/examples/health/get-queue.md | 14 + .../examples/health/get-storage-local.md | 14 + .../server-ruby/examples/health/get-time.md | 14 + .../1.4.x/server-ruby/examples/health/get.md | 14 + .../1.4.x/server-ruby/examples/locale/get.md | 14 + .../server-ruby/examples/locale/list-codes.md | 14 + .../examples/locale/list-continents.md | 14 + .../examples/locale/list-countries-e-u.md | 14 + .../examples/locale/list-countries-phones.md | 14 + .../examples/locale/list-countries.md | 14 + .../examples/locale/list-currencies.md | 14 + .../examples/locale/list-languages.md | 14 + .../examples/storage/create-bucket.md | 14 + .../examples/storage/create-file.md | 14 + .../examples/storage/delete-bucket.md | 14 + .../examples/storage/delete-file.md | 14 + .../examples/storage/get-bucket.md | 14 + .../examples/storage/get-file-download.md | 14 + .../examples/storage/get-file-preview.md | 14 + .../examples/storage/get-file-view.md | 14 + .../server-ruby/examples/storage/get-file.md | 14 + .../examples/storage/list-buckets.md | 14 + .../examples/storage/list-files.md | 14 + .../examples/storage/update-bucket.md | 14 + .../examples/storage/update-file.md | 14 + .../examples/teams/create-membership.md | 14 + .../server-ruby/examples/teams/create.md | 14 + .../examples/teams/delete-membership.md | 14 + .../server-ruby/examples/teams/delete.md | 14 + .../examples/teams/get-membership.md | 14 + .../server-ruby/examples/teams/get-prefs.md | 14 + .../1.4.x/server-ruby/examples/teams/get.md | 14 + .../examples/teams/list-memberships.md | 14 + .../1.4.x/server-ruby/examples/teams/list.md | 14 + .../teams/update-membership-status.md | 14 + .../examples/teams/update-membership.md | 14 + .../server-ruby/examples/teams/update-name.md | 14 + .../examples/teams/update-prefs.md | 14 + .../examples/users/create-argon2user.md | 14 + .../examples/users/create-bcrypt-user.md | 14 + .../examples/users/create-m-d5user.md | 14 + .../examples/users/create-p-h-pass-user.md | 14 + .../examples/users/create-s-h-a-user.md | 14 + .../users/create-scrypt-modified-user.md | 14 + .../examples/users/create-scrypt-user.md | 14 + .../server-ruby/examples/users/create.md | 14 + .../examples/users/delete-identity.md | 14 + .../examples/users/delete-session.md | 14 + .../examples/users/delete-sessions.md | 14 + .../server-ruby/examples/users/delete.md | 14 + .../server-ruby/examples/users/get-prefs.md | 14 + .../1.4.x/server-ruby/examples/users/get.md | 14 + .../examples/users/list-identities.md | 14 + .../server-ruby/examples/users/list-logs.md | 14 + .../examples/users/list-memberships.md | 14 + .../examples/users/list-sessions.md | 14 + .../1.4.x/server-ruby/examples/users/list.md | 14 + .../users/update-email-verification.md | 14 + .../examples/users/update-email.md | 14 + .../examples/users/update-labels.md | 14 + .../server-ruby/examples/users/update-name.md | 14 + .../examples/users/update-password.md | 14 + .../users/update-phone-verification.md | 14 + .../examples/users/update-phone.md | 14 + .../examples/users/update-prefs.md | 14 + .../examples/users/update-status.md | 14 + .../account/create-phone-verification.md | 11 + .../examples/account/create-recovery.md | 14 + .../examples/account/create-verification.md | 13 + .../examples/account/delete-identity.md | 13 + .../examples/account/delete-session.md | 13 + .../examples/account/delete-sessions.md | 11 + .../examples/account/get-prefs.md | 11 + .../examples/account/get-session.md | 13 + .../server-swift/examples/account/get.md | 11 + .../examples/account/list-identities.md | 11 + .../examples/account/list-logs.md | 11 + .../examples/account/list-sessions.md | 11 + .../examples/account/update-email.md | 14 + .../examples/account/update-name.md | 13 + .../examples/account/update-password.md | 13 + .../account/update-phone-verification.md | 14 + .../examples/account/update-phone.md | 14 + .../examples/account/update-prefs.md | 13 + .../examples/account/update-recovery.md | 16 + .../examples/account/update-session.md | 13 + .../examples/account/update-status.md | 11 + .../examples/account/update-verification.md | 14 + .../examples/avatars/get-browser.md | 13 + .../examples/avatars/get-credit-card.md | 13 + .../examples/avatars/get-favicon.md | 13 + .../server-swift/examples/avatars/get-flag.md | 13 + .../examples/avatars/get-image.md | 13 + .../examples/avatars/get-initials.md | 11 + .../server-swift/examples/avatars/get-q-r.md | 13 + .../databases/create-boolean-attribute.md | 16 + .../examples/databases/create-collection.md | 15 + .../databases/create-datetime-attribute.md | 16 + .../examples/databases/create-document.md | 16 + .../databases/create-email-attribute.md | 16 + .../databases/create-enum-attribute.md | 17 + .../databases/create-float-attribute.md | 16 + .../examples/databases/create-index.md | 17 + .../databases/create-integer-attribute.md | 16 + .../examples/databases/create-ip-attribute.md | 16 + .../create-relationship-attribute.md | 16 + .../databases/create-string-attribute.md | 17 + .../databases/create-url-attribute.md | 16 + .../server-swift/examples/databases/create.md | 14 + .../examples/databases/delete-attribute.md | 15 + .../examples/databases/delete-collection.md | 14 + .../examples/databases/delete-document.md | 15 + .../examples/databases/delete-index.md | 15 + .../server-swift/examples/databases/delete.md | 13 + .../examples/databases/get-attribute.md | 15 + .../examples/databases/get-collection.md | 14 + .../examples/databases/get-document.md | 15 + .../examples/databases/get-index.md | 15 + .../server-swift/examples/databases/get.md | 13 + .../examples/databases/list-attributes.md | 14 + .../examples/databases/list-collections.md | 13 + .../examples/databases/list-documents.md | 14 + .../examples/databases/list-indexes.md | 14 + .../server-swift/examples/databases/list.md | 11 + .../databases/update-boolean-attribute.md | 17 + .../examples/databases/update-collection.md | 15 + .../databases/update-datetime-attribute.md | 17 + .../examples/databases/update-document.md | 15 + .../databases/update-email-attribute.md | 17 + .../databases/update-enum-attribute.md | 18 + .../databases/update-float-attribute.md | 19 + .../databases/update-integer-attribute.md | 19 + .../examples/databases/update-ip-attribute.md | 17 + .../update-relationship-attribute.md | 15 + .../databases/update-string-attribute.md | 17 + .../databases/update-url-attribute.md | 17 + .../server-swift/examples/databases/update.md | 14 + .../examples/functions/create-build.md | 15 + .../examples/functions/create-deployment.md | 15 + .../examples/functions/create-execution.md | 13 + .../examples/functions/create-variable.md | 15 + .../server-swift/examples/functions/create.md | 15 + .../examples/functions/delete-deployment.md | 14 + .../examples/functions/delete-variable.md | 14 + .../server-swift/examples/functions/delete.md | 13 + .../examples/functions/download-deployment.md | 14 + .../examples/functions/get-deployment.md | 14 + .../examples/functions/get-execution.md | 14 + .../examples/functions/get-variable.md | 14 + .../server-swift/examples/functions/get.md | 13 + .../examples/functions/list-deployments.md | 13 + .../examples/functions/list-executions.md | 13 + .../examples/functions/list-runtimes.md | 11 + .../examples/functions/list-variables.md | 13 + .../server-swift/examples/functions/list.md | 11 + .../examples/functions/update-deployment.md | 14 + .../examples/functions/update-variable.md | 15 + .../server-swift/examples/functions/update.md | 15 + .../server-swift/examples/graphql/mutation.md | 13 + .../server-swift/examples/graphql/query.md | 13 + .../examples/health/get-antivirus.md | 11 + .../server-swift/examples/health/get-cache.md | 11 + .../server-swift/examples/health/get-d-b.md | 11 + .../examples/health/get-pub-sub.md | 11 + .../examples/health/get-queue-certificates.md | 11 + .../examples/health/get-queue-functions.md | 11 + .../examples/health/get-queue-logs.md | 11 + .../examples/health/get-queue-webhooks.md | 11 + .../server-swift/examples/health/get-queue.md | 11 + .../examples/health/get-storage-local.md | 11 + .../server-swift/examples/health/get-time.md | 11 + .../1.4.x/server-swift/examples/health/get.md | 11 + .../1.4.x/server-swift/examples/locale/get.md | 11 + .../examples/locale/list-codes.md | 11 + .../examples/locale/list-continents.md | 11 + .../examples/locale/list-countries-e-u.md | 11 + .../examples/locale/list-countries-phones.md | 11 + .../examples/locale/list-countries.md | 11 + .../examples/locale/list-currencies.md | 11 + .../examples/locale/list-languages.md | 11 + .../examples/storage/create-bucket.md | 14 + .../examples/storage/create-file.md | 15 + .../examples/storage/delete-bucket.md | 13 + .../examples/storage/delete-file.md | 14 + .../examples/storage/get-bucket.md | 13 + .../examples/storage/get-file-download.md | 14 + .../examples/storage/get-file-preview.md | 14 + .../examples/storage/get-file-view.md | 14 + .../server-swift/examples/storage/get-file.md | 14 + .../examples/storage/list-buckets.md | 11 + .../examples/storage/list-files.md | 13 + .../examples/storage/update-bucket.md | 14 + .../examples/storage/update-file.md | 14 + .../examples/teams/create-membership.md | 15 + .../server-swift/examples/teams/create.md | 14 + .../examples/teams/delete-membership.md | 14 + .../server-swift/examples/teams/delete.md | 13 + .../examples/teams/get-membership.md | 14 + .../server-swift/examples/teams/get-prefs.md | 13 + .../1.4.x/server-swift/examples/teams/get.md | 13 + .../examples/teams/list-memberships.md | 13 + .../1.4.x/server-swift/examples/teams/list.md | 11 + .../teams/update-membership-status.md | 16 + .../examples/teams/update-membership.md | 15 + .../examples/teams/update-name.md | 14 + .../examples/teams/update-prefs.md | 14 + .../examples/users/create-argon2user.md | 15 + .../examples/users/create-bcrypt-user.md | 15 + .../examples/users/create-m-d5user.md | 15 + .../examples/users/create-p-h-pass-user.md | 15 + .../examples/users/create-s-h-a-user.md | 15 + .../users/create-scrypt-modified-user.md | 18 + .../examples/users/create-scrypt-user.md | 20 + .../server-swift/examples/users/create.md | 13 + .../examples/users/delete-identity.md | 13 + .../examples/users/delete-session.md | 14 + .../examples/users/delete-sessions.md | 13 + .../server-swift/examples/users/delete.md | 13 + .../server-swift/examples/users/get-prefs.md | 13 + .../1.4.x/server-swift/examples/users/get.md | 13 + .../examples/users/list-identities.md | 11 + .../server-swift/examples/users/list-logs.md | 13 + .../examples/users/list-memberships.md | 13 + .../examples/users/list-sessions.md | 13 + .../1.4.x/server-swift/examples/users/list.md | 11 + .../users/update-email-verification.md | 14 + .../examples/users/update-email.md | 14 + .../examples/users/update-labels.md | 14 + .../examples/users/update-name.md | 14 + .../examples/users/update-password.md | 14 + .../users/update-phone-verification.md | 14 + .../examples/users/update-phone.md | 14 + .../examples/users/update-prefs.md | 14 + .../examples/users/update-status.md | 14 + docs/references/account/delete-identity.md | 1 + docs/references/account/get-prefs.md | 2 +- docs/references/account/get.md | 2 +- docs/references/account/list-identities.md | 1 + docs/references/account/list-logs.md | 2 +- docs/references/account/list-sessions.md | 2 +- docs/references/functions/create-build.md | 1 + .../references/functions/create-deployment.md | 2 +- docs/references/functions/create-variable.md | 2 +- docs/references/project/create-variable.md | 1 + docs/references/project/delete-variable.md | 1 + docs/references/project/get-variable.md | 1 + docs/references/project/list-variables.md | 1 + docs/references/project/update-variable.md | 1 + docs/references/proxy/create-rule.md | 1 + docs/references/proxy/delete-rule.md | 1 + docs/references/proxy/get-rule.md | 1 + docs/references/proxy/list-rules.md | 1 + ...hip-roles.md => update-team-membership.md} | 2 +- docs/references/users/delete-identity.md | 1 + docs/references/users/list-identities.md | 1 + docs/sdks/dart/CHANGELOG.md | 15 + docs/sdks/flutter/CHANGELOG.md | 14 + docs/services/proxy.md | 3 + docs/services/vcs.md | 3 + docs/tutorials/add-oauth2-provider.md | 2 +- phpcs.xml | 2 + src/Appwrite/Auth/OAuth2.php | 2 +- src/Appwrite/Auth/OAuth2/Exception.php | 12 +- src/Appwrite/Auth/OAuth2/Firebase.php | 389 ++++ src/Appwrite/Auth/OAuth2/Github.php | 11 + src/Appwrite/Detector/Detector.php | 10 +- src/Appwrite/Event/Build.php | 17 +- src/Appwrite/Event/Delete.php | 3 +- src/Appwrite/Event/Event.php | 3 + src/Appwrite/Event/Func.php | 57 +- src/Appwrite/Event/Mail.php | 97 +- src/Appwrite/Event/Migration.php | 98 + src/Appwrite/Extend/Exception.php | 34 +- src/Appwrite/GraphQL/Resolvers.php | 2 +- src/Appwrite/GraphQL/Types/Mapper.php | 2 + src/Appwrite/Messaging/Adapter/Realtime.php | 10 + src/Appwrite/Migration/Migration.php | 84 +- src/Appwrite/Migration/Version/V17.php | 12 + src/Appwrite/Migration/Version/V19.php | 727 ++++++- src/Appwrite/Platform/Services/Tasks.php | 3 + src/Appwrite/Platform/Tasks/Install.php | 86 +- src/Appwrite/Platform/Tasks/Maintenance.php | 3 - src/Appwrite/Platform/Tasks/Migrate.php | 34 +- src/Appwrite/Platform/Tasks/SDKs.php | 4 +- src/Appwrite/Platform/Tasks/Specs.php | 2 - src/Appwrite/Platform/Tasks/Upgrade.php | 42 + src/Appwrite/Platform/Tasks/Usage.php | 60 + src/Appwrite/Resque/Worker.php | 108 +- .../Specification/Format/OpenAPI3.php | 3 + .../Specification/Format/Swagger2.php | 3 + src/Appwrite/Usage/Calculator.php | 15 + src/Appwrite/Usage/Calculators/TimeSeries.php | 557 +++++ src/Appwrite/Usage/Stats.php | 225 ++ .../Validator/Queries/Deployments.php | 3 +- .../Database/Validator/Queries/Executions.php | 2 +- .../Database/Validator/Queries/Functions.php | 5 +- .../Database/Validator/Queries/Identities.php | 23 + .../Validator/Queries/Installations.php | 20 + .../Database/Validator/Queries/Migrations.php | 25 + .../Database/Validator/Queries/Rules.php | 22 + .../Database/Validator/Queries/Variables.php | 4 +- src/Appwrite/Utopia/Request/Filters/V16.php | 48 + src/Appwrite/Utopia/Response.php | 85 +- src/Appwrite/Utopia/Response/Filters/V16.php | 109 + .../Utopia/Response/Model/BaseList.php | 2 +- src/Appwrite/Utopia/Response/Model/Branch.php | 40 + src/Appwrite/Utopia/Response/Model/Build.php | 6 + .../Utopia/Response/Model/Collection.php | 2 +- .../Response/Model/ConsoleVariables.php | 18 + .../Utopia/Response/Model/Database.php | 2 +- .../Utopia/Response/Model/Deployment.php | 89 +- .../Utopia/Response/Model/Detection.php | 40 + src/Appwrite/Utopia/Response/Model/Domain.php | 88 - .../Utopia/Response/Model/Execution.php | 54 +- src/Appwrite/Utopia/Response/Model/Func.php | 62 +- .../Utopia/Response/Model/Headers.php | 46 + .../Utopia/Response/Model/Identity.php | 95 + .../Utopia/Response/Model/Installation.php | 72 + .../Utopia/Response/Model/Migration.php | 96 + .../Model/MigrationFirebaseProject.php | 46 + .../Utopia/Response/Model/MigrationReport.php | 89 + .../Utopia/Response/Model/Project.php | 25 +- .../Response/Model/ProviderRepository.php | 78 + src/Appwrite/Utopia/Response/Model/Rule.php | 92 + .../Utopia/Response/Model/UsageBuckets.php | 30 +- .../Utopia/Response/Model/UsageCollection.php | 30 +- .../Utopia/Response/Model/UsageDatabase.php | 62 +- .../Utopia/Response/Model/UsageDatabases.php | 92 +- .../Utopia/Response/Model/UsageFunction.php | 50 +- .../Utopia/Response/Model/UsageFunctions.php | 47 +- .../Utopia/Response/Model/UsageProject.php | 14 +- .../Utopia/Response/Model/UsageStorage.php | 66 +- .../Utopia/Response/Model/UsageUsers.php | 47 +- .../Utopia/Response/Model/Variable.php | 12 +- src/Appwrite/Vcs/Comment.php | 126 ++ src/Executor/Executor.php | 112 +- tests/e2e/General/UsageTest.php | 1517 +++++++------- tests/e2e/Scopes/ProjectCustom.php | 15 + tests/e2e/Services/Account/AccountBase.php | 2 +- .../Account/AccountConsoleClientTest.php | 81 - .../Account/AccountCustomClientTest.php | 27 +- tests/e2e/Services/Avatars/AvatarsBase.php | 28 +- .../Console/ConsoleConsoleClientTest.php | 7 +- .../e2e/Services/Databases/DatabasesBase.php | 127 +- .../Databases/DatabasesConsoleClientTest.php | 77 +- .../Databases/DatabasesCustomClientTest.php | 416 ++++ .../Databases/DatabasesCustomServerTest.php | 104 + .../DatabasesPermissionsTeamTest.php | 2 +- .../Functions/FunctionsConsoleClientTest.php | 23 +- .../Functions/FunctionsCustomClientTest.php | 164 +- .../Functions/FunctionsCustomServerTest.php | 778 ++----- tests/e2e/Services/GraphQL/Base.php | 47 +- .../Services/GraphQL/FunctionsClientTest.php | 42 +- .../Services/GraphQL/FunctionsServerTest.php | 91 +- .../e2e/Services/GraphQL/TeamsServerTest.php | 4 +- .../Projects/ProjectsConsoleClientTest.php | 270 +-- .../Realtime/RealtimeConsoleClientTest.php | 2 +- .../Realtime/RealtimeCustomClientTest.php | 20 +- tests/e2e/Services/Storage/StorageBase.php | 53 +- .../Storage/StorageConsoleClientTest.php | 15 +- .../Services/Users/UsersConsoleClientTest.php | 43 +- .../Webhooks/WebhooksCustomServerTest.php | 10 +- tests/resources/docker/docker-compose.yml | 1 + tests/resources/functions/dart/main.dart | 40 +- tests/resources/functions/node/index.js | 42 +- tests/resources/functions/php-fn/index.php | 31 +- tests/resources/functions/php-large/index.php | 18 +- tests/resources/functions/php/index.php | 18 +- tests/resources/functions/python/main.py | 41 +- tests/resources/functions/ruby/main.rb | 42 +- tests/resources/functions/timeout/index.php | 5 +- tests/unit/Migration/MigrationTest.php | 88 - tests/unit/Usage/StatsTest.php | 79 +- tests/unit/Utopia/Request/Filters/V16Test.php | 51 + .../unit/Utopia/Response/Filters/V16Test.php | 228 +++ 3359 files changed, 64705 insertions(+), 6301 deletions(-) delete mode 100644 app/config/cloud/contributors.json delete mode 100644 app/config/cloud/employees.json delete mode 100644 app/config/cloud/heroes.json create mode 100644 app/config/locale/templates/email-inner-base.tpl create mode 100644 app/controllers/api/migrations.php create mode 100644 app/controllers/api/proxy.php create mode 100644 app/controllers/api/vcs.php create mode 100644 app/workers/migrations.php delete mode 100644 app/workers/usage.php create mode 100755 bin/upgrade create mode 100644 bin/usage create mode 100644 bin/worker-migrations delete mode 100644 bin/worker-usage create mode 100644 docs/examples/1.4.x/client-android/java/account/create-anonymous-session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/create-email-session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/create-j-w-t.md create mode 100644 docs/examples/1.4.x/client-android/java/account/create-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/create-o-auth2session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/create-phone-session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/client-android/java/account/create-recovery.md create mode 100644 docs/examples/1.4.x/client-android/java/account/create-verification.md create mode 100644 docs/examples/1.4.x/client-android/java/account/create.md create mode 100644 docs/examples/1.4.x/client-android/java/account/delete-identity.md create mode 100644 docs/examples/1.4.x/client-android/java/account/delete-session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/client-android/java/account/get-prefs.md create mode 100644 docs/examples/1.4.x/client-android/java/account/get-session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/get.md create mode 100644 docs/examples/1.4.x/client-android/java/account/list-identities.md create mode 100644 docs/examples/1.4.x/client-android/java/account/list-logs.md create mode 100644 docs/examples/1.4.x/client-android/java/account/list-sessions.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-email.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-name.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-password.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-phone-session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-phone.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-prefs.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-recovery.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-session.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-status.md create mode 100644 docs/examples/1.4.x/client-android/java/account/update-verification.md create mode 100644 docs/examples/1.4.x/client-android/java/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/client-android/java/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/client-android/java/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/client-android/java/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/client-android/java/avatars/get-image.md create mode 100644 docs/examples/1.4.x/client-android/java/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/client-android/java/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/client-android/java/databases/create-document.md create mode 100644 docs/examples/1.4.x/client-android/java/databases/delete-document.md create mode 100644 docs/examples/1.4.x/client-android/java/databases/get-document.md create mode 100644 docs/examples/1.4.x/client-android/java/databases/list-documents.md create mode 100644 docs/examples/1.4.x/client-android/java/databases/update-document.md create mode 100644 docs/examples/1.4.x/client-android/java/functions/create-execution.md create mode 100644 docs/examples/1.4.x/client-android/java/functions/get-execution.md create mode 100644 docs/examples/1.4.x/client-android/java/functions/list-executions.md create mode 100644 docs/examples/1.4.x/client-android/java/graphql/mutation.md create mode 100644 docs/examples/1.4.x/client-android/java/graphql/query.md create mode 100644 docs/examples/1.4.x/client-android/java/locale/get.md create mode 100644 docs/examples/1.4.x/client-android/java/locale/list-codes.md create mode 100644 docs/examples/1.4.x/client-android/java/locale/list-continents.md create mode 100644 docs/examples/1.4.x/client-android/java/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/client-android/java/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/client-android/java/locale/list-countries.md create mode 100644 docs/examples/1.4.x/client-android/java/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/client-android/java/locale/list-languages.md create mode 100644 docs/examples/1.4.x/client-android/java/storage/create-file.md create mode 100644 docs/examples/1.4.x/client-android/java/storage/delete-file.md create mode 100644 docs/examples/1.4.x/client-android/java/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/client-android/java/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/client-android/java/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/client-android/java/storage/get-file.md create mode 100644 docs/examples/1.4.x/client-android/java/storage/list-files.md create mode 100644 docs/examples/1.4.x/client-android/java/storage/update-file.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/create-membership.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/create.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/delete.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/get-membership.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/get.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/list.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/update-membership.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/update-name.md create mode 100644 docs/examples/1.4.x/client-android/java/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create-anonymous-session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create-email-session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create-j-w-t.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create-o-auth2session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create-phone-session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create-recovery.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create-verification.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/create.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/delete-identity.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/delete-session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/get-prefs.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/get-session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/get.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/list-identities.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/list-logs.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/list-sessions.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-email.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-name.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-password.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-phone-session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-phone.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-prefs.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-recovery.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-session.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-status.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/account/update-verification.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/avatars/get-image.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/databases/create-document.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/databases/delete-document.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/databases/get-document.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/databases/list-documents.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/databases/update-document.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/functions/create-execution.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/functions/get-execution.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/functions/list-executions.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/graphql/mutation.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/graphql/query.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/locale/get.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/locale/list-codes.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/locale/list-continents.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/locale/list-countries.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/locale/list-languages.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/storage/create-file.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/storage/delete-file.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/storage/get-file.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/storage/list-files.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/storage/update-file.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/create-membership.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/create.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/delete.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/get-membership.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/get.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/list.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/update-membership.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/update-name.md create mode 100644 docs/examples/1.4.x/client-android/kotlin/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create-anonymous-session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create-email-session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create-j-w-t.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create-o-auth2session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create-phone-session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/create.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/get.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-phone-session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/client-apple/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/client-apple/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/client-apple/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/client-apple/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/client-apple/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/client-apple/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/client-apple/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/client-apple/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/client-apple/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/client-apple/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/client-apple/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/client-apple/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/client-apple/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/client-apple/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/client-apple/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/client-apple/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/client-apple/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/client-apple/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/client-apple/examples/locale/get.md create mode 100644 docs/examples/1.4.x/client-apple/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/client-apple/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/client-apple/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/client-apple/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/client-apple/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/client-apple/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/client-apple/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/client-apple/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/client-apple/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/client-apple/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/client-apple/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/client-apple/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/client-apple/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/client-apple/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/client-apple/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/create.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/get.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/list.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/client-apple/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create-anonymous-session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create-email-session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create-j-w-t.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create-o-auth2session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create-phone-session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/create.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/get.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-phone-session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/locale/get.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/create.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/get.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/list.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/client-flutter/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/create-anonymous-session.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/create-email-session.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/create-j-w-t.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/create-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/create-phone-session.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/create.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/get.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-phone-session.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/locale/get.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/create.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/get.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/list.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/client-graphql/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create-anonymous-session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create-email-session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create-j-w-t.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create-o-auth2session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create-phone-session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/create.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/get.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-phone-session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/client-rest/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/client-rest/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/client-rest/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/client-rest/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/client-rest/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/client-rest/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/client-rest/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/client-rest/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/client-rest/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/client-rest/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/client-rest/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/client-rest/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/client-rest/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/client-rest/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/client-rest/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/client-rest/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/client-rest/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/client-rest/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/client-rest/examples/locale/get.md create mode 100644 docs/examples/1.4.x/client-rest/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/client-rest/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/client-rest/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/client-rest/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/client-rest/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/client-rest/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/client-rest/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/client-rest/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/client-rest/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/client-rest/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/client-rest/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/client-rest/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/client-rest/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/client-rest/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/client-rest/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/create.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/get.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/list.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/client-rest/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create-anonymous-session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create-email-session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create-j-w-t.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create-o-auth2session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create-phone-session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/create.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/get.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-phone-session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/client-web/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/client-web/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/client-web/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/client-web/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/client-web/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/client-web/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/client-web/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/client-web/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/client-web/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/client-web/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/client-web/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/client-web/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/client-web/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/client-web/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/client-web/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/client-web/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/client-web/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/client-web/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/client-web/examples/locale/get.md create mode 100644 docs/examples/1.4.x/client-web/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/client-web/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/client-web/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/client-web/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/client-web/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/client-web/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/client-web/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/client-web/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/client-web/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/client-web/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/client-web/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/client-web/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/client-web/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/client-web/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/client-web/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/create.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/get.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/list.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/client-web/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create-anonymous-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create-email-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create-j-w-t.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create-o-auth2session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create-phone-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/create.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/get.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-phone-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/console-cli/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/console-cli/examples/assistant/chat.md create mode 100644 docs/examples/1.4.x/console-cli/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/console-cli/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/console-cli/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/console-cli/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/console-cli/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/console-cli/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/console-cli/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/console-cli/examples/console/variables.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/create.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/get-collection-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/get-database-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/get-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/get.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/list-collection-logs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/list-document-logs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/list-logs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/list.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/console-cli/examples/databases/update.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/create.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/get-function-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/get-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/get.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/list.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/console-cli/examples/functions/update.md create mode 100644 docs/examples/1.4.x/console-cli/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/console-cli/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/console-cli/examples/health/get.md create mode 100644 docs/examples/1.4.x/console-cli/examples/locale/get.md create mode 100644 docs/examples/1.4.x/console-cli/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/console-cli/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/console-cli/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/console-cli/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/console-cli/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/console-cli/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/console-cli/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/create-appwrite-migration.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/create-firebase-migration.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/create-firebase-o-auth-migration.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/create-n-host-migration.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/create-supabase-migration.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/delete-firebase-auth.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/delete.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/get-appwrite-report.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/get-firebase-report-o-auth.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/get-firebase-report.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/get-n-host-report.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/get-supabase-report.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/get.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/list-firebase-projects.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/list.md create mode 100644 docs/examples/1.4.x/console-cli/examples/migrations/retry.md create mode 100644 docs/examples/1.4.x/console-cli/examples/project/create-variable.md create mode 100644 docs/examples/1.4.x/console-cli/examples/project/delete-variable.md create mode 100644 docs/examples/1.4.x/console-cli/examples/project/get-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/project/get-variable.md create mode 100644 docs/examples/1.4.x/console-cli/examples/project/list-variables.md create mode 100644 docs/examples/1.4.x/console-cli/examples/project/update-variable.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/create-key.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/create-platform.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/create-webhook.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/create.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/delete-email-template.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/delete-key.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/delete-platform.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/delete-sms-template.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/delete-webhook.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/delete.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/get-email-template.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/get-key.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/get-platform.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/get-sms-template.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/get-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/get-webhook.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/get.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/list-keys.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/list-platforms.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/list-webhooks.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/list.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-auth-duration.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-auth-limit.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-auth-password-dictionary.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-auth-password-history.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-auth-sessions-limit.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-auth-status.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-email-template.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-key.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-o-auth2.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-personal-data-check.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-platform.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-service-status-all.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-service-status.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-sms-template.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-smtp-configuration.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-team.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-webhook-signature.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update-webhook.md create mode 100644 docs/examples/1.4.x/console-cli/examples/projects/update.md create mode 100644 docs/examples/1.4.x/console-cli/examples/proxy/create-rule.md create mode 100644 docs/examples/1.4.x/console-cli/examples/proxy/delete-rule.md create mode 100644 docs/examples/1.4.x/console-cli/examples/proxy/get-rule.md create mode 100644 docs/examples/1.4.x/console-cli/examples/proxy/list-rules.md create mode 100644 docs/examples/1.4.x/console-cli/examples/proxy/update-rule-verification.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/get-bucket-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/get-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/console-cli/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/create.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/get.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/list-logs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/list.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/console-cli/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/create.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/delete.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/get-usage.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/get.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/list.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/console-cli/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/console-cli/examples/vcs/create-repository-detection.md create mode 100644 docs/examples/1.4.x/console-cli/examples/vcs/create-repository.md create mode 100644 docs/examples/1.4.x/console-cli/examples/vcs/delete-installation.md create mode 100644 docs/examples/1.4.x/console-cli/examples/vcs/get-installation.md create mode 100644 docs/examples/1.4.x/console-cli/examples/vcs/get-repository.md create mode 100644 docs/examples/1.4.x/console-cli/examples/vcs/list-installations.md create mode 100644 docs/examples/1.4.x/console-cli/examples/vcs/list-repositories.md create mode 100644 docs/examples/1.4.x/console-cli/examples/vcs/list-repository-branches.md create mode 100644 docs/examples/1.4.x/console-cli/examples/vcs/update-external-deployments.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create-anonymous-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create-email-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create-j-w-t.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create-o-auth2session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create-phone-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/create.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/get.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-magic-u-r-l-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-phone-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/console-web/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/console-web/examples/assistant/chat.md create mode 100644 docs/examples/1.4.x/console-web/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/console-web/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/console-web/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/console-web/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/console-web/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/console-web/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/console-web/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/console-web/examples/console/variables.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/create.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/get-collection-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/get-database-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/get-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/get.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/list-collection-logs.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/list-document-logs.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/list-logs.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/list.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/console-web/examples/databases/update.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/create.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/get-function-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/get-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/get.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/list.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/console-web/examples/functions/update.md create mode 100644 docs/examples/1.4.x/console-web/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/console-web/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/console-web/examples/health/get.md create mode 100644 docs/examples/1.4.x/console-web/examples/locale/get.md create mode 100644 docs/examples/1.4.x/console-web/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/console-web/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/console-web/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/console-web/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/console-web/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/console-web/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/console-web/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/create-appwrite-migration.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/create-firebase-migration.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/create-firebase-o-auth-migration.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/create-n-host-migration.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/create-supabase-migration.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/delete-firebase-auth.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/delete.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/get-appwrite-report.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/get-firebase-report-o-auth.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/get-firebase-report.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/get-n-host-report.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/get-supabase-report.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/get.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/list-firebase-projects.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/list.md create mode 100644 docs/examples/1.4.x/console-web/examples/migrations/retry.md create mode 100644 docs/examples/1.4.x/console-web/examples/project/create-variable.md create mode 100644 docs/examples/1.4.x/console-web/examples/project/delete-variable.md create mode 100644 docs/examples/1.4.x/console-web/examples/project/get-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/project/get-variable.md create mode 100644 docs/examples/1.4.x/console-web/examples/project/list-variables.md create mode 100644 docs/examples/1.4.x/console-web/examples/project/update-variable.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/create-key.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/create-platform.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/create-webhook.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/create.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/delete-email-template.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/delete-key.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/delete-platform.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/delete-sms-template.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/delete-webhook.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/delete.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/get-email-template.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/get-key.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/get-platform.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/get-sms-template.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/get-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/get-webhook.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/get.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/list-keys.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/list-platforms.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/list-webhooks.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/list.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-auth-duration.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-auth-limit.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-auth-password-dictionary.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-auth-password-history.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-auth-sessions-limit.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-auth-status.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-email-template.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-key.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-o-auth2.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-personal-data-check.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-platform.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-service-status-all.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-service-status.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-sms-template.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-smtp-configuration.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-team.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-webhook-signature.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update-webhook.md create mode 100644 docs/examples/1.4.x/console-web/examples/projects/update.md create mode 100644 docs/examples/1.4.x/console-web/examples/proxy/create-rule.md create mode 100644 docs/examples/1.4.x/console-web/examples/proxy/delete-rule.md create mode 100644 docs/examples/1.4.x/console-web/examples/proxy/get-rule.md create mode 100644 docs/examples/1.4.x/console-web/examples/proxy/list-rules.md create mode 100644 docs/examples/1.4.x/console-web/examples/proxy/update-rule-verification.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/get-bucket-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/get-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/console-web/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/create.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/get.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/list-logs.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/list.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/console-web/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/create.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/delete.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/get-usage.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/get.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/list.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/console-web/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/console-web/examples/vcs/create-repository-detection.md create mode 100644 docs/examples/1.4.x/console-web/examples/vcs/create-repository.md create mode 100644 docs/examples/1.4.x/console-web/examples/vcs/delete-installation.md create mode 100644 docs/examples/1.4.x/console-web/examples/vcs/get-installation.md create mode 100644 docs/examples/1.4.x/console-web/examples/vcs/get-repository.md create mode 100644 docs/examples/1.4.x/console-web/examples/vcs/list-installations.md create mode 100644 docs/examples/1.4.x/console-web/examples/vcs/list-repositories.md create mode 100644 docs/examples/1.4.x/console-web/examples/vcs/list-repository-branches.md create mode 100644 docs/examples/1.4.x/console-web/examples/vcs/update-external-deployments.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-dart/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-dart/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-dart/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-dart/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-dart/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-dart/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-dart/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-dart/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-dart/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-dart/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-dart/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-dart/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-dart/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-dart/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-dart/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-dart/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-dart/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-dart/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-dart/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-dart/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-dart/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-dart/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-dart/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-dart/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-deno/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-deno/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-deno/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-deno/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-deno/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-deno/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-deno/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-deno/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-deno/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-deno/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-deno/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-deno/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-deno/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-deno/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-deno/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-deno/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-deno/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-deno/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-deno/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-deno/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-deno/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-deno/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-deno/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-deno/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-dotnet/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-graphql/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/get-session.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-email.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-name.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-password.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-session.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-status.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/create.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/delete.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/list.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/databases/update.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/create.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/delete.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/list.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/functions/update.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/graphql/query.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get-time.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/health/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/locale/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/create.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/delete.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/list.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/create.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/delete.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/list.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/update-email.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/update-name.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/update-password.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/java/users/update-status.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/get-session.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-email.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-name.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-password.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-session.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-status.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/create.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/delete.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/list.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/databases/update.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/create.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/delete.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/list.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/functions/update.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/graphql/query.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get-time.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/health/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/locale/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/create.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/delete.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/list.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/create.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/delete.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/get.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/list.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/update-email.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/update-name.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/update-password.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-kotlin/kotlin/users/update-status.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-nodejs/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-php/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-php/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-php/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-php/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-php/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-php/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-php/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-php/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-php/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-php/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-php/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-php/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-php/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-php/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-php/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-php/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-php/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-php/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-php/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-php/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-php/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-php/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-php/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-php/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-python/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-python/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-python/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-python/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-python/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-python/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-python/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-python/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-python/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-python/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-python/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-python/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-python/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-python/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-python/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-python/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-python/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-python/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-python/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-python/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-python/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-python/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-python/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-python/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-rest/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-rest/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-rest/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-rest/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-rest/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-rest/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-rest/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-rest/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-rest/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-rest/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-rest/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-rest/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-rest/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-rest/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-rest/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-rest/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-rest/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-rest/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-rest/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-rest/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-rest/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-rest/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-rest/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-rest/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-ruby/examples/users/update-status.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/create-phone-verification.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/create-recovery.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/create-verification.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/delete-identity.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/delete-session.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/get-prefs.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/get-session.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/get.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/list-identities.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/list-logs.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/list-sessions.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-email.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-name.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-password.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-phone.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-prefs.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-recovery.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-session.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-status.md create mode 100644 docs/examples/1.4.x/server-swift/examples/account/update-verification.md create mode 100644 docs/examples/1.4.x/server-swift/examples/avatars/get-browser.md create mode 100644 docs/examples/1.4.x/server-swift/examples/avatars/get-credit-card.md create mode 100644 docs/examples/1.4.x/server-swift/examples/avatars/get-favicon.md create mode 100644 docs/examples/1.4.x/server-swift/examples/avatars/get-flag.md create mode 100644 docs/examples/1.4.x/server-swift/examples/avatars/get-image.md create mode 100644 docs/examples/1.4.x/server-swift/examples/avatars/get-initials.md create mode 100644 docs/examples/1.4.x/server-swift/examples/avatars/get-q-r.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-collection.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-document.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-email-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-float-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-index.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-string-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create-url-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/create.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/delete-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/delete-collection.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/delete-document.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/delete-index.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/delete.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/get-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/get-collection.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/get-document.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/get-index.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/get.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/list-attributes.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/list-collections.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/list-documents.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/list-indexes.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/list.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-boolean-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-collection.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-datetime-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-document.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-email-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-enum-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-float-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-integer-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-ip-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-relationship-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-string-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update-url-attribute.md create mode 100644 docs/examples/1.4.x/server-swift/examples/databases/update.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/create-build.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/create-deployment.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/create-execution.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/create-variable.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/create.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/delete-deployment.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/delete-variable.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/delete.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/download-deployment.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/get-deployment.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/get-execution.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/get-variable.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/get.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/list-deployments.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/list-executions.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/list-runtimes.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/list-variables.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/list.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/update-deployment.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/update-variable.md create mode 100644 docs/examples/1.4.x/server-swift/examples/functions/update.md create mode 100644 docs/examples/1.4.x/server-swift/examples/graphql/mutation.md create mode 100644 docs/examples/1.4.x/server-swift/examples/graphql/query.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-antivirus.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-cache.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-d-b.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-pub-sub.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-queue-certificates.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-queue-functions.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-queue-logs.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-queue-webhooks.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-queue.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-storage-local.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get-time.md create mode 100644 docs/examples/1.4.x/server-swift/examples/health/get.md create mode 100644 docs/examples/1.4.x/server-swift/examples/locale/get.md create mode 100644 docs/examples/1.4.x/server-swift/examples/locale/list-codes.md create mode 100644 docs/examples/1.4.x/server-swift/examples/locale/list-continents.md create mode 100644 docs/examples/1.4.x/server-swift/examples/locale/list-countries-e-u.md create mode 100644 docs/examples/1.4.x/server-swift/examples/locale/list-countries-phones.md create mode 100644 docs/examples/1.4.x/server-swift/examples/locale/list-countries.md create mode 100644 docs/examples/1.4.x/server-swift/examples/locale/list-currencies.md create mode 100644 docs/examples/1.4.x/server-swift/examples/locale/list-languages.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/create-bucket.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/create-file.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/delete-bucket.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/delete-file.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/get-bucket.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/get-file-download.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/get-file-preview.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/get-file-view.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/get-file.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/list-buckets.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/list-files.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/update-bucket.md create mode 100644 docs/examples/1.4.x/server-swift/examples/storage/update-file.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/create-membership.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/create.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/delete-membership.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/delete.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/get-membership.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/get-prefs.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/get.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/list-memberships.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/list.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/update-membership-status.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/update-membership.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/update-name.md create mode 100644 docs/examples/1.4.x/server-swift/examples/teams/update-prefs.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/create-argon2user.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/create-bcrypt-user.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/create-m-d5user.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/create-p-h-pass-user.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/create-s-h-a-user.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/create-scrypt-modified-user.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/create-scrypt-user.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/create.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/delete-identity.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/delete-session.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/delete-sessions.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/delete.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/get-prefs.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/get.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/list-identities.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/list-logs.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/list-memberships.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/list-sessions.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/list.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/update-email-verification.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/update-email.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/update-labels.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/update-name.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/update-password.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/update-phone-verification.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/update-phone.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/update-prefs.md create mode 100644 docs/examples/1.4.x/server-swift/examples/users/update-status.md create mode 100644 docs/references/account/delete-identity.md create mode 100644 docs/references/account/list-identities.md create mode 100644 docs/references/functions/create-build.md create mode 100644 docs/references/project/create-variable.md create mode 100644 docs/references/project/delete-variable.md create mode 100644 docs/references/project/get-variable.md create mode 100644 docs/references/project/list-variables.md create mode 100644 docs/references/project/update-variable.md create mode 100644 docs/references/proxy/create-rule.md create mode 100644 docs/references/proxy/delete-rule.md create mode 100644 docs/references/proxy/get-rule.md create mode 100644 docs/references/proxy/list-rules.md rename docs/references/teams/{update-team-membership-roles.md => update-team-membership.md} (78%) create mode 100644 docs/references/users/delete-identity.md create mode 100644 docs/references/users/list-identities.md create mode 100644 docs/services/proxy.md create mode 100644 docs/services/vcs.md create mode 100644 src/Appwrite/Auth/OAuth2/Firebase.php create mode 100644 src/Appwrite/Event/Migration.php create mode 100644 src/Appwrite/Platform/Tasks/Upgrade.php create mode 100644 src/Appwrite/Platform/Tasks/Usage.php create mode 100644 src/Appwrite/Usage/Calculator.php create mode 100644 src/Appwrite/Usage/Calculators/TimeSeries.php create mode 100644 src/Appwrite/Usage/Stats.php create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Identities.php create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Installations.php create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Rules.php create mode 100644 src/Appwrite/Utopia/Request/Filters/V16.php create mode 100644 src/Appwrite/Utopia/Response/Filters/V16.php create mode 100644 src/Appwrite/Utopia/Response/Model/Branch.php create mode 100644 src/Appwrite/Utopia/Response/Model/Detection.php delete mode 100644 src/Appwrite/Utopia/Response/Model/Domain.php create mode 100644 src/Appwrite/Utopia/Response/Model/Headers.php create mode 100644 src/Appwrite/Utopia/Response/Model/Identity.php create mode 100644 src/Appwrite/Utopia/Response/Model/Installation.php create mode 100644 src/Appwrite/Utopia/Response/Model/Migration.php create mode 100644 src/Appwrite/Utopia/Response/Model/MigrationFirebaseProject.php create mode 100644 src/Appwrite/Utopia/Response/Model/MigrationReport.php create mode 100644 src/Appwrite/Utopia/Response/Model/ProviderRepository.php create mode 100644 src/Appwrite/Utopia/Response/Model/Rule.php create mode 100644 src/Appwrite/Vcs/Comment.php create mode 100644 tests/unit/Utopia/Request/Filters/V16Test.php create mode 100644 tests/unit/Utopia/Response/Filters/V16Test.php diff --git a/.env b/.env index 8b266abccf..6ef35b57c1 100644 --- a/.env +++ b/.env @@ -1,12 +1,9 @@ _APP_ENV=development _APP_LOCALE=en -_APP_WORKER_PER_CORE=2 +_APP_WORKER_PER_CORE=6 _APP_CONSOLE_WHITELIST_ROOT=disabled _APP_CONSOLE_WHITELIST_EMAILS= -_APP_CONSOLE_WHITELIST_CODES=code-zero,code-one _APP_CONSOLE_WHITELIST_IPS= -_APP_CONSOLE_INVITES=enabled -_APP_CONSOLE_ROOT_SESSION=disabled _APP_SYSTEM_EMAIL_NAME=Appwrite _APP_SYSTEM_EMAIL_ADDRESS=team@appwrite.io _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=security@appwrite.io @@ -14,8 +11,9 @@ _APP_SYSTEM_RESPONSE_FORMAT= _APP_OPTIONS_ABUSE=disabled _APP_OPTIONS_FORCE_HTTPS=disabled _APP_OPENSSL_KEY_V1=your-secret-key -_APP_DOMAIN=demo.appwrite.io -_APP_DOMAIN_TARGET=demo.appwrite.io +_APP_DOMAIN=localhost +_APP_DOMAIN_FUNCTIONS=functions.localhost +_APP_DOMAIN_TARGET=localhost _APP_REDIS_HOST=redis _APP_REDIS_PORT=6379 _APP_REDIS_PASS= @@ -26,26 +24,39 @@ _APP_DB_SCHEMA=appwrite _APP_DB_USER=user _APP_DB_PASS=password _APP_DB_ROOT_PASS=rootsecretpassword -_APP_CONNECTIONS_MAX=3100 -_APP_POOL_CLIENTS=14 -_APP_CONNECTIONS_DB_PROJECT=db_fra1_02=mariadb://user:password@mariadb:3306/appwrite -_APP_CONNECTIONS_DB_CONSOLE=db_fra1_01=mariadb://user:password@mariadb:3306/appwrite -_APP_CONNECTIONS_CACHE=redis_fra1_01=redis://redis:6379 -_APP_CONNECTIONS_QUEUE=redis_fra1_01=redis://redis:6379 -_APP_CONNECTIONS_PUBSUB=redis_fra1_01=redis://redis:6379 -_APP_CONNECTIONS_STORAGE=local://localhost +_APP_STORAGE_DEVICE=Local +_APP_STORAGE_S3_ACCESS_KEY= +_APP_STORAGE_S3_SECRET= +_APP_STORAGE_S3_REGION=us-east-1 +_APP_STORAGE_S3_BUCKET= +_APP_STORAGE_DO_SPACES_ACCESS_KEY= +_APP_STORAGE_DO_SPACES_SECRET= +_APP_STORAGE_DO_SPACES_REGION=us-east-1 +_APP_STORAGE_DO_SPACES_BUCKET= +_APP_STORAGE_BACKBLAZE_ACCESS_KEY= +_APP_STORAGE_BACKBLAZE_SECRET= +_APP_STORAGE_BACKBLAZE_REGION=us-west-004 +_APP_STORAGE_BACKBLAZE_BUCKET= +_APP_STORAGE_LINODE_ACCESS_KEY= +_APP_STORAGE_LINODE_SECRET= +_APP_STORAGE_LINODE_REGION=eu-central-1 +_APP_STORAGE_LINODE_BUCKET= +_APP_STORAGE_WASABI_ACCESS_KEY= +_APP_STORAGE_WASABI_SECRET= +_APP_STORAGE_WASABI_REGION=eu-central-1 +_APP_STORAGE_WASABI_BUCKET= _APP_STORAGE_ANTIVIRUS=disabled _APP_STORAGE_ANTIVIRUS_HOST=clamav _APP_STORAGE_ANTIVIRUS_PORT=3310 +_APP_INFLUXDB_HOST=influxdb +_APP_INFLUXDB_PORT=8086 +_APP_STATSD_HOST=telegraf +_APP_STATSD_PORT=8125 _APP_SMTP_HOST=maildev _APP_SMTP_PORT=1025 _APP_SMTP_SECURE= _APP_SMTP_USERNAME= _APP_SMTP_PASSWORD= -_APP_USERS_STATS_RECIPIENTS= -_APP_HAMSTER_INTERVAL=86400 -_APP_HAMSTER_TIME=21:00 -_APP_MIXPANEL_TOKEN= _APP_SMS_PROVIDER=sms://username:password@mock _APP_SMS_FROM=+123456789 _APP_STORAGE_LIMIT=30000000 @@ -54,30 +65,35 @@ _APP_FUNCTIONS_SIZE_LIMIT=30000000 _APP_FUNCTIONS_TIMEOUT=900 _APP_FUNCTIONS_BUILD_TIMEOUT=900 _APP_FUNCTIONS_CPUS=1 -_APP_FUNCTIONS_MEMORY=512 +_APP_FUNCTIONS_MEMORY=1024 _APP_FUNCTIONS_INACTIVE_THRESHOLD=600 _APP_FUNCTIONS_MAINTENANCE_INTERVAL=600 _APP_FUNCTIONS_RUNTIMES_NETWORK=runtimes _APP_EXECUTOR_SECRET=your-secret-key -_APP_EXECUTOR_HOST=http://exc1/v1 +_APP_EXECUTOR_HOST=http://proxy/v1 _APP_FUNCTIONS_RUNTIMES= _APP_MAINTENANCE_INTERVAL=86400 _APP_MAINTENANCE_RETENTION_CACHE=2592000 _APP_MAINTENANCE_RETENTION_EXECUTION=1209600 _APP_MAINTENANCE_RETENTION_ABUSE=86400 _APP_MAINTENANCE_RETENTION_AUDIT=1209600 -_APP_MAINTENANCE_RETENTION_SCHEDULES=86400 +_APP_USAGE_AGGREGATION_INTERVAL=5 _APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000 +_APP_MAINTENANCE_RETENTION_SCHEDULES=86400 _APP_USAGE_STATS=enabled -_APP_USAGE_AGGREGATION_INTERVAL=30 _APP_LOGGING_PROVIDER= _APP_LOGGING_CONFIG= _APP_GRAPHQL_MAX_BATCH_SIZE=10 _APP_GRAPHQL_MAX_COMPLEXITY=250 _APP_GRAPHQL_MAX_DEPTH=3 -_APP_REGION=default _APP_DOCKER_HUB_USERNAME= _APP_DOCKER_HUB_PASSWORD= -_APP_CONSOLE_GITHUB_SECRET= -_APP_CONSOLE_GITHUB_APP_ID= -OPENAI_API_KEY=YOUR_OPENAI_API_KEY \ No newline at end of file +_APP_VCS_GITHUB_APP_NAME= +_APP_VCS_GITHUB_PRIVATE_KEY="" +_APP_VCS_GITHUB_APP_ID= +_APP_VCS_GITHUB_CLIENT_ID= +_APP_VCS_GITHUB_CLIENT_SECRET= +_APP_VCS_GITHUB_WEBHOOK_SECRET= +_APP_MIGRATIONS_FIREBASE_CLIENT_ID= +_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET= +_APP_ASSISTANT_OPENAI_API_KEY= \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d3fdf1e2d3..8fb3ac3518 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -49,7 +49,9 @@ jobs: sleep 30 - name: Doctor - run: docker compose exec -T appwrite doctor + run: | + docker compose logs appwrite + docker compose exec -T appwrite doctor - name: Environment Variables run: docker compose exec -T appwrite vars diff --git a/.gitmodules b/.gitmodules index 92afa7ada7..a4726398ed 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "app/console"] path = app/console url = https://github.com/appwrite/console - branch = disallow-personal-data + branch = 3.0.2 diff --git a/CHANGES.md b/CHANGES.md index 864fc04012..2d9af087db 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,19 @@ +# Version 1.4.1 + +## Features + +- Add upgrade task [#6068](https://github.com/appwrite/appwrite/pull/6068) + +## Fixes + +- Fix VCS/migration/assistant scopes [#6071](https://github.com/appwrite/appwrite/pull/6071) +- Add missing parameters required for custom email templates [#6077](https://github.com/appwrite/appwrite/pull/6077) +- Fix `Call to a member function label() on null` error when using a custom domain [#6079](https://github.com/appwrite/appwrite/pull/6079) + +## Changes + +- Update console to 3.0.2 [#6071](https://github.com/appwrite/appwrite/pull/6071) + # Version 1.4.0 ## Features @@ -121,41 +137,6 @@ - Get default region from environment on project create [#4780](https://github.com/appwrite/appwrite/pull/4780) - Fix french translation [#4782](https://github.com/appwrite/appwrite/pull/4782) - Fix max mimetype size [#4814](https://github.com/appwrite/appwrite/pull/4814) -- New usage metrics collection flow [#4770](https://github.com/appwrite/appwrite/pull/4770) - - Deprecated influxdb, telegraf containers and removed all of their occurrences from the code. - - Removed _APP_INFLUXDB_HOST, _APP_INFLUXDB_PORT, _APP_STATSD_HOST, _APP_STATSD_PORT env variables. - - Removed usage labels dependency. - - Dropped type attribute from stats collection. - - Usage metrics are processed via new usage worker. - - Metrics changes: - - Storage - - deprecated - - filesCreate, filesRead, filesUpdate, filesDelete, bucketsCreate, bucketsRead, bucketsUpdate, bucketsDelete. - - renamed - - filesCount to filesTotal, storage to filesStorage, bucketsCount to bucketsTotal. - - Auth - - deprecated - - usersCreate, usersRead, usersUpdate, usersDelete, sessionsCreate sessionsProviderCreate, sessionsDelete. - - renamed - - usersCount to usersTotal. - - added - - sessionsTotal. - - Databases - - deprecated - - databasesCreate, databasesRead, databasesDelete, documentsCreate, documentsRead, documentsUpdate, documentsDelete, collectionsCreate, collectionsRead, collectionsUpdate, collectionsDelete. - - renamed - - databasesCount to databasesTotal, collectionsCount to collectionsTotal, documentsCount to documentsTotal. - - Functions - - deprecated - - executionsFailure, executionsSuccess, buildsFailure, buildsSuccess, executionsFailure, executionsSuccess. - - renamed - - executionsTime to executionsCompute, buildsTime to buildsCompute, documentsCount to documentsTotal. - - added - - functionsTotal, buildsStorage, deploymentsTotal, deploymentsStorage. - - Project - - renamed - - executions to executionsTotal, builds to buildsTotal, requests to requestsTotal, storage to filesStorage, buckets to bucketsTotal, users to usersTotal, documents to documentsTotal, collections to collectionsTotal, databases to databasesTotal. - ## Bugs - Fix invited account verified status [#4776](https://github.com/appwrite/appwrite/pull/4776) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 83e14d8c31..1341c9f133 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -109,7 +109,9 @@ docker run --rm --interactive --tty \ ### User Interface -Appwrite uses an internal micro-framework called Litespeed.js to build simple UI components in vanilla JS and [less](http://lesscss.org/) for compiling CSS code. To apply any of your changes to the UI, use the `gulp build` or `gulp less` commands, and restart the Appwrite main container to load the new static files to memory using `docker compose restart appwrite`. +Appwrite's UI is built with [Svelte](https://svelte.dev/), [Svelte Kit](https://kit.svelte.dev/), and the [Pink Design](https://github.com/appwrite/pink) component library. You can find the source code in the [Appwrite Console](https://github.com/appwrite/console) repository. + +To contribute to the UI, head to the [Contribution Guide](https://github.com/appwrite/console/blob/main/CONTRIBUTING.md) of Appwrite Console. ### Get Started @@ -238,6 +240,8 @@ Appwrite stack is a combination of a variety of open-source technologies and too - Redis - for managing cache and in-memory data (currently, we do not use Redis for persistent data). - MariaDB - for database storage and queries. +- InfluxDB - for managing stats and time-series based data +- Statsd - for sending data over UDP protocol (using Telegraf) - ClamAV - for validating and scanning storage files. - Imagemagick - for manipulating and managing image media files. - Webp - for better compression of images on supporting clients. diff --git a/Dockerfile b/Dockerfile index 37659cafa1..23bd3f188f 100755 --- a/Dockerfile +++ b/Dockerfile @@ -29,7 +29,7 @@ ENV VITE_APPWRITE_GROWTH_ENDPOINT=$VITE_APPWRITE_GROWTH_ENDPOINT RUN npm ci RUN npm run build -FROM appwrite/base:0.4.2 as final +FROM appwrite/base:0.4.3 as final LABEL maintainer="team@appwrite.io" @@ -43,14 +43,15 @@ ENV DOCKER_COMPOSE_VERSION=v2.5.0 ENV _APP_SERVER=swoole \ _APP_ENV=production \ _APP_LOCALE=en \ + _APP_WORKER_PER_CORE= \ _APP_DOMAIN=localhost \ + _APP_DOMAIN_FUNCTIONS=functions.localhost \ _APP_DOMAIN_TARGET=localhost \ _APP_HOME=https://appwrite.io \ _APP_EDITION=community \ _APP_CONSOLE_WHITELIST_ROOT=enabled \ _APP_CONSOLE_WHITELIST_EMAILS= \ _APP_CONSOLE_WHITELIST_IPS= \ - _APP_CONSOLE_ROOT_SESSION= \ _APP_SYSTEM_EMAIL_NAME= \ _APP_SYSTEM_EMAIL_ADDRESS= \ _APP_SYSTEM_RESPONSE_FORMAT= \ @@ -62,6 +63,27 @@ ENV _APP_SERVER=swoole \ _APP_STORAGE_ANTIVIRUS=enabled \ _APP_STORAGE_ANTIVIRUS_HOST=clamav \ _APP_STORAGE_ANTIVIRUS_PORT=3310 \ + _APP_STORAGE_DEVICE=Local \ + _APP_STORAGE_S3_ACCESS_KEY= \ + _APP_STORAGE_S3_SECRET= \ + _APP_STORAGE_S3_REGION= \ + _APP_STORAGE_S3_BUCKET= \ + _APP_STORAGE_DO_SPACES_ACCESS_KEY= \ + _APP_STORAGE_DO_SPACES_SECRET= \ + _APP_STORAGE_DO_SPACES_REGION= \ + _APP_STORAGE_DO_SPACES_BUCKET= \ + _APP_STORAGE_BACKBLAZE_ACCESS_KEY= \ + _APP_STORAGE_BACKBLAZE_SECRET= \ + _APP_STORAGE_BACKBLAZE_REGION= \ + _APP_STORAGE_BACKBLAZE_BUCKET= \ + _APP_STORAGE_LINODE_ACCESS_KEY= \ + _APP_STORAGE_LINODE_SECRET= \ + _APP_STORAGE_LINODE_REGION= \ + _APP_STORAGE_LINODE_BUCKET= \ + _APP_STORAGE_WASABI_ACCESS_KEY= \ + _APP_STORAGE_WASABI_SECRET= \ + _APP_STORAGE_WASABI_REGION= \ + _APP_STORAGE_WASABI_BUCKET= \ _APP_REDIS_HOST=redis \ _APP_REDIS_PORT=6379 \ _APP_DB_HOST=mariadb \ @@ -69,22 +91,45 @@ ENV _APP_SERVER=swoole \ _APP_DB_USER=root \ _APP_DB_PASS=password \ _APP_DB_SCHEMA=appwrite \ + _APP_INFLUXDB_HOST=influxdb \ + _APP_INFLUXDB_PORT=8086 \ + _APP_STATSD_HOST=telegraf \ + _APP_STATSD_PORT=8125 \ + _APP_SMTP_HOST= \ + _APP_SMTP_PORT= \ + _APP_SMTP_SECURE= \ + _APP_SMTP_USERNAME= \ + _APP_SMTP_PASSWORD= \ + _APP_SMS_PROVIDER= \ + _APP_SMS_FROM= \ _APP_FUNCTIONS_SIZE_LIMIT=30000000 \ _APP_FUNCTIONS_TIMEOUT=900 \ + _APP_FUNCTIONS_CONTAINERS=10 \ _APP_FUNCTIONS_CPUS=1 \ _APP_FUNCTIONS_MEMORY=128 \ + _APP_FUNCTIONS_MEMORY_SWAP=128 \ _APP_EXECUTOR_SECRET=a-random-secret \ - _APP_EXECUTOR_HOST=http://exc1/v1 \ + _APP_EXECUTOR_HOST=http://appwrite-executor/v1 \ + _APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes \ _APP_SETUP=self-hosted \ _APP_VERSION=$VERSION \ _APP_USAGE_STATS=enabled \ + _APP_USAGE_AGGREGATION_INTERVAL=30 \ # 14 Days = 1209600 s _APP_MAINTENANCE_RETENTION_EXECUTION=1209600 \ _APP_MAINTENANCE_RETENTION_AUDIT=1209600 \ # 1 Day = 86400 s _APP_MAINTENANCE_RETENTION_ABUSE=86400 \ _APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000 \ - _APP_MAINTENANCE_INTERVAL=86400 + _APP_MAINTENANCE_INTERVAL=86400 \ + _APP_LOGGING_PROVIDER= \ + _APP_LOGGING_CONFIG= \ + _APP_VCS_GITHUB_APP_NAME= \ + _APP_VCS_GITHUB_PRIVATE_KEY= \ + _APP_VCS_GITHUB_APP_ID= \ + _APP_VCS_GITHUB_CLIENT_ID= \ + _APP_VCS_GITHUB_CLIENT_SECRET= \ + _APP_VCS_GITHUB_WEBHOOK_SECRET= RUN \ if [ "$DEBUG" == "true" ]; then \ @@ -119,21 +164,16 @@ RUN mkdir -p /storage/uploads && \ # Executables RUN chmod +x /usr/local/bin/doctor && \ - chmod +x /usr/local/bin/patch-delete-schedule-updated-at-attribute && \ - chmod +x /usr/local/bin/clear-card-cache && \ - chmod +x /usr/local/bin/calc-users-stats && \ - chmod +x /usr/local/bin/calc-tier-stats && \ - chmod +x /usr/local/bin/patch-delete-project-collections && \ chmod +x /usr/local/bin/maintenance && \ - chmod +x /usr/local/bin/volume-sync && \ + chmod +x /usr/local/bin/usage && \ chmod +x /usr/local/bin/install && \ + chmod +x /usr/local/bin/upgrade && \ chmod +x /usr/local/bin/migrate && \ chmod +x /usr/local/bin/realtime && \ chmod +x /usr/local/bin/schedule && \ chmod +x /usr/local/bin/sdks && \ chmod +x /usr/local/bin/specs && \ chmod +x /usr/local/bin/ssl && \ - chmod +x /usr/local/bin/hamster && \ chmod +x /usr/local/bin/test && \ chmod +x /usr/local/bin/vars && \ chmod +x /usr/local/bin/worker-audits && \ @@ -145,7 +185,16 @@ RUN chmod +x /usr/local/bin/doctor && \ chmod +x /usr/local/bin/worker-mails && \ chmod +x /usr/local/bin/worker-messaging && \ chmod +x /usr/local/bin/worker-webhooks && \ - chmod +x /usr/local/bin/worker-usage + chmod +x /usr/local/bin/worker-migrations + +# Cloud Executabless +RUN chmod +x /usr/local/bin/hamster && \ + chmod +x /usr/local/bin/volume-sync && \ + chmod +x /usr/local/bin/patch-delete-schedule-updated-at-attribute && \ + chmod +x /usr/local/bin/patch-delete-project-collections && \ + chmod +x /usr/local/bin/clear-card-cache && \ + chmod +x /usr/local/bin/calc-users-stats && \ + chmod +x /usr/local/bin/calc-tier-stats # Letsencrypt Permissions RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/ diff --git a/README-CN.md b/README-CN.md index b634458547..f960943477 100644 --- a/README-CN.md +++ b/README-CN.md @@ -66,7 +66,7 @@ docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ - appwrite/appwrite:1.3.8 + appwrite/appwrite:1.4.1 ``` ### Windows @@ -78,7 +78,7 @@ docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --entrypoint="install" ^ - appwrite/appwrite:1.3.8 + appwrite/appwrite:1.4.1 ``` #### PowerShell @@ -88,7 +88,7 @@ docker run -it --rm ` --volume /var/run/docker.sock:/var/run/docker.sock ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --entrypoint="install" ` - appwrite/appwrite:1.3.8 + appwrite/appwrite:1.4.1 ``` 运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。 diff --git a/README.md b/README.md index 2b82d49eb0..b205b18d8a 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ - appwrite/appwrite:1.3.8 + appwrite/appwrite:1.4.1 ``` ### Windows @@ -87,7 +87,7 @@ docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --entrypoint="install" ^ - appwrite/appwrite:1.3.8 + appwrite/appwrite:1.4.1 ``` #### PowerShell @@ -97,7 +97,7 @@ docker run -it --rm ` --volume /var/run/docker.sock:/var/run/docker.sock ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --entrypoint="install" ` - appwrite/appwrite:1.3.8 + appwrite/appwrite:1.4.1 ``` Once the Docker installation is complete, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after completing the installation. @@ -131,7 +131,7 @@ Choose from one of the providers below: Akamai Logo -
Akamai
+
Akamai Compute diff --git a/SECURITY.md b/SECURITY.md index bc85b354d8..a0591d7745 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,6 +9,7 @@ | 1.1.x | :white_check_mark: | | 1.2.x | :white_check_mark: | | 1.3.x | :white_check_mark: | +| 1.4.x | :white_check_mark: | ## Reporting a Vulnerability diff --git a/app/cli.php b/app/cli.php index d1dd885775..c8ebd089b1 100644 --- a/app/cli.php +++ b/app/cli.php @@ -58,7 +58,7 @@ CLI::setResource('dbForConsole', function ($pools, $cache) { ->getResource(); $dbForConsole = new Database($dbAdapter, $cache); - $dbForConsole->setNamespace('console'); + $dbForConsole->setNamespace('_console'); // Ensure tables exist $collections = Config::getParam('collections', [])['console']; @@ -74,7 +74,7 @@ CLI::setResource('dbForConsole', function ($pools, $cache) { $pools->get('console')->reclaim(); sleep($sleep); } - } while ($attempts < $maxAttempts); + } while ($attempts < $maxAttempts && !$ready); if (!$ready) { throw new Exception("Console is not ready yet. Please try again later."); @@ -116,6 +116,29 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, return $getProjectDB; }, ['pools', 'dbForConsole', 'cache']); +CLI::setResource('influxdb', function (Registry $register) { + $client = $register->get('influxdb'); /** @var InfluxDB\Client $client */ + $attempts = 0; + $max = 10; + $sleep = 1; + + do { // check if telegraf database is ready + try { + $attempts++; + $database = $client->selectDB('telegraf'); + if (in_array('telegraf', $client->listDatabases())) { + break; // leave the do-while if successful + } + } catch (\Throwable $th) { + Console::warning("InfluxDB not ready. Retrying connection ({$attempts})..."); + if ($attempts >= $max) { + throw new \Exception('InfluxDB database not ready yet'); + } + sleep($sleep); + } + } while ($attempts < $max); + return $database; +}, ['register']); CLI::setResource('queueForFunctions', function (Group $pools) { return new Func($pools->get('queue')->pop()->getResource()); diff --git a/app/config/cloud/contributors.json b/app/config/cloud/contributors.json deleted file mode 100644 index efa36c3cb2..0000000000 --- a/app/config/cloud/contributors.json +++ /dev/null @@ -1 +0,0 @@ -[1297371,1759475,6360216,20852629,5857008,19310830,9708641,26739219,23742426,22174310,77877486,1477010,29069505,62933155,45863583,42211,176163,58045728,7091609,31401437,1911066,66096031,22432834,43054051,79051850,22895284,100597998,91385411,49699333,7818620,11004008,54898623,27856297,33250853,49375670,30630364,50206,47822499,7481165,52557347,13681567,20492520,51369094,51821861,50256986,28431370,13692220,24373771,15938422,27148250,14805534,36137226,36071208,40193621,56179878,53281158,48085134,19358691,32528768,19733683,37348419,13719696,18309412,42106787,53618500,5306011,4408379,35486736,18586611,15062564,27011453,56090587,44623032,25107942,81188,33922418,16717633,32809211,69401139,25815659,4104127,20889958,3102249,12476526,2635185,28495651,50957556,2791280,31023616,20955511,835733,471907,69008866,44906587,45271396,76054330,45748739,41908747,23402178,47356149,8921,36632821,3668741,71702982,29725587,26303198,785830,51410502,60089135,2847349,43172716,48546075,8216525,41161981,51828039,4334997,80918302,38534289,47860497,80036766,41341387,49818988,58487637,29237374,46913894,5148229,4377199,29686102,26272249,75117692,4090256,27357868,33062368,38664231,46695441,743291,22633385,6368283,11593067,45097959,43381712,3284228,1972717,33012425,61755381,25405707,3144291,44156359,5497267,7423905,20716175,28586681,5975506,23518097,22187384,24191952,7768078,971530,51240166,55633427,34207400,77061285,11719476,35950229,66742927,34406802,802933,50047839,39148877,26602940,9693472,44273767,19362725,31209978,30521594,686298,6237394,35039730,42580581,36671793,8502129,8466918,81866614,54903252,28373606,13381361,72331432,30694270,5355510,8209163,86675510,9453522,42496309,56145786,2149381,393945,22084723,52621436,8872447,5575392,29619660,5547479,8852116,11151445,4717349,17725274,65615065,18537755,29292618,53044263,26597930,10313411,55998629,77529288,17404636,33729848,19422168,17916404,66111735,10329006,33502846,398230,81643826,105039167,47522632,91655303,9774614,10603631,284924,60857954,22885912,116552306,36103454,794606,27729549,1754457,36594527,13899668,78664749,47406531,27698189,5305654,53345517,6756412,29176704,77790497,47504894,37251540,52361778,52200375,1351177,66022861,73975409,25745396,31433638,37118134,43210805,20317665,11923975,47187468,16362381,36751163,14959876,32362757,65529384,52352285,74085816,3628535,43902034,75667593,26132902,466713,617558,96806061,33605526,11290524,43621940,12446314,17146935,55018955,56096559,79797000,40014186,34449936,58387964,23368207,42414965,44056349,33743031,12294525,58251592,33755729,9021747,932084,11428067,97121933,80122730,60894542,58583793,56051809,32243289,9934371,90936802,74638775,65399526,77604,64524822,47782249,43633955,42793632,55969597,72334601,82395440,92818577,60866204,65016769,23725091,45892107,55308895,86314140,82756460,47685349,63562160,73419211,1613216,50882624,91469717,46166258,60927324,41763158,83607556,2171717,50497814,39427312,61322830,40076195,39419448,29397545,55090719,53259730,20885012,64558515,69677883,55741087,72426535,46033036,68477507,30376878,73700530,25518600,29922887,36229969,47573417,40424087,49054503,16880385,22801227,72848513,64347914,814402,49149679,55017867,49481876,67067955,31439735,63878173,80322286,43746210,17332970,22702905,62476876,89888292,75736952,54059881,90782137,63588969,57111920,63330165,70258211,46371923,17837758,59364507,52203828,60147326,18481195,74822422,9803078,67309607,60410049,47360939,19922556,90848252,24698014,58886915,63579762,96648934,68523530,60518745,37345795,3929651,54993657,52061363,43019989,5787917,94674993,71593494,17143469,10288548,1830380,71510505,59124772,2335145,70798495,46474346,49263351,52062536,63151043,65248303,26071571,53626355,43992469,60785452,63467479,71837281,19490891,58628586,38250310,7271718,1110414,57227290,11625672,85063520,88965873,70096901,42029519,85363195,64471630,69353350,66922161,2221746,100430077,12299813,62690310,68282006,99184676,2450,22989561,22212661,59973863,11232940,76688923,22321353,77732479,84286404,32268377,34828782,23068019,57074509,24620969,20735983,26173690,75809937,49760818,86646105,52617262] \ No newline at end of file diff --git a/app/config/cloud/employees.json b/app/config/cloud/employees.json deleted file mode 100644 index 1575a05883..0000000000 --- a/app/config/cloud/employees.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "eldad@appwrite.io": { "memberSince": "2020-10-15", "spot": "0", "gitHub": "eldadfux" }, - "christy@appwrite.io": { "memberSince": "2020-12-01", "spot": "1", "gitHub": "christyjacob4" }, - "torsten@appwrite.io": { "memberSince": "2020-12-28", "spot": "2", "gitHub": "torstendittmann" }, - "damodar@appwrite.io": { "memberSince": "2021-01-02", "spot": "3", "gitHub": "lohanidamodar" }, - "bradley@appwrite.io": { "memberSince": "2021-05-21", "spot": "5", "gitHub": "PineappleIOnic" }, - "jake@appwrite.io": { "memberSince": "2021-06-28", "spot": "6", "gitHub": "abnegate" }, - "sara@appwrite.io": { "memberSince": "2021-08-16", "spot": "7", "gitHub": "sarakaandorp" }, - "matej@appwrite.io": { "memberSince": "2021-08-23", "spot": "8", "gitHub": "meldiron" }, - "aditya@appwrite.io": { "memberSince": "2021-09-01", "spot": "9", "gitHub": "adityaoberai" }, - "wess@appwrite.io": { "memberSince": "2021-11-08", "spot": "12", "gitHub": "wess" }, - "may@appwrite.io": { "memberSince": "2021-11-28", "spot": "14", "gitHub": "MayEnder" }, - "elad@appwrite.io": { "memberSince": "2021-12-19", "spot": "15", "gitHub": "elad2412" }, - "vincent@appwrite.io": { "memberSince": "2022-01-01", "spot": "16", "gitHub": "gewenyu99" }, - "haimantika@appwrite.io": { "memberSince": "2022-04-01", "spot": "18", "gitHub": "Haimantika" }, - "chen@appwrite.io": { "memberSince": "2022-01-24", "spot": "19", "gitHub": "chenparnasa" }, - "tessa@appwrite.io": { "memberSince": "2022-04-21", "spot": "20", "gitHub": "tessamero" }, - "shimon@appwrite.io": { "memberSince": "2022-05-01", "spot": "23", "gitHub": "shimonewman" }, - "shmuel@appwrite.io": { "memberSince": "2022-03-20", "spot": "24", "gitHub": "fogelito" }, - "arman@appwrite.io": { "memberSince": "2022-04-04", "spot": "25", "gitHub": "ArmanNik" }, - "carla@appwrite.io": { "memberSince": "2022-04-04", "spot": "26", "gitHub": "heyCarla" }, - "emma@appwrite.io": { "memberSince": "2022-05-08", "spot": "27", "gitHub": "emmacarpagnano1" }, - "dylan@appwrite.io": { "memberSince": "2022-05-09", "spot": "28", "gitHub": "DylanG-64" }, - "steven@appwrite.io": { "memberSince": "2022-07-01", "spot": "30", "gitHub": "stnguyen90" }, - "jyoti@appwrite.io": { "memberSince": "2022-10-24", "spot": "31", "gitHub": "joeyouss" }, - "jade@appwrite.io": { "memberSince": "2022-10-31", "spot": "32", "gitHub": "dajebp" }, - "khushboo@appwrite.io": { "memberSince": "2021-11-08", "spot": "13", "gitHub": "vermakhushboo" }, - "thomas@appwrite.io": { "memberSince": "2022-11-03", "spot": "34", "gitHub": "TGlide" }, - "holly@appwrite.io": { "memberSince": "2022-12-05", "spot": "35", "gitHub": "HollyBarclay" }, - "laura@appwrite.io": { "memberSince": "2023-01-25", "spot": "36", "gitHub": "LauraDuRy" }, - "caio@appwrite.io": { "memberSince": "2023-03-27", "spot": "37", "gitHub": "ariascaio" }, - "luke@appwrite.io": { "memberSince": "2023-05-04", "spot": "38", "gitHub": "loks0n" } -} diff --git a/app/config/cloud/heroes.json b/app/config/cloud/heroes.json deleted file mode 100644 index 3fc81b3b3f..0000000000 --- a/app/config/cloud/heroes.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "bishwajeet.techmaster@gmail.com": { "memberSince": "2023-02-07" }, - "lucasaudart@gmail.com": { "memberSince": "2023-02-07" }, - "tkarmakar27112000@gmail.com": { "memberSince": "2023-02-07" }, - "alves.mckl@gmail.com": { "memberSince": "2023-02-07" }, - "dpns_nampula@rnlay.com": { "memberSince": "2023-02-07" }, - "a.stephensimon@outlook.com": { "memberSince": "2023-02-07" }, - "hidianapham@gmail.com": { "memberSince": "2023-02-07" } -} diff --git a/app/config/collections.php b/app/config/collections.php index 15effbf5ae..79f1622574 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -253,7 +253,7 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => ['datetime'], - ], + ] ], 'indexes' => [ [ @@ -700,6 +700,172 @@ $commonCollections = [ ], ], + 'identities' => [ + '$collection' => ID::custom(Database::METADATA), + '$id' => ID::custom('identities'), + 'name' => 'Identities', + 'attributes' => [ + [ + '$id' => ID::custom('userInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('provider'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerUid'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerEmail'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 320, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerAccessToken'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['encrypt'], + ], + [ + '$id' => ID::custom('providerAccessTokenExpiry'), + 'type' => Database::VAR_DATETIME, + 'format' => '', + 'size' => 0, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['datetime'], + ], + [ + '$id' => ID::custom('providerRefreshToken'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['encrypt'], + ], + [ + // Used to store data from provider that may or may not be sensitive + '$id' => ID::custom('secrets'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => [], + 'array' => false, + 'filters' => ['json', 'encrypt'], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_userInternalId_provider_providerUid'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['userInternalId', 'provider', 'providerUid'], + 'lengths' => [Database::LENGTH_KEY, 100, 385], + 'orders' => [Database::ORDER_ASC, Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_provider_providerUid'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['provider', 'providerUid'], + 'lengths' => [100, 640], + 'orders' => [Database::ORDER_ASC, Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_provider'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['provider'], + 'lengths' => [100], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerUid'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerUid'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerEmail'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerEmail'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerAccessTokenExpiry'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerAccessTokenExpiry'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + ], + ], + 'teams' => [ '$collection' => ID::custom(Database::METADATA), '$id' => ID::custom('teams'), @@ -1061,14 +1227,14 @@ $commonCollections = [ 'type' => Database::INDEX_FULLTEXT, 'attributes' => ['name'], 'lengths' => [], - 'orders' => [Database::ORDER_ASC], + 'orders' => [], ], [ '$id' => ID::custom('_key_search'), 'type' => Database::INDEX_FULLTEXT, 'attributes' => ['search'], 'lengths' => [], - 'orders' => [Database::ORDER_ASC], + 'orders' => [], ], [ '$id' => ID::custom('_key_enabled'), @@ -1147,7 +1313,7 @@ $commonCollections = [ 'type' => Database::VAR_INTEGER, 'format' => '', 'size' => 8, - 'signed' => true, + 'signed' => false, 'required' => true, 'default' => null, 'array' => false, @@ -1175,6 +1341,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('type'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 1, + 'signed' => false, + 'required' => true, + 'default' => 0, // 0 -> count, 1 -> sum + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ @@ -1193,47 +1370,8 @@ $commonCollections = [ ], [ '$id' => ID::custom('_key_metric_period_time'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['metric', 'period', 'time'], - 'lengths' => [], - 'orders' => [Database::ORDER_DESC], - ], - ], - ], - - 'statsLogger' => [ - '$collection' => ID::custom(Database::METADATA), - '$id' => ID::custom('statsLogger'), - 'name' => 'StatsLogger', - 'attributes' => [ - [ - '$id' => ID::custom('time'), - 'type' => Database::VAR_DATETIME, - 'format' => '', - 'size' => 0, - 'signed' => false, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => ['datetime'], - ], - [ - '$id' => ID::custom('metrics'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 5012, - 'signed' => true, - 'required' => false, - 'default' => [], - 'array' => false, - 'filters' => ['json'], - ], - ], - 'indexes' => [ - [ - '$id' => ID::custom('_key_time'), 'type' => Database::INDEX_KEY, - 'attributes' => ['time'], + 'attributes' => ['metric', 'period', 'time'], 'lengths' => [], 'orders' => [Database::ORDER_DESC], ], @@ -1278,6 +1416,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('default'), + 'type' => Database::VAR_BOOLEAN, + 'signed' => true, + 'size' => 0, + 'format' => '', + 'filters' => [], + 'required' => false, + 'default' => false, + 'array' => false, + ], [ '$id' => ID::custom('credentials'), 'type' => Database::VAR_STRING, @@ -1498,6 +1647,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('targets'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['subQueryTopicTargets'], + ] ], 'indexes' => [ [ @@ -1536,28 +1696,6 @@ $commonCollections = [ '$id' => ID::custom('subscribers'), 'name' => 'Subscribers', 'attributes' => [ - [ - '$id' => ID::custom('userId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('userInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('targetId'), 'type' => Database::VAR_STRING, @@ -1604,20 +1742,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_userId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_userInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userInternalId'], - 'lengths' => [128], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_targetId'), 'type' => Database::INDEX_KEY, @@ -1704,16 +1828,16 @@ $commonCollections = [ 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, - 'filters' => [], + 'filters' => ['subQueryProviderType'], ], [ '$id' => ID::custom('identifier'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 2048, + 'size' => Database::LENGTH_KEY, 'signed' => true, 'required' => true, 'default' => null, @@ -1749,16 +1873,9 @@ $commonCollections = [ 'attributes' => ['providerInternalId'], 'lengths' => [], 'orders' => [], - ], - [ - '$id' => ID::custom('_key_providerType'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerType'], - 'lengths' => [], - 'orders' => [], - ], + ] ], - ] + ], ]; $projectCollections = array_merge([ @@ -2190,6 +2307,109 @@ $projectCollections = array_merge([ 'required' => true, 'array' => false, ], + [ + '$id' => ID::custom('live'), + 'type' => Database::VAR_BOOLEAN, + 'signed' => true, + 'size' => 0, + 'format' => '', + 'filters' => [], + 'required' => true, + 'array' => false, + ], + [ + '$id' => ID::custom('installationId'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('installationInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerRepositoryId'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('repositoryId'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('repositoryInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerBranch'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerRootDirectory'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerSilentMode'), + 'type' => Database::VAR_BOOLEAN, + 'signed' => true, + 'size' => 0, + 'format' => '', + 'filters' => [], + 'required' => false, + 'default' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('logging'), + 'type' => Database::VAR_BOOLEAN, + 'signed' => true, + 'size' => 0, + 'format' => '', + 'filters' => [], + 'required' => true, + 'array' => false, + ], [ '$id' => ID::custom('runtime'), 'type' => Database::VAR_STRING, @@ -2207,7 +2427,7 @@ $projectCollections = array_merge([ 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -2251,7 +2471,7 @@ $projectCollections = array_merge([ 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -2300,6 +2520,39 @@ $projectCollections = array_merge([ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('version'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 8, + 'signed' => true, + 'required' => false, + 'default' => 'v3', + 'array' => false, + 'filters' => [], + ], + [ + 'array' => false, + '$id' => ID::custom('entrypoint'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'filters' => [], + ], + [ + 'array' => false, + '$id' => ID::custom('commands'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'filters' => [], + ] ], 'indexes' => [ [ @@ -2307,7 +2560,7 @@ $projectCollections = array_merge([ 'type' => Database::INDEX_FULLTEXT, 'attributes' => ['search'], 'lengths' => [], - 'orders' => [Database::ORDER_ASC], + 'orders' => [], ], [ '$id' => ID::custom('_key_name'), @@ -2323,6 +2576,41 @@ $projectCollections = array_merge([ 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], + [ + '$id' => ID::custom('_key_installationId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['installationId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_installationInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['installationInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerRepositoryId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerRepositoryId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_repositoryId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['repositoryId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_repositoryInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['repositoryInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], [ '$id' => ID::custom('_key_runtime'), 'type' => Database::INDEX_KEY, @@ -2336,21 +2624,7 @@ $projectCollections = array_merge([ 'attributes' => ['deployment'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_schedule'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['schedule'], - 'lengths' => [], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_timeout'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['timeout'], - 'lengths' => [], - 'orders' => [Database::ORDER_ASC], - ], + ] ], ], @@ -2365,7 +2639,7 @@ $projectCollections = array_merge([ 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -2398,7 +2672,7 @@ $projectCollections = array_merge([ 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -2425,6 +2699,17 @@ $projectCollections = array_merge([ 'default' => null, 'filters' => [], ], + [ + 'array' => false, + '$id' => ID::custom('commands'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => false, + 'default' => null, + 'filters' => [], + ], [ '$id' => ID::custom('path'), 'type' => Database::VAR_STRING, @@ -2436,6 +2721,188 @@ $projectCollections = array_merge([ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('type'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('installationId'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('installationInternalId'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerRepositoryId'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('repositoryId'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('repositoryInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerRepositoryName'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerRepositoryOwner'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerRepositoryUrl'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerCommitHash'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerCommitAuthorUrl'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerCommitAuthor'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerCommitMessage'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerCommitUrl'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerBranch'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerBranchUrl'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerRootDirectory'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => Database::LENGTH_KEY, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], + [ + '$id' => ID::custom('providerCommentId'), + 'type' => Database::VAR_STRING, + 'signed' => true, + 'size' => 2048, + 'format' => '', + 'filters' => [], + 'required' => false, + 'array' => false, + ], [ '$id' => ID::custom('size'), 'type' => Database::VAR_INTEGER, @@ -2525,13 +2992,6 @@ $projectCollections = array_merge([ 'lengths' => [], 'orders' => [], ], - [ - '$id' => ID::custom('_key_entrypoint'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['entrypoint'], - 'lengths' => [768], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_size'), 'type' => Database::INDEX_KEY, @@ -2595,12 +3055,23 @@ $projectCollections = array_merge([ 'filters' => [], ], [ - '$id' => 'deploymentInternalId', + '$id' => ID::custom('size'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('deploymentInternalId'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -2639,7 +3110,7 @@ $projectCollections = array_merge([ 'filters' => [], ], [ - '$id' => ID::custom('outputPath'), + '$id' => ID::custom('path'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => 2048, @@ -2650,18 +3121,7 @@ $projectCollections = array_merge([ 'filters' => [], ], [ - '$id' => ID::custom('stderr'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 1000000, - 'signed' => true, - 'required' => false, - 'default' => '', - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('stdout'), + '$id' => ID::custom('logs'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => 1000000, @@ -2716,7 +3176,7 @@ $projectCollections = array_merge([ 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -2738,7 +3198,7 @@ $projectCollections = array_merge([ 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -2777,7 +3237,18 @@ $projectCollections = array_merge([ 'filters' => [], ], [ - '$id' => ID::custom('response'), + '$id' => ID::custom('duration'), + 'type' => Database::VAR_FLOAT, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('errors'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => 1000000, @@ -2788,7 +3259,7 @@ $projectCollections = array_merge([ 'filters' => [], ], [ - '$id' => ID::custom('stderr'), + '$id' => ID::custom('logs'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => 1000000, @@ -2799,18 +3270,40 @@ $projectCollections = array_merge([ 'filters' => [], ], [ - '$id' => ID::custom('stdout'), + 'array' => false, + '$id' => ID::custom('requestMethod'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 1000000, + 'size' => 128, + 'signed' => true, + 'required' => false, + 'default' => null, + 'filters' => [], + ], + [ + 'array' => false, + '$id' => ID::custom('requestPath'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 2048, + 'signed' => true, + 'required' => false, + 'default' => null, + 'filters' => [], + ], + [ + '$id' => ID::custom('requestHeaders'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, 'signed' => true, 'required' => false, 'default' => null, 'array' => false, - 'filters' => [], + 'filters' => ['json'], ], [ - '$id' => ID::custom('statusCode'), + '$id' => ID::custom('responseStatusCode'), 'type' => Database::VAR_INTEGER, 'format' => '', 'size' => 0, @@ -2821,15 +3314,15 @@ $projectCollections = array_merge([ 'filters' => [], ], [ - '$id' => ID::custom('duration'), - 'type' => Database::VAR_FLOAT, + '$id' => ID::custom('responseHeaders'), + 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 0, + 'size' => 16384, 'signed' => true, 'required' => false, 'default' => null, 'array' => false, - 'filters' => [], + 'filters' => ['json'], ], [ '$id' => ID::custom('search'), @@ -2873,9 +3366,9 @@ $projectCollections = array_merge([ 'orders' => [Database::ORDER_ASC], ], [ - '$id' => ID::custom('_key_statusCode'), + '$id' => ID::custom('_key_responseStatusCode'), 'type' => Database::INDEX_KEY, - 'attributes' => ['statusCode'], + 'attributes' => ['responseStatusCode'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], @@ -2889,99 +3382,6 @@ $projectCollections = array_merge([ ], ], - 'variables' => [ - '$collection' => Database::METADATA, - '$id' => 'variables', - 'name' => 'variables', - 'attributes' => [ - [ - '$id' => 'functionInternalId', - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => 'functionId', - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => 'key', - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => 'value', - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 8192, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [ 'encrypt' ] - ], - [ - '$id' => ID::custom('search'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 16384, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - ], - 'indexes' => [ - [ - '$id' => '_key_function', - 'type' => Database::INDEX_KEY, - 'attributes' => ['functionInternalId'], - 'lengths' => [Database::LENGTH_KEY], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => '_key_uniqueKey', - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['functionInternalId', 'key'], - 'lengths' => [Database::LENGTH_KEY, Database::LENGTH_KEY], - 'orders' => [Database::ORDER_ASC, Database::ORDER_ASC], - ], - [ - '$id' => '_key_key', - 'type' => Database::INDEX_KEY, - 'attributes' => ['key'], - 'lengths' => [Database::LENGTH_KEY], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_fulltext_search'), - 'type' => Database::INDEX_FULLTEXT, - 'attributes' => ['search'], - 'lengths' => [], - 'orders' => [], - ], - ], - ], - 'cache' => [ '$collection' => Database::METADATA, '$id' => 'cache', @@ -3020,7 +3420,7 @@ $projectCollections = array_merge([ 'array' => false, 'filters' => [], ], - ], + ], 'indexes' => [ [ '$id' => '_key_accessedAt', @@ -3038,6 +3438,261 @@ $projectCollections = array_merge([ ], ], ], + + 'variables' => [ + '$collection' => Database::METADATA, + '$id' => 'variables', + 'name' => 'variables', + 'attributes' => [ + [ + '$id' => ID::custom('resourceType'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 100, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('resourceInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('resourceId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => 'key', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => 'value', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 8192, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => ['encrypt'] + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => '_key_resourceInternalId', + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [], + ], + [ + '$id' => '_key_resourceType', + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceType'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => '_key_resourceId_resourceType', + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceId', 'resourceType'], + 'lengths' => [Database::LENGTH_KEY, 100], + 'orders' => [Database::ORDER_ASC, Database::ORDER_ASC], + ], + [ + '$id' => '_key_uniqueKey', + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['resourceId', 'key', 'resourceType'], + 'lengths' => [Database::LENGTH_KEY, Database::LENGTH_KEY, 100], + 'orders' => [Database::ORDER_ASC, Database::ORDER_ASC, Database::ORDER_ASC], + ], + [ + '$id' => '_key_key', + 'type' => Database::INDEX_KEY, + 'attributes' => ['key'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_fulltext_search'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['search'], + 'lengths' => [], + 'orders' => [], + ], + ], + ], + + 'migrations' => [ + '$collection' => ID::custom(Database::METADATA), + '$id' => ID::custom('migrations'), + 'name' => 'Migrations', + 'attributes' => [ + [ + '$id' => ID::custom('status'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('stage'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('source'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 8192, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('credentials'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 65536, + 'signed' => true, + 'required' => false, + 'default' => [], + 'array' => false, + 'filters' => ['json', 'encrypt'], + ], + [ + '$id' => ID::custom('resources'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => [], + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('statusCounters'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 3000, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => ['json'], + ], + [ + '$id' => ID::custom('resourceData'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 131070, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => ['json'], + ], + [ + '$id' => ID::custom('errors'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 65535, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ] + ], + 'indexes' => [ + [ + '$id' => '_key_status', + 'type' => Database::INDEX_KEY, + 'attributes' => ['status'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => '_key_stage', + 'type' => Database::INDEX_KEY, + 'attributes' => ['stage'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => '_key_source', + 'type' => Database::INDEX_KEY, + 'attributes' => ['source'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_fulltext_search'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['search'], + 'lengths' => [], + 'orders' => [], + ] + ], + ], ], $commonCollections); $consoleCollections = array_merge([ @@ -3299,17 +3954,6 @@ $consoleCollections = array_merge([ 'array' => false, 'filters' => ['subQueryKeys'], ], - [ - '$id' => ID::custom('domains'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 16384, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => ['subQueryDomains'], - ], [ '$id' => ID::custom('search'), 'type' => Database::VAR_STRING, @@ -3445,7 +4089,7 @@ $consoleCollections = array_merge([ [ '$id' => ID::custom('_key_region_resourceType_resourceUpdatedAt'), 'type' => Database::INDEX_KEY, - 'attributes' => ['region', 'resourceType','resourceUpdatedAt'], + 'attributes' => ['region', 'resourceType', 'resourceUpdatedAt'], 'lengths' => [], 'orders' => [], ], @@ -3553,111 +4197,6 @@ $consoleCollections = array_merge([ ], ], - 'domains' => [ - '$collection' => ID::custom(Database::METADATA), - '$id' => ID::custom('domains'), - 'name' => 'domains', - 'attributes' => [ - [ - '$id' => ID::custom('projectInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('projectId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('updated'), - 'type' => Database::VAR_DATETIME, - 'format' => '', - 'size' => 0, - 'signed' => false, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => ['datetime'], - ], - [ - '$id' => ID::custom('domain'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('tld'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('registerable'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('verification'), - 'type' => Database::VAR_BOOLEAN, - 'format' => '', - 'size' => 0, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('certificateId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - ], - 'indexes' => [ - [ - '$id' => ID::custom('_key_project'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['projectInternalId'], - 'lengths' => [Database::LENGTH_KEY], - 'orders' => [Database::ORDER_ASC], - ], - ], - ], - 'keys' => [ '$collection' => ID::custom(Database::METADATA), '$id' => ID::custom('keys'), @@ -3939,10 +4478,10 @@ $consoleCollections = array_merge([ 'filters' => [], ], [ - '$id' => ID::custom('log'), + '$id' => ID::custom('logs'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 16384, + 'size' => 1000000, 'signed' => true, 'required' => false, 'default' => null, @@ -4021,6 +4560,564 @@ $consoleCollections = array_merge([ ], ] ], + + 'rules' => [ + '$collection' => ID::custom(Database::METADATA), + '$id' => ID::custom('rules'), + 'name' => 'Rules', + 'attributes' => [ + [ + '$id' => ID::custom('projectId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('projectInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('domain'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('resourceType'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 100, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('resourceInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('resourceId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('status'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('certificateId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ] + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_domain'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['domain'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_projectInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['projectInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_projectId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['projectId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => '_key_resourceInternalId', + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => '_key_resourceId', + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => '_key_resourceType', + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceType'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + ], + ], + + 'installations' => [ + '$collection' => ID::custom(Database::METADATA), + '$id' => ID::custom('installations'), + 'name' => 'installations', + 'attributes' => [ + [ + '$id' => ID::custom('projectId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('projectInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerInstallationId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('organization'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('provider'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('personal'), + 'type' => Database::VAR_BOOLEAN, + 'signed' => true, + 'size' => 0, + 'format' => '', + 'filters' => [], + 'required' => false, + 'default' => false, + 'array' => false, + ], + ], + 'indexes' => [ + + [ + '$id' => ID::custom('_key_projectInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['projectInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_projectId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['projectId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerInstallationId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerInstallationId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + ], + ], + + 'repositories' => [ + '$collection' => ID::custom(Database::METADATA), + '$id' => ID::custom('repositories'), + 'name' => 'repositories', + 'attributes' => [ + [ + '$id' => ID::custom('installationId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => ID::custom('installationInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('projectId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => ID::custom('projectInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerRepositoryId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => ID::custom('resourceId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('resourceInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('resourceType'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => ID::custom('providerPullRequestIds'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => true, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_installationId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['installationId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_installationInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['installationInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_projectInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['projectInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_projectId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['projectId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerRepositoryId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerRepositoryId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_resourceId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => '_key_resourceInternalId', + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_resourceType'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceType'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ] + ], + ], + + 'vcsComments' => [ + '$collection' => ID::custom(Database::METADATA), + '$id' => ID::custom('vcsComments'), + 'name' => 'vcsComments', + 'attributes' => [ + [ + '$id' => ID::custom('installationId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => ID::custom('installationInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('projectId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => ID::custom('projectInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerRepositoryId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => ID::custom('providerCommentId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => ID::custom('providerPullRequestId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => ID::custom('providerBranch'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_installationId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['installationId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_installationInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['installationInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_projectInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['projectInternalId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_projectId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['projectId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerRepositoryId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerRepositoryId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerPullRequestId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerPullRequestId'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_providerBranch'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['providerBranch'], + 'lengths' => [Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC], + ], + ], + ], + + 'vcsCommentLocks' => [ + '$collection' => ID::custom(Database::METADATA), + '$id' => ID::custom('vcsCommentLocks'), + 'name' => 'vcsCommentLocks', + 'attributes' => [], + 'indexes' => [] + ], ], $commonCollections); $bucketCollections = [ @@ -4234,7 +5331,7 @@ $bucketCollections = [ 'type' => Database::INDEX_FULLTEXT, 'attributes' => ['search'], 'lengths' => [], - 'orders' => [Database::ORDER_ASC], + 'orders' => [], ], [ '$id' => ID::custom('_key_bucket'), @@ -4408,7 +5505,7 @@ $dbCollections = [ 'orders' => [Database::ORDER_ASC], ], ], - ], + ] ]; diff --git a/app/config/errors.php b/app/config/errors.php index ed1a9f0aa2..ea95e5dfbe 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -98,6 +98,11 @@ return [ 'description' => 'Usage stats is not configured. Please check the value of the _APP_USAGE_STATS environment variable of your Appwrite server.', 'code' => 501, ], + Exception::GENERAL_NOT_IMPLEMENTED => [ + 'name' => Exception::GENERAL_NOT_IMPLEMENTED, + 'description' => 'This method was not fully implemented yet. If you believe this is a mistake, please upgrade your Appwrite server version.', + 'code' => 405, + ], /** User Errors */ Exception::USER_COUNT_EXCEEDED => [ @@ -112,12 +117,12 @@ return [ ], Exception::USER_ALREADY_EXISTS => [ 'name' => Exception::USER_ALREADY_EXISTS, - 'description' => 'A user with the same id, email, or phone already exists in your project.', + 'description' => 'A user with the same id, email, or phone already exists in this project.', 'code' => 409, ], Exception::USER_BLOCKED => [ 'name' => Exception::USER_BLOCKED, - 'description' => 'The current user has been blocked.', + 'description' => 'The current user has been blocked. You can unblock the user by making a request to the User API\'s "Update User Status" endpoint or in the Appwrite Console\'s Auth section.', 'code' => 401, ], Exception::USER_INVALID_TOKEN => [ @@ -177,12 +182,12 @@ return [ ], Exception::USER_PASSWORD_RECENTLY_USED => [ 'name' => Exception::USER_PASSWORD_RECENTLY_USED, - 'description' => 'The password you are trying to use is similar to your previous password. Please choose a stronger password.', + 'description' => 'The password you are trying to use is similar to your previous password. For your security, please choose a different password and try again.', 'code' => 400, ], Exception::USER_PASSWORD_PERSONAL_DATA => [ 'name' => Exception::USER_PASSWORD_PERSONAL_DATA, - 'description' => 'The password you are trying to use contains references to your name, email, phone or userID. Please choose a different password and try again.', + 'description' => 'The password you are trying to use contains references to your name, email, phone or userID. For your security, please choose a different password and try again.', 'code' => 400, ], Exception::USER_SESSION_NOT_FOUND => [ @@ -190,6 +195,11 @@ return [ 'description' => 'The current user session could not be found.', 'code' => 404, ], + Exception::USER_IDENTITY_NOT_FOUND => [ + 'name' => Exception::USER_IDENTITY_NOT_FOUND, + 'description' => 'The identity could not be found. Please sign in with OAuth provider to create identity first.', + 'code' => 404, + ], Exception::USER_UNAUTHORIZED => [ 'name' => Exception::USER_UNAUTHORIZED, 'description' => 'The current user is not authorized to perform the requested action.', @@ -249,7 +259,7 @@ return [ ], Exception::TEAM_INVALID_SECRET => [ 'name' => Exception::TEAM_INVALID_SECRET, - 'description' => 'The team invitation secret is invalid.', + 'description' => 'The team invitation secret is invalid. Please request a new invitation and try again.', 'code' => 401, ], Exception::TEAM_MEMBERSHIP_MISMATCH => [ @@ -264,7 +274,7 @@ return [ ], Exception::TEAM_ALREADY_EXISTS => [ 'name' => Exception::TEAM_ALREADY_EXISTS, - 'description' => 'Team with requested ID already exists.', + 'description' => 'Team with requested ID already exists. Please choose a different ID and try again.', 'code' => 409, ], @@ -276,7 +286,7 @@ return [ ], Exception::MEMBERSHIP_ALREADY_CONFIRMED => [ 'name' => Exception::MEMBERSHIP_ALREADY_CONFIRMED, - 'description' => 'Membership already confirmed', + 'description' => 'Membership is already confirmed.', 'code' => 409, ], @@ -308,6 +318,11 @@ return [ ], /** Storage */ + Exception::STORAGE_FILE_ALREADY_EXISTS => [ + 'name' => Exception::STORAGE_FILE_ALREADY_EXISTS, + 'description' => 'A storage file with the requested ID already exists.', + 'code' => 409, + ], Exception::STORAGE_FILE_NOT_FOUND => [ 'name' => Exception::STORAGE_FILE_NOT_FOUND, 'description' => 'The requested file could not be found.', @@ -340,7 +355,7 @@ return [ ], Exception::STORAGE_BUCKET_ALREADY_EXISTS => [ 'name' => Exception::STORAGE_BUCKET_ALREADY_EXISTS, - 'description' => 'A storage bucket with the requested ID already exists.', + 'description' => 'A storage bucket with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.', 'code' => 409, ], Exception::STORAGE_BUCKET_NOT_FOUND => [ @@ -360,7 +375,34 @@ return [ ], Exception::STORAGE_INVALID_APPWRITE_ID => [ 'name' => Exception::STORAGE_INVALID_APPWRITE_ID, - 'description' => 'The value for x-appwrite-id header is invalid. Please check the value of the x-appwrite-id header is valid id and not unique().', + 'description' => 'The value for x-appwrite-id header is invalid. Please check the value of the x-appwrite-id header is a valid id and not unique().', + 'code' => 400, + ], + + /** VCS */ + Exception::INSTALLATION_NOT_FOUND => [ + 'name' => Exception::INSTALLATION_NOT_FOUND, + 'description' => 'Installation with the requested ID could not be found. Check to see if the ID is correct, or create the installation.', + 'code' => 404, + ], + Exception::PROVIDER_REPOSITORY_NOT_FOUND => [ + 'name' => Exception::PROVIDER_REPOSITORY_NOT_FOUND, + 'description' => 'VCS (Version Control System) repository with the requested ID could not be found. Check to see if the ID is correct, and if it belongs to installationId you provided.', + 'code' => 404, + ], + Exception::REPOSITORY_NOT_FOUND => [ + 'name' => Exception::REPOSITORY_NOT_FOUND, + 'description' => 'Repository with the requested ID could not be found. Check to see if the ID is correct, or create the respository.', + 'code' => 404, + ], + Exception::PROVIDER_CONTRIBUTION_CONFLICT => [ + 'name' => Exception::PROVIDER_CONTRIBUTION_CONFLICT, + 'description' => 'External contribution is already authorized.', + 'code' => 409, + ], + Exception::GENERAL_PROVIDER_FAILURE => [ + 'name' => Exception::GENERAL_PROVIDER_FAILURE, + 'description' => 'VCS (Version Control System) provider failed to proccess the request. We believe this is an error with the VCS provider. Try again, or contact support for more information.', 'code' => 400, ], @@ -375,6 +417,11 @@ return [ 'description' => 'The requested runtime is either inactive or unsupported. Please check the value of the _APP_FUNCTIONS_RUNTIMES environment variable.', 'code' => 404, ], + Exception::FUNCTION_ENTRYPOINT_MISSING => [ + 'name' => Exception::FUNCTION_RUNTIME_UNSUPPORTED, + 'description' => 'Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".', + 'code' => 404, + ], /** Builds */ Exception::BUILD_NOT_FOUND => [ @@ -428,7 +475,7 @@ return [ ], Exception::COLLECTION_ALREADY_EXISTS => [ 'name' => Exception::COLLECTION_ALREADY_EXISTS, - 'description' => 'A collection with the requested ID already exists.', + 'description' => 'A collection with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.', 'code' => 409, ], Exception::COLLECTION_LIMIT_EXCEEDED => [ @@ -450,17 +497,17 @@ return [ ], Exception::DOCUMENT_MISSING_DATA => [ 'name' => Exception::DOCUMENT_MISSING_DATA, - 'description' => 'The document data is missing. You must provide the document data.', + 'description' => 'The document data is missing. Try again with document data populated', 'code' => 400, ], Exception::DOCUMENT_MISSING_PAYLOAD => [ 'name' => Exception::DOCUMENT_MISSING_PAYLOAD, - 'description' => 'The document data and permissions are missing. You must provide either the document data or permissions to be updated.', + 'description' => 'The document data and permissions are missing. You must provide either document data or permissions to be updated.', 'code' => 400, ], Exception::DOCUMENT_ALREADY_EXISTS => [ 'name' => Exception::DOCUMENT_ALREADY_EXISTS, - 'description' => 'Document with the requested ID already exists.', + 'description' => 'Document with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.', 'code' => 409, ], Exception::DOCUMENT_UPDATE_CONFLICT => [ @@ -502,7 +549,7 @@ return [ ], Exception::ATTRIBUTE_ALREADY_EXISTS => [ 'name' => Exception::ATTRIBUTE_ALREADY_EXISTS, - 'description' => 'Attribute with the requested ID already exists.', + 'description' => 'Attribute with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.', 'code' => 409, ], Exception::ATTRIBUTE_LIMIT_EXCEEDED => [ @@ -534,7 +581,7 @@ return [ ], Exception::INDEX_ALREADY_EXISTS => [ 'name' => Exception::INDEX_ALREADY_EXISTS, - 'description' => 'Index with the requested ID already exists.', + 'description' => 'Index with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.', 'code' => 409, ], Exception::INDEX_INVALID => [ @@ -551,7 +598,7 @@ return [ ], Exception::PROJECT_ALREADY_EXISTS => [ 'name' => Exception::PROJECT_ALREADY_EXISTS, - 'description' => 'Project with the requested ID already exists.', + 'description' => 'Project with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.', 'code' => 409, ], Exception::PROJECT_UNKNOWN => [ @@ -589,14 +636,44 @@ return [ 'description' => 'The project key has expired. Please generate a new key using the Appwrite console.', 'code' => 401, ], + Exception::ROUTER_HOST_NOT_FOUND => [ + 'name' => Exception::ROUTER_HOST_NOT_FOUND, + 'description' => 'Host is not trusted. This could occur because you have not configured a custom domain. Add a custom domain to your project first and try again.', + 'code' => 404, + ], + Exception::ROUTER_DOMAIN_NOT_CONFIGURED => [ + 'name' => Exception::ROUTER_DOMAIN_NOT_CONFIGURED, + 'description' => 'Domain environment variables not configured. Please configure domain environment variables before using Appwrite outside of localhost.', + 'code' => 500, + ], + Exception::RULE_RESOURCE_NOT_FOUND => [ + 'name' => Exception::RULE_RESOURCE_NOT_FOUND, + 'description' => 'Resource could not be found. Please check if the resourceId and resourceType are correct, or if the resource actually exists.', + 'code' => 404, + ], + Exception::RULE_NOT_FOUND => [ + 'name' => Exception::RULE_NOT_FOUND, + 'description' => 'Rule with the requested ID could not be found. Please check if the ID provided is correct or if the rule actually exists.', + 'code' => 404, + ], + Exception::RULE_ALREADY_EXISTS => [ + 'name' => Exception::RULE_ALREADY_EXISTS, + 'description' => 'Domain is already used. Please try again with a different domain.', + 'code' => 409, + ], + Exception::RULE_VERIFICATION_FAILED => [ + 'name' => Exception::RULE_VERIFICATION_FAILED, + 'description' => 'Domain verification failed. Please check if your DNS records are correct and try again.', + 'code' => 401, + ], Exception::PROJECT_SMTP_CONFIG_INVALID => [ 'name' => Exception::PROJECT_SMTP_CONFIG_INVALID, - 'description' => 'Provided SMTP config is invalid.', + 'description' => 'Provided SMTP config is invalid. Please check the configured values and try again.', 'code' => 400, ], Exception::PROJECT_TEMPLATE_DEFAULT_DELETION => [ 'name' => Exception::PROJECT_TEMPLATE_DEFAULT_DELETION, - 'description' => 'The default template for the project cannot be deleted.', + 'description' => 'You can\'t delete default template. If you are trying to reset your template changes, you can ignore this error as it\'s already been reset.', 'code' => 401, ], Exception::WEBHOOK_NOT_FOUND => [ @@ -614,21 +691,6 @@ return [ 'description' => 'Platform with the requested ID could not be found.', 'code' => 404, ], - Exception::DOMAIN_NOT_FOUND => [ - 'name' => Exception::DOMAIN_NOT_FOUND, - 'description' => 'Domain with the requested ID could not be found.', - 'code' => 404, - ], - Exception::DOMAIN_ALREADY_EXISTS => [ - 'name' => Exception::DOMAIN_ALREADY_EXISTS, - 'description' => 'The requested domain is currently in use by a project.', - 'code' => 409, - ], - Exception::DOMAIN_FORBIDDEN => [ - 'name' => Exception::DOMAIN_FORBIDDEN, - 'description' => 'The requested domain cannot be used as a custom domain.', - 'code' => 403, - ], Exception::VARIABLE_NOT_FOUND => [ 'name' => Exception::VARIABLE_NOT_FOUND, 'description' => 'Variable with the requested ID could not be found.', @@ -636,19 +698,9 @@ return [ ], Exception::VARIABLE_ALREADY_EXISTS => [ 'name' => Exception::VARIABLE_ALREADY_EXISTS, - 'description' => 'Variable with the same ID already exists in your project.', + 'description' => 'Variable with the same ID already exists in this project. Try again with a different ID.', 'code' => 409, ], - Exception::DOMAIN_VERIFICATION_FAILED => [ - 'name' => Exception::DOMAIN_VERIFICATION_FAILED, - 'description' => 'Domain verification for the requested domain has failed.', - 'code' => 401, - ], - Exception::DOMAIN_TARGET_INVALID => [ - 'name' => Exception::DOMAIN_TARGET_INVALID, - 'description' => 'Your Appwrite instance is not publicly accessible. Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.', - 'code' => 501, - ], Exception::GRAPHQL_NO_QUERY => [ 'name' => Exception::GRAPHQL_NO_QUERY, 'description' => 'Param "query" is not optional.', @@ -659,4 +711,21 @@ return [ 'description' => 'Too many queries.', 'code' => 400, ], + + /** Migrations */ + Exception::MIGRATION_NOT_FOUND => [ + 'name' => Exception::MIGRATION_NOT_FOUND, + 'description' => 'Migration with the requested ID could not be found. Please verify that the provided ID is correct and try again.', + 'code' => 404, + ], + Exception::MIGRATION_ALREADY_EXISTS => [ + 'name' => Exception::MIGRATION_ALREADY_EXISTS, + 'description' => 'Migration with the requested ID already exists. Try again with a different ID.', + 'code' => 409, + ], + Exception::MIGRATION_IN_PROGRESS => [ + 'name' => Exception::MIGRATION_IN_PROGRESS, + 'description' => 'Migration is already in progress. You can check the status of the migration in your Appwrite Console\'s "Settings" > "Migrations".', + 'code' => 409, + ], ]; diff --git a/app/config/events.php b/app/config/events.php index 55dfad77d0..c0b6cc3b41 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -236,5 +236,19 @@ return [ 'update' => [ '$description' => 'This event triggers when a function is updated.', ] + ], + 'rules' => [ + '$model' => Response::MODEL_PROXY_RULE, + '$resource' => true, + '$description' => 'This event triggers on any proxy rule event.', + 'create' => [ + '$description' => 'This event triggers when a proxy rule is created.' + ], + 'delete' => [ + '$description' => 'This event triggers when a proxy rule is deleted.', + ], + 'update' => [ + '$description' => 'This event triggers when a proxy rule is updated.', + ] ] ]; diff --git a/app/config/locale/templates/email-base.tpl b/app/config/locale/templates/email-base.tpl index b9b5b1bb8d..f41a9530e1 100644 --- a/app/config/locale/templates/email-base.tpl +++ b/app/config/locale/templates/email-base.tpl @@ -42,39 +42,21 @@ border: none; border-top: 1px solid #E8E9F0; } + + p { + margin-bottom: 10px; + } -
- -
-

- {{subject}} -

-
- - - -
-

{{hello}}

- -

{{body}}

- - {{redirect}} - -


{{footer}}

-
- -

{{thanks}} -
- {{signature}} -

+ {{body}}
diff --git a/app/config/locale/templates/email-inner-base.tpl b/app/config/locale/templates/email-inner-base.tpl new file mode 100644 index 0000000000..53ffe83a5b --- /dev/null +++ b/app/config/locale/templates/email-inner-base.tpl @@ -0,0 +1,15 @@ +

{{hello}}

+ +
+ +

{{body}}

+ +{{redirect}} + +

{{footer}}

+ +
+ +

{{thanks}}

+ +

{{signature}}

\ No newline at end of file diff --git a/app/config/locale/translations/af.json b/app/config/locale/translations/af.json index d3bccdadae..f81800dbb2 100644 --- a/app/config/locale/translations/af.json +++ b/app/config/locale/translations/af.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s span", "emails.verification.subject": "Rekening Bevestiging", - "emails.verification.hello": "Goeie dag {{name}}", + "emails.verification.hello": "Goeie dag {{user}}", "emails.verification.body": "Volg hierdie skakel om u e-pos adres te bevestig.", "emails.verification.footer": "Ignoreer gerus hierdie boodskap as u nie die versoek gestuur het om u adres te bevestig nie.", "emails.verification.thanks": "Baie dankie", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Baie dankie", "emails.magicSession.signature": "Die {{project}} span", "emails.recovery.subject": "Herstel Wagwoord", - "emails.recovery.hello": "Goeie dag {{name}}", + "emails.recovery.hello": "Goeie dag {{user}}", "emails.recovery.body": "Volg hierdie skakel om u {{project}} wagwoord te herstel.", "emails.recovery.footer": "Ignoreer gerus hierdie boodskap as u nie die versoek gestuur het om u wagwoord te herstel nie.", "emails.recovery.thanks": "Baie dankie", diff --git a/app/config/locale/translations/ar.json b/app/config/locale/translations/ar.json index 9a40d4f1c3..87d75d7643 100644 --- a/app/config/locale/translations/ar.json +++ b/app/config/locale/translations/ar.json @@ -4,7 +4,7 @@ "settings.direction": "rtl", "emails.sender": "فريق %s", "emails.verification.subject": "تأكيد الحساب", - "emails.verification.hello": "مرحبا {{name}}", + "emails.verification.hello": "مرحبا {{user}}", "emails.verification.body": "برجاء اتباع الرابط التالي لتأكيد بريدك الإلكتروني", "emails.verification.footer": "لو لم تطلب تأكيد هذا البريد الإلكتروني، يمكنك تجاهل هذه الرسالة", "emails.verification.thanks": "شكرا", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "شكرا", "emails.magicSession.signature": "فريق {{project}}", "emails.recovery.subject": "تغيير كلمة السر", - "emails.recovery.hello": "أهلا {{name}}", + "emails.recovery.hello": "أهلا {{user}}", "emails.recovery.body": "برجاء اتباع الراط التالي لتغيير كلمة السر الخاصة بـ{{project}}", "emails.recovery.footer": "لولم تطلب تغيير كلمة السر، يمكنك تجاهل هذه الرسالة", "emails.recovery.thanks": "شكرا", diff --git a/app/config/locale/translations/as.json b/app/config/locale/translations/as.json index 20bd54a8e9..31809f2bbd 100644 --- a/app/config/locale/translations/as.json +++ b/app/config/locale/translations/as.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s দল", "emails.verification.subject": "একাউণ্ট প্ৰমাণীকৰণ", - "emails.verification.hello": "নমস্কাৰ {{name}}", + "emails.verification.hello": "নমস্কাৰ {{user}}", "emails.verification.body": "আপোনাৰ ইমেইল ঠিকনা প্ৰমাণিত কৰিবলৈ এই লিংকটো অনুসৰণ কৰক।", "emails.verification.footer": "যদি আপুনি এই ঠিকনাটো সত্যাপিত কৰিবলৈ কোৱা নাই, আপুনি এই বাৰ্তাটো উপেক্ষা কৰিব পাৰে।", "emails.verification.thanks": "ধন্যবাদ", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "ধন্যবাদ", "emails.magicSession.signature": "{{project}} দল", "emails.recovery.subject": "পাছৱাৰ্ড ৰিছেট", - "emails.recovery.hello": "ধন্যবাদ {{name}}", + "emails.recovery.hello": "ধন্যবাদ {{user}}", "emails.recovery.body": "আপোনাৰ {{project}} পাছৱৰ্ড ৰিছেট কৰিবলৈ এই লিংকটো অনুসৰণ কৰক।.", "emails.recovery.footer": "যদি আপুনি আপোনাৰ পাছৱৰ্ড ৰিছেট কৰিবলৈ কোৱা নাছিল, আপুনি এই বাৰ্তাটো উপেক্ষা কৰিব পাৰে।", "emails.recovery.thanks": "ধন্যবাদ", diff --git a/app/config/locale/translations/az.json b/app/config/locale/translations/az.json index dd26ebda8e..55be9e805a 100644 --- a/app/config/locale/translations/az.json +++ b/app/config/locale/translations/az.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Komandası", "emails.verification.subject": "Hesab Doğrulama", - "emails.verification.hello": "Salam {{name}}", + "emails.verification.hello": "Salam {{user}}", "emails.verification.body": "E-poçt ünvanınızı təsdiq etmək üçün bu linki izləyin.", "emails.verification.footer": "Bu ünvanı doğrulamağı xahiş etməmisinizsə, bu mesajı gözardı edə bilərsiniz.", "emails.verification.thanks": "Təşəkkürlər", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Təşəkkürlər", "emails.magicSession.signature": "{{project}} komandası", "emails.recovery.subject": "Şifrə Sıfırlanması", - "emails.recovery.hello": "Salam {{name}}", + "emails.recovery.hello": "Salam {{user}}", "emails.recovery.body": "{{project}} şifrənizi sıfırlamaq üçün bu linki izləyin.", "emails.recovery.footer": "Şifrənizi sıfırlamağı xahiş etməmisinizsə, bu mesajı gözardı edə bilərsiniz.", "emails.recovery.thanks": "Təşəkkürlər", diff --git a/app/config/locale/translations/be.json b/app/config/locale/translations/be.json index c46c40f2c3..73ae26c215 100644 --- a/app/config/locale/translations/be.json +++ b/app/config/locale/translations/be.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Каманда %s", "emails.verification.subject": "Верыфікацыя акаўнта", - "emails.verification.hello": "Прывітанне {{name}}", + "emails.verification.hello": "Прывітанне {{user}}", "emails.verification.body": "Перайдзіце па гэтай спасылцы, каб пацвердзіць свой адрас электроннай пошты", "emails.verification.footer": "Калі вы не запытвалі пацвярджэнне гэтага адрасу, праігнаруйце гэтае паведамленне.", "emails.verification.thanks": "Дзякуем", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Дзякуем", "emails.magicSession.signature": "каманда {{project}}", "emails.recovery.subject": "Скід пароля", - "emails.recovery.hello": "Прывітанне, {{name}}", + "emails.recovery.hello": "Прывітанне, {{user}}", "emails.recovery.body": "Перайдзіце па гэтай спасылцы, каб скінуць пароль для праекта {{project}}.", "emails.recovery.footer": "Калі вы не прасілі скінуць пароль, вы можаце праігнараваць гэта паведамленне.", "emails.recovery.thanks": "Дзякуем", diff --git a/app/config/locale/translations/bh.json b/app/config/locale/translations/bh.json index d151297932..edbc15c28c 100644 --- a/app/config/locale/translations/bh.json +++ b/app/config/locale/translations/bh.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s टीम", "emails.verification.subject": "खाता प्रमाणिकरण", - "emails.verification.hello": "नमस्ते {{name}}", + "emails.verification.hello": "नमस्ते {{user}}", "emails.verification.body": "ईमेल प्रमाणिकरण करे क लेल दिहल गइल लिंक फॉलो करें|", "emails.verification.footer": "अगर ई पता को सत्यापित करे के लिए ना कहाले, तो आप ई संदेश क अनदेखा कर सकत अछि।", "emails.verification.thanks": "धन्यवाद", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "धन्यवाद", "emails.magicSession.signature": "{{project}} टीम", "emails.recovery.subject": "पासवर्ड बदल क लेल|", - "emails.recovery.hello": "प्रणाम {{name}}", + "emails.recovery.hello": "प्रणाम {{user}}", "emails.recovery.body": "पासवर्ड बदल क लेल दिहल गइल लिंक फॉलो करें|", "emails.recovery.footer": "अगर पासवर्ड बदल क लेल ना कहाले, तो आप ई संदेश क अनदेखा कर सकत अछि।", "emails.recovery.thanks": "धन्यवाद", diff --git a/app/config/locale/translations/bn.json b/app/config/locale/translations/bn.json index da8899f699..06ef081610 100644 --- a/app/config/locale/translations/bn.json +++ b/app/config/locale/translations/bn.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s টীম", "emails.verification.subject": "বিষয়", - "emails.verification.hello": "নমস্কার {{name}}", + "emails.verification.hello": "নমস্কার {{user}}", "emails.verification.body": "এই লিঙ্কের মাধ্যমে ইমেইল যাচাই করুন।", "emails.verification.footer": "আপনি যদি এই ঠিকানা যাচাই করতে না বলেন, তাহলে আপনি এই বার্তাটি উপেক্ষা করতে পারেন।", "emails.verification.thanks": "ধন্যবাদ", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "ধন্যবাদ", "emails.magicSession.signature": "{{project}} টীম", "emails.recovery.subject": "পাসওয়ার্ড রিসেট", - "emails.recovery.hello": "নমস্কার {{name}}", + "emails.recovery.hello": "নমস্কার {{user}}", "emails.recovery.body": "এই লিঙ্কের মাধ্যমে আপনার {{project}} পাসওয়ার্ড পুনরায় সেট করুন।", "emails.recovery.footer": "আপনি যদি আপনার পাসওয়ার্ড পুনরায় সেট করতে না বলেন, তাহলে আপনি এই বার্তাটি উপেক্ষা করতে পারেন।", "emails.recovery.thanks": "ধন্যবাদ", diff --git a/app/config/locale/translations/ca.json b/app/config/locale/translations/ca.json index 32649b7e66..281f1b9d5f 100644 --- a/app/config/locale/translations/ca.json +++ b/app/config/locale/translations/ca.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Equip", "emails.verification.subject": "Verificació del compte", - "emails.verification.hello": "Hola {{name}}", + "emails.verification.hello": "Hola {{user}}", "emails.verification.body": "Accedeix a aquest enllaç per tal de verificar la teva adreça electrònica.", "emails.verification.footer": "Si no has sol·licitat la verificació d'aquesta adreça electrònica, pots ignorar aquest missatge.", "emails.verification.thanks": "Gràcies", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Gràcies", "emails.magicSession.signature": "Equip {{project}}", "emails.recovery.subject": "Reinicialitzar contrasenya", - "emails.recovery.hello": "Hola {{name}}", + "emails.recovery.hello": "Hola {{user}}", "emails.recovery.body": "Accedeix a aquest enllaç per a reinicialitzar la teva contrasenya de {{project}}.", "emails.recovery.footer": "Si no has sol·licitat reinicialitzar la teva contrasenya, pots ignorar aquest missatge.", "emails.recovery.thanks": "Gràcies", diff --git a/app/config/locale/translations/da.json b/app/config/locale/translations/da.json index 68401be419..73aaef5590 100644 --- a/app/config/locale/translations/da.json +++ b/app/config/locale/translations/da.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Team", "emails.verification.subject": "Konto Verifikation", - "emails.verification.hello": "Hej {{name}}", + "emails.verification.hello": "Hej {{user}}", "emails.verification.body": "Følg dette link, for at verificere din email adresse.", "emails.verification.footer": "Hvis du ikke har bedt om at verificere denne adresse, ignorer venligst denne besked.", "emails.verification.thanks": "Tak", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Tak", "emails.magicSession.signature": "{{project}} team", "emails.recovery.subject": "Nulstil Password", - "emails.recovery.hello": "Hej {{name}}", + "emails.recovery.hello": "Hej {{user}}", "emails.recovery.body": "Følg dette link for at nulstille koden til {{project}}.", "emails.recovery.footer": "Hvis du ikke har bedt om at nulstille dit password, ignorer venligst denne besked.", "emails.recovery.thanks": "Tak", diff --git a/app/config/locale/translations/de.json b/app/config/locale/translations/de.json index b3de6a2fb1..5fa1c14c27 100644 --- a/app/config/locale/translations/de.json +++ b/app/config/locale/translations/de.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Team", "emails.verification.subject": "Kontoverifizierung", - "emails.verification.hello": "Hey {{name}}", + "emails.verification.hello": "Hey {{user}}", "emails.verification.body": "Folge diesem Link, um deine E-Mail-Adresse zu bestätigen.", "emails.verification.footer": "Solltest du keine Verifizierung dieser E-Mail-Adresse angefordert haben, kannst du diese Nachricht ignorieren.", "emails.verification.thanks": "Danke", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Danke", "emails.magicSession.signature": "{{project}}-Team", "emails.recovery.subject": "Kennwort zurücksetzen", - "emails.recovery.hello": "Hallo {{name}}", + "emails.recovery.hello": "Hallo {{user}}", "emails.recovery.body": "Folge diesem Link, um dein {{project}}-Kennwort zurückzusetzen.", "emails.recovery.footer": "Solltest du keine Kennwort-Zurücksetzung angefordert haben, kannst du diese Nachricht ignorieren.", "emails.recovery.thanks": "Danke", diff --git a/app/config/locale/translations/el.json b/app/config/locale/translations/el.json index 83af3cad0b..88ceeb873e 100644 --- a/app/config/locale/translations/el.json +++ b/app/config/locale/translations/el.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Ομάδα %s", "emails.verification.subject": "Επαλήθευση Λογαριασμού", - "emails.verification.hello": "Γεια σου {{name}}", + "emails.verification.hello": "Γεια σου {{user}}", "emails.verification.body": "Ακολουθήστε αυτό το link για να επαληθεύσετε τη δ/νση του email σας", "emails.verification.footer": "Εάν δεν ζητήσατε επαλήθευση αυτής της δ/νσης email, μπορείτε να αγνοήσετε αυτό το μήνυμα", "emails.verification.thanks": "Ευχαριστούμε", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Ευχαριστούμε", "emails.magicSession.signature": "Η ομάδα του {{project}}", "emails.recovery.subject": "Αλλαγή κωδικού πρόσβασης", - "emails.recovery.hello": "Γεια σου {{name}}", + "emails.recovery.hello": "Γεια σου {{user}}", "emails.recovery.body": "Ακολουθήστε αυτό το link για να αλλάξετε τον {{project}} κωδικό σας", "emails.recovery.footer": "Εάν δεν ζητήσατε αλλαγή του κωδικού σας πρόσβασης, μπορείτε να αγνοήσετε αυτό το μήνυμα", "emails.recovery.thanks": "Ευχαριστούμε", diff --git a/app/config/locale/translations/en.json b/app/config/locale/translations/en.json index 91cc2405b6..681c88ae94 100644 --- a/app/config/locale/translations/en.json +++ b/app/config/locale/translations/en.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Team", "emails.verification.subject": "Account Verification", - "emails.verification.hello": "Hey {{name}}", + "emails.verification.hello": "Hey {{user}}", "emails.verification.body": "Follow this link to verify your email address.", "emails.verification.footer": "If you didn’t ask to verify this address, you can ignore this message.", "emails.verification.thanks": "Thanks", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Thanks", "emails.magicSession.signature": "{{project}} team", "emails.recovery.subject": "Password Reset", - "emails.recovery.hello": "Hello {{name}}", + "emails.recovery.hello": "Hello {{user}}", "emails.recovery.body": "Follow this link to reset your {{project}} password.", "emails.recovery.footer": "If you didn’t ask to reset your password, you can ignore this message.", "emails.recovery.thanks": "Thanks", diff --git a/app/config/locale/translations/eo.json b/app/config/locale/translations/eo.json index e10dfd5d6e..bb553f1ced 100644 --- a/app/config/locale/translations/eo.json +++ b/app/config/locale/translations/eo.json @@ -3,7 +3,7 @@ "settings.direction": "ltr", "emails.sender": "Teamo %s", "emails.verification.subject": "Konta Konfirmo", - "emails.verification.hello": "Saluton {{name}}", + "emails.verification.hello": "Saluton {{user}}", "emails.verification.body": "Alklaku ĉi tiun ligon por kontroli vian retpoŝtan adreson.", "emails.verification.footer": "Se vi ne petis ĉi tiun konfirmon de ĉi tiu retpoŝto, vi povas ignori ĉi tiun mesaĝon.", "emails.verification.thanks": "Dankegon.", @@ -15,7 +15,7 @@ "emails.magicSession.thanks": "Dankegon", "emails.magicSession.signature": "Teamo {{project}}", "emails.recovery.subject": "Parsvorta Restarigo", - "emails.recovery.hello": "Saluton {{name}}", + "emails.recovery.hello": "Saluton {{user}}", "emails.recovery.body": "Alklaku ĉi tiun ligon por reagordi vian pasvorton. {{project}}", "emails.recovery.footer": "Se vi ne petis reagordi vian pasvorton, vi povas ignori ĉi tiun mesaĝon.", "emails.recovery.thanks": "Dankegon", diff --git a/app/config/locale/translations/es.json b/app/config/locale/translations/es.json index d0138bdde8..b22fa0ca93 100644 --- a/app/config/locale/translations/es.json +++ b/app/config/locale/translations/es.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Equipo %s", "emails.verification.subject": "Verificación de cuenta", - "emails.verification.hello": "Hola {{name}}", + "emails.verification.hello": "Hola {{user}}", "emails.verification.body": "Haz clic en este enlace para verificar tu correo.", "emails.verification.footer": "Si no has solicitado verificar este correo, puedes ignorar este mensaje.", "emails.verification.thanks": "Gracias", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Gracias", "emails.magicSession.signature": "Equipo de {{project}}", "emails.recovery.subject": "Restablecer contraseña", - "emails.recovery.hello": "Hola {{name}}", + "emails.recovery.hello": "Hola {{user}}", "emails.recovery.body": "Haz clic en este enlace para restablecer la contraseña de {{project}}.", "emails.recovery.footer": "Si no has solicitado restablecer la contraseña, puedes ignorar este mensaje.", "emails.recovery.thanks": "Gracias", diff --git a/app/config/locale/translations/fa.json b/app/config/locale/translations/fa.json index 346e3759bf..ef1e74cf0e 100644 --- a/app/config/locale/translations/fa.json +++ b/app/config/locale/translations/fa.json @@ -4,29 +4,29 @@ "settings.direction": "rtl", "emails.sender": "تیم %s", "emails.verification.subject": "تأیید حساب", - "emails.verification.hello": "سلام {{name}}", + "emails.verification.hello": "سلام {{user}}", "emails.verification.body": "برای تأیید ایمیل‌تان پیوند زیر را دنبال کنید.", "emails.verification.footer": "اگر شما درخواست تأیید حساب نداده‌اید، می‌توانید این پیام را نادیده بگیرید.", "emails.verification.thanks": "سپاس فراوان", - "emails.verification.signature": "تیم {{name}}", + "emails.verification.signature": "تیم {{user}}", "emails.magicSession.subject": "ورود به حساب کاربری", "emails.magicSession.hello": "سلام،", "emails.magicSession.body": "برای ورود به حساب‌تان پیوند زیر را دنبال کنید.", "emails.magicSession.footer": "اگر شما درخواست ورود به حساب کاربری با استفاده از این ایمیل را نداد‌ه‌اید، می‌توانید این پیام را نادیده بگیرید.", "emails.magicSession.thanks": "سپاس فراوان", - "emails.magicSession.signature": "تیم {{name}}", + "emails.magicSession.signature": "تیم {{user}}", "emails.recovery.subject": "بازیابی گذرواژه", - "emails.recovery.hello": "سلام {{name}}", + "emails.recovery.hello": "سلام {{user}}", "emails.recovery.body": "برای بازیابی گذرواژه‌تان پیوند زیر را دنبال کنید.", "emails.recovery.footer": "اگر شما درخواست بازیابی گذرواژه نداده‌اید، می‌توانید این پیام را نادیده بگیرید.", "emails.recovery.thanks": "سپاس فراوان", - "emails.recovery.signature": "تیم {{name}}", + "emails.recovery.signature": "تیم {{user}}", "emails.invitation.subject": "دعوت به تیم %s در %s", "emails.invitation.hello": "سلام", "emails.invitation.body": "این ایمیل برای شما فرستاده شده‌است زیرا {{owner}} می‌خواهد شما را به تیم {{team}} در پروژه‌ی {{project}} بیفزاید.", "emails.invitation.footer": "اگر علاقه ندارید، می‌توانید این پیام را نادیده بگیرید.", "emails.invitation.thanks": "سپاس فراوان", - "emails.invitation.signature": "تیم {{name}}", + "emails.invitation.signature": "تیم {{user}}", "locale.country.unknown": "ناشناخته", "countries.af": "افغانستان", "countries.ao": "آنگولا", diff --git a/app/config/locale/translations/fr.json b/app/config/locale/translations/fr.json index 362d04c93a..29fdb8645e 100644 --- a/app/config/locale/translations/fr.json +++ b/app/config/locale/translations/fr.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Équipe %s", "emails.verification.subject": "Vérification du compte", - "emails.verification.hello": "Bonjour {{name}}", + "emails.verification.hello": "Bonjour {{user}}", "emails.verification.body": "Suivez ce lien pour vérifier votre adresse e-mail.", "emails.verification.footer": "Si vous n'avez pas demandé à vérifier cette adresse, vous pouvez ignorer ce message.", "emails.verification.thanks": "Merci", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Merci", "emails.magicSession.signature": "L'équipe {{project}}", "emails.recovery.subject": "Réinitialisation du mot de passe", - "emails.recovery.hello": "Bonjour {{name}}", + "emails.recovery.hello": "Bonjour {{user}}", "emails.recovery.body": "Suivez ce lien pour réinitialiser votre mot de passe pour {{project}}.", "emails.recovery.footer": "Si vous n'avez pas demandé à réinitialiser votre mot de passe, vous pouvez ignorer ce message.", "emails.recovery.thanks": "Merci", diff --git a/app/config/locale/translations/ga.json b/app/config/locale/translations/ga.json index d572fa01a8..15471f4f66 100644 --- a/app/config/locale/translations/ga.json +++ b/app/config/locale/translations/ga.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Foireann", "emails.verification.subject": "Fíoraithe cuntais", - "emails.verification.hello": "Haigh {{name}}", + "emails.verification.hello": "Haigh {{user}}", "emails.verification.body": "Lean an nasc seo chun do ríomhphost a fhíorú.", "emails.verification.footer": "Mura ndearna tú iarratas an seoladh seo a fhíoru, déan neamhaird den teachtaireacht seo.", "emails.verification.thanks": "Go raibh maith agat", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Go raibh maith agat", "emails.magicSession.signature": "{{project}} foireann", "emails.recovery.subject": "Athshocrú pasfhocail", - "emails.recovery.hello": "Haigh {{name}}", + "emails.recovery.hello": "Haigh {{user}}", "emails.recovery.body": "Lean an nasc seo chun do pasfhocal {{project}} a athshocrú.", "emails.recovery.footer": "Mura ndearna tú iarratas do pasfhocal a athshocrú, déan neamhaird den teachtaireacht seo.", "emails.recovery.thanks": "Go raibh maith agat", diff --git a/app/config/locale/translations/gu.json b/app/config/locale/translations/gu.json index 9357160cc5..1483f5b0b0 100644 --- a/app/config/locale/translations/gu.json +++ b/app/config/locale/translations/gu.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s ટીમ", "emails.verification.subject": "ખાતાની ચકાસણી", - "emails.verification.hello": "નમસ્કાર {{name}}", + "emails.verification.hello": "નમસ્કાર {{user}}", "emails.verification.body": "તમારું ઇમેઇલ સરનામું ચકાસવા માટે આ લિંકને અનુસરો.", "emails.verification.footer": "જો તમે આ સરનામાંની ચકાસણી કરવાનું ન કહ્યું હોય, તો તમે આ સંદેશને અવગણી શકો છો.", "emails.verification.thanks": "આભાર", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "આભાર", "emails.magicSession.signature": "{{project}} ટીમ", "emails.recovery.subject": "પાસવર્ડ ફરીથી સેટ કરો", - "emails.recovery.hello": "નમસ્કાર {{name}}", + "emails.recovery.hello": "નમસ્કાર {{user}}", "emails.recovery.body": "તમારો {{project}} પાસવર્ડ ફરીથી સેટ કરવા માટે આ લિંકને અનુસરો.", "emails.recovery.footer": "જો તમે તમારો પાસવર્ડ ફરીથી સેટ કરવાનું ન કહ્યું હોય, તો તમે આ સંદેશને અવગણી શકો છો.", "emails.recovery.thanks": "આભાર", diff --git a/app/config/locale/translations/he.json b/app/config/locale/translations/he.json index ef4af6f56e..2704341570 100644 --- a/app/config/locale/translations/he.json +++ b/app/config/locale/translations/he.json @@ -4,7 +4,7 @@ "settings.direction": "rtl", "emails.sender": "צוות %s", "emails.verification.subject": "אימות חשבון", - "emails.verification.hello": "שלום {{name}}", + "emails.verification.hello": "שלום {{user}}", "emails.verification.body": "לחץ על קישור זה כדי לאמת את כתובת הדוא\"ל שלך.", "emails.verification.footer": "אם לא ביקשת לאמת כתובת זו, תוכל להתעלם מהודעה זו.", "emails.verification.thanks": "תודה", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "תודה", "emails.magicSession.signature": "צוות {{project}}", "emails.recovery.subject": "איפוס סיסמא", - "emails.recovery.hello": "שלום {{name}}", + "emails.recovery.hello": "שלום {{user}}", "emails.recovery.body": "עקוב אחר קישור זה כדי לאפס את סיסמתך ב-{{project}}.", "emails.recovery.footer": "אם לא ביקשת לאפס את הסיסמה, תוכל להתעלם מהודעה זו.", "emails.recovery.thanks": "תודה", diff --git a/app/config/locale/translations/hi.json b/app/config/locale/translations/hi.json index 2a4229acce..680044f660 100644 --- a/app/config/locale/translations/hi.json +++ b/app/config/locale/translations/hi.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s टीम", "emails.verification.subject": "अकाउंट वेरिफिकेशन ", - "emails.verification.hello": "नमस्ते {{name}}", + "emails.verification.hello": "नमस्ते {{user}}", "emails.verification.body": "इस लिंक के माध्यम से अपने ईमेल को सत्यापित कीजिये।", "emails.verification.footer": "यदि आप इस पते को सत्यापित नहीं करना चाहते हैं, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।", "emails.verification.thanks": "धन्यवाद", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "धन्यवाद", "emails.magicSession.signature": "{{project}} टीम", "emails.recovery.subject": "पासवर्ड रीसेट", - "emails.recovery.hello": "नमस्ते {{name}}", + "emails.recovery.hello": "नमस्ते {{user}}", "emails.recovery.body": "इस लिंक के माध्यम से अपना {{project}} पासवर्ड रीसेट करें।", "emails.recovery.footer": "यदि आप अपना पासवर्ड रीसेट नहीं करना चाहते हैं, तो आप इस संदेश को नज़रअंदाज़ कर सकते हैं।", "emails.recovery.thanks": "धन्यवाद", diff --git a/app/config/locale/translations/hr.json b/app/config/locale/translations/hr.json index 4dcebf0a41..fb3057df86 100644 --- a/app/config/locale/translations/hr.json +++ b/app/config/locale/translations/hr.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Tim", "emails.verification.subject": "Verifikacija računa", - "emails.verification.hello": "Pozdrav {{name}}", + "emails.verification.hello": "Pozdrav {{user}}", "emails.verification.body": "Slijedite ovu poveznicu da biste potvrdili svoju adresu e-pošte.", "emails.verification.footer": "Ukoliko niste zatražili potvrdu ove adrese, možete zanemariti ovu poruku.", "emails.verification.thanks": "Hvala", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Hvala", "emails.magicSession.signature": "{{project}} tim", "emails.recovery.subject": "Ponovno postavljanje lozinke", - "emails.recovery.hello": "Pozdrav {{name}}", + "emails.recovery.hello": "Pozdrav {{user}}", "emails.recovery.body": "Slijedite ovu poveznicu za ponovno postavljanje {{project}} lozinke.", "emails.recovery.footer": "Ako niste zatražili ponovno postavljanje Vaše lozinke, možete zanemariti ovu poruku.", "emails.recovery.thanks": "Hvala", diff --git a/app/config/locale/translations/hu.json b/app/config/locale/translations/hu.json index 17ce2e544b..094f6dee1f 100644 --- a/app/config/locale/translations/hu.json +++ b/app/config/locale/translations/hu.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Csapat", "emails.verification.subject": "Fiók Megerősítése", - "emails.verification.hello": "Szia {{name}}", + "emails.verification.hello": "Szia {{user}}", "emails.verification.body": "Kattints a linkre, hogy megerősítsd az email címedet.", "emails.verification.footer": "Ha nem te kérted a címed megerősítését, akkor nyugodtan hagyd figyelmen kívül ezt az üzenetet.", "emails.verification.thanks": "Köszönettel", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Köszönettel", "emails.magicSession.signature": "a {{project}} csapat", "emails.recovery.subject": "Jelszó Visszaállítása", - "emails.recovery.hello": "Hahó, {{name}}", + "emails.recovery.hello": "Hahó, {{user}}", "emails.recovery.body": "Kattints a linkre a {{project}} jelszavad visszaállításához.", "emails.recovery.footer": "Ha nem te kezdeményezted a jelszavad visszaállítását, akkor nyugodtan hagyd figyelmen kívül ezt az üzenetet.", "emails.recovery.thanks": "Köszönettel", diff --git a/app/config/locale/translations/id.json b/app/config/locale/translations/id.json index 06429e9583..eb054d998e 100644 --- a/app/config/locale/translations/id.json +++ b/app/config/locale/translations/id.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Tim %s", "emails.verification.subject": "Verifikasi Akun", - "emails.verification.hello": "Hai {{name}}", + "emails.verification.hello": "Hai {{user}}", "emails.verification.body": "Ikuti tautan ini untuk memverifikasi alamat email Anda.", "emails.verification.footer": "Jika Anda tidak meminta untuk memverifikasi alamat email ini, Anda dapat mengabaikan pesan ini.", "emails.verification.thanks": "Terima kasih", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Terima kasih", "emails.magicSession.signature": "Tim {{project}}", "emails.recovery.subject": "Atur Ulang Kata Sandi", - "emails.recovery.hello": "Halo {{name}}", + "emails.recovery.hello": "Halo {{user}}", "emails.recovery.body": "Ikuti tautan ini untuk menyetel ulang kata sandi {{project}} Anda.", "emails.recovery.footer": "Jika Anda tidak meminta untuk menyetel ulang kata sandi, Anda dapat mengabaikan pesan ini.", "emails.recovery.thanks": "Terima kasih", diff --git a/app/config/locale/translations/it.json b/app/config/locale/translations/it.json index 06080901bf..727e46f94e 100644 --- a/app/config/locale/translations/it.json +++ b/app/config/locale/translations/it.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Team %s", "emails.verification.subject": "Verifica account", - "emails.verification.hello": "Ciao {{name}}", + "emails.verification.hello": "Ciao {{user}}", "emails.verification.body": "Clicca questo link per verificare il tuo indirizzo email.", "emails.verification.footer": "Se non hai richiesto la verifica dell’indirizzo email, puoi ignorare questo messaggio.", "emails.verification.thanks": "Grazie", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Grazie", "emails.magicSession.signature": "Il team {{project}}", "emails.recovery.subject": "Reimpostazione password", - "emails.recovery.hello": "Ciao {{name}}", + "emails.recovery.hello": "Ciao {{user}}", "emails.recovery.body": "Clicca questo link per reimpostare la tua password di {{project}}.", "emails.recovery.footer": "Se non hai richiesto la reimpostazione della password, puoi ignorare questo messaggio.", "emails.recovery.thanks": "Grazie", diff --git a/app/config/locale/translations/ja.json b/app/config/locale/translations/ja.json index 415c753f19..386a7e4870 100644 --- a/app/config/locale/translations/ja.json +++ b/app/config/locale/translations/ja.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s チーム", "emails.verification.subject": "アカウント認証", - "emails.verification.hello": "こんにちは{{name}}さん", + "emails.verification.hello": "こんにちは{{user}}さん", "emails.verification.body": "メールアドレスを有効化するためには下記リンクをクリックして下さい。", "emails.verification.footer": "このメールに心当たりが無い場合は破棄をお願いいたします。", "emails.verification.thanks": "ご利用いただきありがとうございます。", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "ご利用いただきありがとうございます。", "emails.magicSession.signature": "{{project}}チーム", "emails.recovery.subject": "パスワードリセット", - "emails.recovery.hello": "こんにちは{{name}}さん", + "emails.recovery.hello": "こんにちは{{user}}さん", "emails.recovery.body": "パスワードをリセットするためには下記リンクをクリックしてください。", "emails.recovery.footer": "このメールに心当たりが無い場合は破棄をお願いいたします。", "emails.recovery.thanks": "ご利用いただきありがとうございます。", diff --git a/app/config/locale/translations/jv.json b/app/config/locale/translations/jv.json index 06990dfa9f..6af2a88443 100644 --- a/app/config/locale/translations/jv.json +++ b/app/config/locale/translations/jv.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Tim %s", "emails.verification.subject": "Verifikasi Akun", - "emails.verification.hello": "Hai {{name}}", + "emails.verification.hello": "Hai {{user}}", "emails.verification.body": "Klik link iki kanggo verifikasi alamat email sampeyan.", "emails.verification.footer": "Yen sampeyan ora njaluk verifikasi alamat iki, sampeyan iso nglirwakake pesen iki.", "emails.verification.thanks": "Matur nuwun", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Matur nuwun", "emails.magicSession.signature": "Tim {{project}}", "emails.recovery.subject": "Setel ulang sandi", - "emails.recovery.hello": "Halo {{name}}", + "emails.recovery.hello": "Halo {{user}}", "emails.recovery.body": "Klik link iki kanggo setel ulang sandi {{project}}.", "emails.recovery.footer": "Yen sampeyan ora njaluk setel ulang sandi, sampeyan iso nglirwakake pesen iki.", "emails.recovery.thanks": "Matur nuwun", diff --git a/app/config/locale/translations/kn.json b/app/config/locale/translations/kn.json index 1dfe029778..570b5ddf01 100644 --- a/app/config/locale/translations/kn.json +++ b/app/config/locale/translations/kn.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s ತಂಡ", "emails.verification.subject": "ಖಾತೆ ಪರಿಶೀಲನೆ", - "emails.verification.hello": "ನಮಸ್ಕಾರ {{name}}", + "emails.verification.hello": "ನಮಸ್ಕಾರ {{user}}", "emails.verification.body": "ನಿಮ್ಮ ಇಮೇಲ್ ವಿಳಾಸ ಪರಿಶೀಲನೆಗೆ ಈ ಲಿಂಕನ್ನು ಅನುಸರಿಸಿ", "emails.verification.footer": "ನೀವು ಇಮೇಲ್ ವಿಳಾಸ ಪರಿಶೀಲನೆಗೆ ಕೇಳದಿದ್ದರೆ, ಈ ಸಂದೇಶವನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ", "emails.verification.thanks": "ಧನ್ಯವಾದಗಳು", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "ಧನ್ಯವಾದಗಳು", "emails.magicSession.signature": "{{project}} ತಂಡ", "emails.recovery.subject": "ಗುಪ್ತಪದ ಮರುಹೊಂದಿಸಿ", - "emails.recovery.hello": "ನಮಸ್ಕಾರ {{name}}", + "emails.recovery.hello": "ನಮಸ್ಕಾರ {{user}}", "emails.recovery.body": "ನಿಮ್ಮ {{project}} ಗುಪ್ತಪದವನ್ನು ಮರುಹೊಂದಿಸಲು ಈ ಲಿಂಕನ್ನು ಅನುಸರಿಸಿ", "emails.recovery.footer": "ನೀವು ಗುಪ್ತಪದವನ್ನು ಮರುಹೊಂದಿಸಲು ಕೇಳದಿದ್ದರೆ, ಈ ಸಂದೇಶವನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ", "emails.recovery.thanks": "ಧನ್ಯವಾದಗಳು", diff --git a/app/config/locale/translations/ko.json b/app/config/locale/translations/ko.json index 7478b45fbe..6bb67d3cc3 100644 --- a/app/config/locale/translations/ko.json +++ b/app/config/locale/translations/ko.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s 팀", "emails.verification.subject": "계정 인증", - "emails.verification.hello": "안녕하세요 {{name}}님", + "emails.verification.hello": "안녕하세요 {{user}}님", "emails.verification.body": "이메일 인증을 위해 링크를 클릭하여주세요.", "emails.verification.footer": "이메일 인증을 부탁하지 않으셨다면 이 메시지를 무시하여주세요.", "emails.verification.thanks": "감사합니다", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "감사합니다", "emails.magicSession.signature": "{{project}} 팀", "emails.recovery.subject": "비밀번호 재설정", - "emails.recovery.hello": "안녕하세요 {{name}}님", + "emails.recovery.hello": "안녕하세요 {{user}}님", "emails.recovery.body": "{{project}}의 비밀번호 재설정을 위해 링크를 클릭하여주세요.", "emails.recovery.footer": "비밀번호 재설정 신청을 하지 않으셨다면 이 메세지를 무시하여주세요.", "emails.recovery.thanks": "감사합니다", diff --git a/app/config/locale/translations/la.json b/app/config/locale/translations/la.json index ea2b276a39..0d766af60f 100644 --- a/app/config/locale/translations/la.json +++ b/app/config/locale/translations/la.json @@ -4,7 +4,7 @@ "settings.direction": "ltr*", "emails.sender": "%s team", "emails.verification.subject": "Ratio comprobatio", - "emails.verification.hello": "Salve ibi {{name}}", + "emails.verification.hello": "Salve ibi {{user}}", "emails.verification.body": "Sequere hanc nexum ut quin inscriptionem tuum.", "emails.verification.footer": "Si verificationem huius inscriptionis non postulasti, nuntium hunc ignorare potes.", "emails.verification.thanks": "Gratias", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Gratias", "emails.magicSession.signature": "{{project}} team", "emails.recovery.subject": "Recuperet password", - "emails.recovery.hello": "Salve ibi {{name}}", + "emails.recovery.hello": "Salve ibi {{user}}", "emails.recovery.body": "Sequere hanc conjunctionem ut recipias project password {{project}}", "emails.recovery.footer": "Si tesseram tuam recuperare non petis, nuntium hunc ignorare potes", "emails.recovery.thanks": "Gratias", diff --git a/app/config/locale/translations/lb.json b/app/config/locale/translations/lb.json index d874d46a70..909887549d 100644 --- a/app/config/locale/translations/lb.json +++ b/app/config/locale/translations/lb.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Team", "emails.verification.subject": "Kont Verifikatioun", - "emails.verification.hello": "Hey {{name}}", + "emails.verification.hello": "Hey {{user}}", "emails.verification.body": "Follegt dëse Link fir Är E -Mail Adress z'iwwerpréiwen.", "emails.verification.footer": "Wann Dir net gefrot hutt dës Adress z'iwwerpréiwen, kënnt Dir dëse Message ignoréieren.", "emails.verification.thanks": "Merci", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Merci", "emails.magicSession.signature": "{{project}} équipe", "emails.recovery.subject": "Password Reset", - "emails.recovery.hello": "Hello {{name}}", + "emails.recovery.hello": "Hello {{user}}", "emails.recovery.body": "Follegt dëse Link fir Äert {{project}} Passwuert zréckzesetzen.", "emails.recovery.footer": "Wann Dir net gefrot hutt Äert Passwuert zréckzesetzen, kënnt Dir dëse Message ignoréieren.", "emails.recovery.thanks": "Merci", diff --git a/app/config/locale/translations/lt.json b/app/config/locale/translations/lt.json index ef836b0ab2..43c5edc947 100644 --- a/app/config/locale/translations/lt.json +++ b/app/config/locale/translations/lt.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s komanda", "emails.verification.subject": "Paskyros Patvirtinimas", - "emails.verification.hello": "Labas {{name}}", + "emails.verification.hello": "Labas {{user}}", "emails.verification.body": "Spauskite šią nuorodą, kad patvirtintumėte savo el. paštą.", "emails.verification.footer": "Jei neprašėte patvirtinti šio el. pašto, galite ignoruoti šį pranešimą.", "emails.verification.thanks": "Ačiū", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Ačiū", "emails.magicSession.signature": "{{project}} komanda", "emails.recovery.subject": "Slaptažodžio Atkūrimas", - "emails.recovery.hello": "Labas {{name}}", + "emails.recovery.hello": "Labas {{user}}", "emails.recovery.body": "Spauskite šią nuorodą, kad atkurtumėte projekto {{project}} slaptažodį.", "emails.recovery.footer": "Jei neprašėte atkurti savo slaptažodzio, galite ignoruoti šį pranešimą.", "emails.recovery.thanks": "Ačiū", diff --git a/app/config/locale/translations/lv.json b/app/config/locale/translations/lv.json index c5fe8533f4..c193296184 100644 --- a/app/config/locale/translations/lv.json +++ b/app/config/locale/translations/lv.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s komanda", "emails.verification.subject": "Konta verifikācija", - "emails.verification.hello": "Sveicināti, {{name}}", + "emails.verification.hello": "Sveicināti, {{user}}", "emails.verification.body": "Sekojiet saitei, lai apstiprinātu savu e-pasta adresi.", "emails.verification.footer": "Ja Jūs nepieprasījāt šīs adreses apstiprinājumu, lūdzu, ignorējiet šo ziņu.", "emails.verification.thanks": "Paldies", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Paldies", "emails.magicSession.signature": "{{project}} komanda", "emails.recovery.subject": "Paroles atjaunināšana", - "emails.recovery.hello": "Labdien, {{name}}", + "emails.recovery.hello": "Labdien, {{user}}", "emails.recovery.body": "Sekojiet saitei, lai atjauninātu {{project}} paroli.", "emails.recovery.footer": "Ja Jūs nepieprasījāt paroles atjaunināšanu, lūdzu, ignorējiet šo ziņu.", "emails.recovery.thanks": "Paldies", diff --git a/app/config/locale/translations/ml.json b/app/config/locale/translations/ml.json index 4997d0dfcd..ae5339f645 100644 --- a/app/config/locale/translations/ml.json +++ b/app/config/locale/translations/ml.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s ടീം", "emails.verification.subject": "അക്കൗണ്ട് സ്ഥിരീകരണം", - "emails.verification.hello": "നമസ്കാരം {{name}}", + "emails.verification.hello": "നമസ്കാരം {{user}}", "emails.verification.body": "നിങ്ങളുടെ ഇമെയിൽ വിലാസം സ്ഥിരീകരിക്കുന്നതിനായി ഈ ലിങ്ക് പിന്തുടരുക.", "emails.verification.footer": "ഈ വിലാസം സ്ഥിരീകരിക്കാന്‍ നിങ്ങൾ ആവശ്യപ്പെട്ടില്ലെങ്കിൽ, നിങ്ങൾക്ക് ഈ സന്ദേശം അവഗണിക്കാവുന്നതാണ്.", "emails.verification.thanks": "നന്ദി", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "നന്ദി", "emails.magicSession.signature": "{{project}} ടീം", "emails.recovery.subject": "രഹസ്യവാക്ക് പുനക്രമീകരണം", - "emails.recovery.hello": "നമസ്കാരം {{name}}", + "emails.recovery.hello": "നമസ്കാരം {{user}}", "emails.recovery.body": "നിങ്ങളുടെ {{Project}} രഹസ്യവാക്ക് പുനക്രമീകരിക്കുന്നതിന് ഈ ലിങ്ക് പിന്തുടരുക.", "emails.recovery.footer": "നിങ്ങളുടെ രഹസ്യവാക്ക് പുനക്രമീകരിക്കാന്‍ നിങ്ങൾ ആവശ്യപ്പെട്ടില്ലെങ്കിൽ, ഈ സന്ദേശം അവഗണിക്കാവുന്നതാണ്.", "emails.recovery.thanks": "നന്ദി", diff --git a/app/config/locale/translations/mr.json b/app/config/locale/translations/mr.json index 1b3adfe061..8f390a4ea0 100644 --- a/app/config/locale/translations/mr.json +++ b/app/config/locale/translations/mr.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s टीम", "emails.verification.subject": "खाते सत्यापन", - "emails.verification.hello": "नमस्कार {{name}}", + "emails.verification.hello": "नमस्कार {{user}}", "emails.verification.body": "आपला ईमेल पत्ता सत्यापित करण्यासाठी या दुव्याचे अनुसरण करा.", "emails.verification.footer": "आपण या पत्त्याची पडताळणी करण्यास सांगितले नसल्यास, आपण या संदेशाकडे दुर्लक्ष करू शकता.", "emails.verification.thanks": "धन्यवाद", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "धन्यवाद", "emails.magicSession.signature": "{{project}} संघ", "emails.recovery.subject": "पासवर्ड रीसेट", - "emails.recovery.hello": "नमस्कार {{name}}", + "emails.recovery.hello": "नमस्कार {{user}}", "emails.recovery.body": "आपला {{project}}चे पासवर्ड रीसेट करण्यासाठी या लिंकचे अनुसरण करा", "emails.recovery.footer": "आपण आपला पासवर्ड रीसेट करण्यास सांगितले नसल्यास, आपण या संदेशाकडे दुर्लक्ष करू शकता.", "emails.recovery.thanks": "धन्यवाद", diff --git a/app/config/locale/translations/ms.json b/app/config/locale/translations/ms.json index 23a302d684..b0543bcc13 100644 --- a/app/config/locale/translations/ms.json +++ b/app/config/locale/translations/ms.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Team", "emails.verification.subject": "Pengesahan Akaun", - "emails.verification.hello": "Hey {{name}}", + "emails.verification.hello": "Hey {{user}}", "emails.verification.body": "Tekan pautan ini untuk mengesahkan alamat email anda.", "emails.verification.footer": "Sekiranya anda tidak membuat permintaan untuk mengesahkan email ini, sila abaikan mesej ini.", "emails.verification.thanks": "Terima kasih", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Terima kasih", "emails.magicSession.signature": "{{project}} team", "emails.recovery.subject": "Menetap semula Kata Laluan", - "emails.recovery.hello": "Hello {{name}}", + "emails.recovery.hello": "Hello {{user}}", "emails.recovery.body": "Tekan pautan ini untuk menetapkan semula kata laluan {{project}}.", "emails.recovery.footer": "Sekiranya anda tidak membuat permintaan menetap semula kata laluan, sila abaikan mesej ini.", "emails.recovery.thanks": "Terima kasih", diff --git a/app/config/locale/translations/nb.json b/app/config/locale/translations/nb.json index 06ea6f8413..4b747d3836 100644 --- a/app/config/locale/translations/nb.json +++ b/app/config/locale/translations/nb.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Team", "emails.verification.subject": "Kontobekreftelse", - "emails.verification.hello": "Hei {{name}}", + "emails.verification.hello": "Hei {{user}}", "emails.verification.body": "Følg denne lenken for å bekrefte din e-postadresse.", "emails.verification.footer": "Dersom du ikke ba om å bekrefte e-postadressen, kan du se bort fra denne meldingen.", "emails.verification.thanks": "Takk", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Takk", "emails.magicSession.signature": "{{project}} team", "emails.recovery.subject": "Nullstille passord", - "emails.recovery.hello": "Hei {{name}}", + "emails.recovery.hello": "Hei {{user}}", "emails.recovery.body": "Følg denne lenken for å nullstille ditt {{project}} passord.", "emails.recovery.footer": "Dersom du ikke ba om å nullstille passordet ditt, kan du se bort fra denne meldingen.", "emails.recovery.thanks": "Takk", diff --git a/app/config/locale/translations/ne.json b/app/config/locale/translations/ne.json index 77de4c1541..a55c8a7f84 100644 --- a/app/config/locale/translations/ne.json +++ b/app/config/locale/translations/ne.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s समूह", "emails.verification.subject": "खाता प्रमाणिकरण", - "emails.verification.hello": "नमस्ते {{name}}", + "emails.verification.hello": "नमस्ते {{user}}", "emails.verification.body": "इमेल ठेगाना प्रमाणित गर्नको लागी यो लिंकमा जानुहोस।", "emails.verification.footer": "यदि तपाइँले आफ्नो खाता प्रमाणित गर्न सोध्नु भएको छैन भने तपाइँले यो सन्देश लाई बेवास्ता गर्न सक्नुहुन्छ।", "emails.verification.thanks": "धन्यवाद", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "धन्यवाद", "emails.magicSession.signature": "{{project}} समूह", "emails.recovery.subject": "पासवर्ड रिसेट", - "emails.recovery.hello": "नमस्ते {{name}}", + "emails.recovery.hello": "नमस्ते {{user}}", "emails.recovery.body": "{{project}}को पासवर्ड रिसेट गर्नको लागी यो लिंकमा जानुहोस।", "emails.recovery.footer": "यदि तपाइँले आफ्नो पासवर्ड रिसेट गर्न सोध्नु भएको छैन भने तपाइँले यो सन्देश लाई बेवास्ता गर्न सक्नुहुन्छ।", "emails.recovery.thanks": "धन्यवाद", diff --git a/app/config/locale/translations/nl.json b/app/config/locale/translations/nl.json index c41d3987bc..98a3999096 100644 --- a/app/config/locale/translations/nl.json +++ b/app/config/locale/translations/nl.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Team", "emails.verification.subject": "Account Verificatie", - "emails.verification.hello": "Hoi {{name}}", + "emails.verification.hello": "Hoi {{user}}", "emails.verification.body": "Volg deze link om uw e-mail te verifieren", "emails.verification.footer": "Als u geen aanvraag voor verificatie heeft gemaakt, kan u deze mail negeren", "emails.verification.thanks": "Bedankt", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Bedankt", "emails.magicSession.signature": "{{project}} team", "emails.recovery.subject": "Wachtwoord Herinstellen", - "emails.recovery.hello": "Hallo {{name}}", + "emails.recovery.hello": "Hallo {{user}}", "emails.recovery.body": "Volg deze link om het wachtwoord van uw project {{project}} te wijzigen", "emails.recovery.footer": "Als u geen aanvraag heeft gemaakt om uw wachtwoord te wijzigen, kan u deze mail negeren", "emails.recovery.thanks": "Bedankt", diff --git a/app/config/locale/translations/nn.json b/app/config/locale/translations/nn.json index b87f14d8d1..6c40f1a514 100644 --- a/app/config/locale/translations/nn.json +++ b/app/config/locale/translations/nn.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Team", "emails.verification.subject": "Kontostadfesting", - "emails.verification.hello": "Hallo {{name}}", + "emails.verification.hello": "Hallo {{user}}", "emails.verification.body": "Følg denne lenkja for å bekrefta din e-postadresse.", "emails.verification.footer": "Om du ikkje bad om å bekrefta e-postadressa, kan du ignorera denne meldinga.", "emails.verification.thanks": "Takk", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Takk", "emails.magicSession.signature": "{{project}} team", "emails.recovery.subject": "Nullstilla passord", - "emails.recovery.hello": "Hallo {{name}}", + "emails.recovery.hello": "Hallo {{user}}", "emails.recovery.body": "Følg denne lenkja for å nullstilla ditt {{project}} passord.", "emails.recovery.footer": "Om du ikkje ba om å nullstilla passordet ditt, kan du ignorera denne meldinga.", "emails.recovery.thanks": "Takk", diff --git a/app/config/locale/translations/or.json b/app/config/locale/translations/or.json index fdf5c7ab34..26ede93c3a 100644 --- a/app/config/locale/translations/or.json +++ b/app/config/locale/translations/or.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s ଦଳ", "emails.verification.subject": "ଖାତା ଯାଞ୍ଚ", - "emails.verification.hello": "ନମସ୍କାର {{name}}", + "emails.verification.hello": "ନମସ୍କାର {{user}}", "emails.verification.body": "ଆପଣଙ୍କର ଇମେଲ୍ ଠିକଣା ଯାଞ୍ଚ କରିବାକୁ ଏହି ଲିଙ୍କ୍ ଅନୁସରଣ କରନ୍ତୁ |", "emails.verification.footer": "ଯଦି ଆପଣ ଏହି ଠିକଣା ଯାଞ୍ଚ କରିବାକୁ କହି ନାହାଁନ୍ତି, ତେବେ ଆପଣ ଏହି ସନ୍ଦେଶକୁ ଉପେକ୍ଷା କରିପାରିବେ |", "emails.verification.thanks": "ଧନ୍ୟବାଦ", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "ଧନ୍ୟବାଦ", "emails.magicSession.signature": "{{project}} ଦଳ", "emails.recovery.subject": "ପାସୱାର୍ଡ ପୁନଃ ସେଟ୍ କରନ୍ତୁ |", - "emails.recovery.hello": "ନମସ୍କାର {{name}}", + "emails.recovery.hello": "ନମସ୍କାର {{user}}", "emails.recovery.body": "ଆପଣଙ୍କର {{project}} ପାସୱାର୍ଡ ପୁନଃ ସେଟ୍ କରିବାକୁ ଏହି ଲିଙ୍କକୁ ଅନୁସରଣ କରନ୍ତୁ |", "emails.recovery.footer": "ଯଦି ଆପଣ ଆପଣଙ୍କର ପାସୱାର୍ଡ ପୁନଃ ସେଟ୍ କରିବାକୁ କହି ନାହାଁନ୍ତି, ତେବେ ଆପଣ ଏହି ସନ୍ଦେଶକୁ ଉପେକ୍ଷା କରିପାରିବେ |", "emails.recovery.thanks": "ଧନ୍ୟବାଦ", diff --git a/app/config/locale/translations/pl.json b/app/config/locale/translations/pl.json index 86c3f73457..f351b8ce23 100644 --- a/app/config/locale/translations/pl.json +++ b/app/config/locale/translations/pl.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Zespół %s", "emails.verification.subject": "Weryfikacja konta", - "emails.verification.hello": "Cześć {{name}}", + "emails.verification.hello": "Cześć {{user}}", "emails.verification.body": "Przejdź do tego linku, aby zweryfikować swój adres e-mail.", "emails.verification.footer": "Jeśli to nie Ty prosiłeś o zweryfikowanie tego adresu, zignoruj tę wiadomość.", "emails.verification.thanks": "Dziękujemy", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Dziękujemy", "emails.magicSession.signature": "Zespół {{project}}", "emails.recovery.subject": "Resetowanie hasła", - "emails.recovery.hello": "Cześć {{name}}", + "emails.recovery.hello": "Cześć {{user}}", "emails.recovery.body": "Przejdź do tego linku, aby zresetować hasło dla {{project}}.", "emails.recovery.footer": "Jeśli to nie Ty prosiłeś o zresetowanie swojego hasła, zignoruj tę wiadomość.", "emails.recovery.thanks": "Dziękujemy", diff --git a/app/config/locale/translations/pt-br.json b/app/config/locale/translations/pt-br.json index 67590d3fe0..d19f374b67 100644 --- a/app/config/locale/translations/pt-br.json +++ b/app/config/locale/translations/pt-br.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Time %s", "emails.verification.subject": "Verificação da Conta", - "emails.verification.hello": "Olá {{name}}", + "emails.verification.hello": "Olá {{user}}", "emails.verification.body": "Clique neste link para verificar o seu endereço de e-mail.", "emails.verification.footer": "Se você não solicitou a verificação deste e-mail, ignore essa mensagem.", "emails.verification.thanks": "Muito obrigado", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Muito obrigado", "emails.magicSession.signature": "Time {{project}}", "emails.recovery.subject": "Redefinição de senha", - "emails.recovery.hello": "Olá {{name}}", + "emails.recovery.hello": "Olá {{user}}", "emails.recovery.body": "Clique neste link para redefinir sua senha do {{project}}.", "emails.recovery.footer": "Se você não solicitou a redefinição da sua senha, você pode ignorar essa mensagem.", "emails.recovery.thanks": "Muito obrigado", diff --git a/app/config/locale/translations/pt-pt.json b/app/config/locale/translations/pt-pt.json index cf9ef377a8..ef45a319a3 100644 --- a/app/config/locale/translations/pt-pt.json +++ b/app/config/locale/translations/pt-pt.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Equipa %s", "emails.verification.subject": "Verificação de contas", - "emails.verification.hello": "Hey {{name}}", + "emails.verification.hello": "Hey {{user}}", "emails.verification.body": "Siga esta ligação para verificar o seu endereço de correio electrónico.", "emails.verification.footer": "Se não pediu para verificar este endereço, pode ignorar esta mensagem.", "emails.verification.thanks": "Obrigado", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Obrigado", "emails.magicSession.signature": "Equipa {{project}}", "emails.recovery.subject": "Redefinição de senha", - "emails.recovery.hello": "Olá {{name}}", + "emails.recovery.hello": "Olá {{user}}", "emails.recovery.body": "Utilize este link para redefinir a palavra-passe do seu projecto {{project}}", "emails.recovery.footer": "Se não pediu para redefinir a sua palavra-passe, pode ignorar esta mensagem.", "emails.recovery.thanks": "Obrigado", diff --git a/app/config/locale/translations/ro.json b/app/config/locale/translations/ro.json index 9976359179..1a3515dc9d 100644 --- a/app/config/locale/translations/ro.json +++ b/app/config/locale/translations/ro.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Echipa", "emails.verification.subject": "Verificare cont", - "emails.verification.hello": "Bună ziua, {{name}}", + "emails.verification.hello": "Bună ziua, {{user}}", "emails.verification.body": "Click pe acest link pentru a valida adresa de email.", "emails.verification.footer": "Dacă nu ai cerut validarea adresei de email, poți ignora acest mesaj.", "emails.verification.thanks": "Mulțumim", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Mulțumim", "emails.magicSession.signature": "Echipa {{project}}", "emails.recovery.subject": "Resetare parolă", - "emails.recovery.hello": "Bună ziua, {{name}}", + "emails.recovery.hello": "Bună ziua, {{user}}", "emails.recovery.body": "Click aici pentru a reseta parola pentru {{project}}", "emails.recovery.footer": "Dacă nu ai cerut să îți schimbi parola, ignoră acest mesaj.", "emails.recovery.thanks": "Mulțumim", diff --git a/app/config/locale/translations/ru.json b/app/config/locale/translations/ru.json index 9221996715..112e320310 100644 --- a/app/config/locale/translations/ru.json +++ b/app/config/locale/translations/ru.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Команда %s", "emails.verification.subject": "Верификация аккаунта", - "emails.verification.hello": "Здравствуйте, {{name}}", + "emails.verification.hello": "Здравствуйте, {{user}}", "emails.verification.body": "Перейдите по ссылке, чтобы подтвердить свой адрес электронной почты.", "emails.verification.footer": "Если вы не запрашивали подтверждение этого адреса, проигнорируйте это сообщение.", "emails.verification.thanks": "Спасибо", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Спасибо", "emails.magicSession.signature": "команда {{project}}", "emails.recovery.subject": "Сброс пароля", - "emails.recovery.hello": "Здравствуйте, {{name}}", + "emails.recovery.hello": "Здравствуйте, {{user}}", "emails.recovery.body": "Перейдите по этой ссылке для того чтобы сбросить свой пароль для проекта {{project}}", "emails.recovery.footer": "Если вы не запрашивали сброс пароля, проигнорируйте это сообщение.", "emails.recovery.thanks": "Спасибо", diff --git a/app/config/locale/translations/sa.json b/app/config/locale/translations/sa.json index f77e5f5d4d..09c5f7a8d2 100644 --- a/app/config/locale/translations/sa.json +++ b/app/config/locale/translations/sa.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s गणः", "emails.verification.subject": "पञ्जिकानिर्णायनम्‌", - "emails.verification.hello": "अयि {{name}}", + "emails.verification.hello": "अयि {{user}}", "emails.verification.body": "ई-पत्रनिर्णायनार्थमिदं संयोगसूत्रमनुसरतु।", "emails.verification.footer": "यदि अस्य संकेतस्य निर्णायनं नेष्यते तर्हि वात्र्तामिमामुपेक्षताम्‌।", "emails.verification.thanks": "धन्यवादः", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "धन्यवादः", "emails.magicSession.signature": "{{project}} गणः", "emails.recovery.subject": "कूटशब्दपुनयाेजनम्‌", - "emails.recovery.hello": "अयि भो {{name}}", + "emails.recovery.hello": "अयि भो {{user}}", "emails.recovery.body": "{{project}} कूटशब्दपुनयाेजनाय संयोगमेनमनुसरतु।", "emails.recovery.footer": "यदि कूटशब्दस्य पुनयाेजनं नेष्यते तर्हि वात्र्तामिमामुपेक्षताम्‌।", "emails.recovery.thanks": "धन्यवादः", diff --git a/app/config/locale/translations/sd.json b/app/config/locale/translations/sd.json index c3aee50f5f..7961b64e4c 100644 --- a/app/config/locale/translations/sd.json +++ b/app/config/locale/translations/sd.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s ٽيم", "emails.verification.subject": " اڪائونٽ جي تصديق", - "emails.verification.hello": "سلام {{name}}", + "emails.verification.hello": "سلام {{user}}", "emails.verification.body": "پنھنجي اي ميل ايڊريس جي تصديق ڪرڻ لاءِ ھن لنڪ تي عمل ڪريو.", "emails.verification.footer": "جيڪڏھن توھان نه پ askيا ھئا ھن ايڊريس جي تصديق ڪرڻ لاءِ ، توھان نظر انداز ڪري سگھوٿا ھن پيغام کي.", "emails.verification.thanks": "مهرباني", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "مهرباني", "emails.magicSession.signature": "{{project}} ٽيم", "emails.recovery.subject": "پاسورڊ ري سيٽ", - "emails.recovery.hello": "هيلو {{name}}", + "emails.recovery.hello": "هيلو {{user}}", "emails.recovery.body": "ھن لنڪ تي عمل ڪريو پنھنجو {{project}} پاسورڊ ري سيٽ ڪرڻ لاءِ.", "emails.recovery.footer": "جيڪڏھن توھان نه پ پيو ھو پنھنجي پاسورڊ کي ري سيٽ ڪرڻ لاءِ ، توھان نظر انداز ڪري سگھوٿا ھن پيغام کي.", "emails.recovery.thanks": "مهرباني", diff --git a/app/config/locale/translations/si.json b/app/config/locale/translations/si.json index 0253a9420c..b10240d77d 100644 --- a/app/config/locale/translations/si.json +++ b/app/config/locale/translations/si.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s කණ්ඩායම", "emails.verification.subject": "ගිණුම් සත්‍යාපනය", - "emails.verification.hello": "හේයි {{name}}", + "emails.verification.hello": "හේයි {{user}}", "emails.verification.body": "ඔබගේ විද්‍යුත් තැපැල් ලිපිනය සත්‍යාපනය කිරීමට මෙම සම්බන්ධකය අනුගමනය කරන්න.", "emails.verification.footer": "මෙම ලිපිනය සත්‍යාපනය කරන ලෙස ඔබ ඉල්ලුවේ නැත්නම්, ඔබට මෙම පණිවිඩය නොසලකා හැරිය හැක.", "emails.verification.thanks": "ස්තුතියි", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "ස්තුතියි", "emails.magicSession.signature": "{{project}} කණ්ඩායම", "emails.recovery.subject": "මුරපද යළි පිහිටුවීම", - "emails.recovery.hello": "ආයුබෝවන් {{name}}", + "emails.recovery.hello": "ආයුබෝවන් {{user}}", "emails.recovery.body": "ඔබගේ {{project}} මුරපදය නැවත සැකසීමට මෙම සම්බන්ධකය අනුගමනය කරන්න.", "emails.recovery.footer": "ඔබගේ මුරපදය නැවත සකසන ලෙස ඔබ ඉල්ලුවේ නැත්නම්, ඔබට මෙම පණිවිඩය නොසලකා හැරිය හැක.", "emails.recovery.thanks": "ස්තුතියි", diff --git a/app/config/locale/translations/sk.json b/app/config/locale/translations/sk.json index b891e4e3a3..a5468ddd6d 100644 --- a/app/config/locale/translations/sk.json +++ b/app/config/locale/translations/sk.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Tím", "emails.verification.subject": "Overenie účtu", - "emails.verification.hello": "Ahoj {{name}}", + "emails.verification.hello": "Ahoj {{user}}", "emails.verification.body": "Použi tento link pre overenie svojej emailovej adresy.", "emails.verification.footer": "Ak si nepožiadal o overenie tejto adresy, môžeš túto správu ignorovať.", "emails.verification.thanks": "Ďakujeme.", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Ďakujeme", "emails.magicSession.signature": "{{project}} tím", "emails.recovery.subject": "Obnovenie hesla", - "emails.recovery.hello": "Ahoj {{name}}", + "emails.recovery.hello": "Ahoj {{user}}", "emails.recovery.body": "Použi tento link pre obnovenie svojho {{project}} hesla.", "emails.recovery.footer": "Ak si nepožiadal o obnovu svojho hesla, túto správu môžeš ignorovať.", "emails.recovery.thanks": "Ďakujeme", diff --git a/app/config/locale/translations/sn.json b/app/config/locale/translations/sn.json index 9d87509e9a..07c00bc29b 100644 --- a/app/config/locale/translations/sn.json +++ b/app/config/locale/translations/sn.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Chikwata che%s", "emails.verification.subject": "Kuratidzi kuti ndiwe muridzi weakaundi", - "emails.verification.hello": "Hesi {{name}}", + "emails.verification.hello": "Hesi {{user}}", "emails.verification.body": "Tevedza chinongedzo ichi kuti uratidze kuti kero iyi ndeyako.", "emails.verification.footer": "Kana usina kukumbira kuti uratidze kuti kero iyi ndeyako, unogona kufuratira meseji iyi.", "emails.verification.thanks": "Ndatenda", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Ndatenda", "emails.magicSession.signature": "Chikwata che{{project}}", "emails.recovery.subject": "Kuchinja pasiwedhi", - "emails.recovery.hello": "Mhoro {{name}}", + "emails.recovery.hello": "Mhoro {{user}}", "emails.recovery.body": "Baya chinongedzo ichi kuti uchinje pasiwedhi yako ye{{project}}.", "emails.recovery.footer": "Kana usina kukumbira kuchinja pasiwedhi yako, unogona kufuratira meseji iyi.", "emails.recovery.thanks": "Ndatenda", diff --git a/app/config/locale/translations/sv.json b/app/config/locale/translations/sv.json index eecca99a55..751fd292a3 100644 --- a/app/config/locale/translations/sv.json +++ b/app/config/locale/translations/sv.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s-teamet", "emails.verification.subject": "Verifiera konto", - "emails.verification.hello": "Hej {{name}}", + "emails.verification.hello": "Hej {{user}}", "emails.verification.body": "Klicka på denna länk för att verifiera din email", "emails.verification.footer": "Om du inte bad om att verifiera den här e-postadressen kan du ignorera detta mail.", "emails.verification.thanks": "Tack", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Tack", "emails.magicSession.signature": "{{project}} teamet", "emails.recovery.subject": "Återställ lösenord", - "emails.recovery.hello": "Hej {{name}}", + "emails.recovery.hello": "Hej {{user}}", "emails.recovery.body": "Klicka på denna länk för att återställa lösenordet på {{project}}", "emails.recovery.footer": "Om du inte bad om att återställa ditt lösenord kan du ignorera detta mail.", "emails.recovery.thanks": "Tack", diff --git a/app/config/locale/translations/ta.json b/app/config/locale/translations/ta.json index 8555a00bf1..5cc09bd9fa 100644 --- a/app/config/locale/translations/ta.json +++ b/app/config/locale/translations/ta.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s குழு", "emails.verification.subject": "கணக்கு சரிபார்ப்பு", - "emails.verification.hello": "ஏய் {{name}}", + "emails.verification.hello": "ஏய் {{user}}", "emails.verification.body": "உங்கள் மின்னஞ்சல் முகவரியைச் சரிபார்க்க இந்த இணைப்பைப் பின்தொடரவும்.", "emails.verification.footer": "இந்த முகவரியைச் சரிபார்க்கும்படி உங்களிடம் கேட்கப்படவில்லை என்றால், இந்தச் செய்தியை நீங்கள் புறக்கணிக்கலாம்.", "emails.verification.thanks": "நன்றி", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "நன்றி", "emails.magicSession.signature": "{{project}} குழு", "emails.recovery.subject": "கடவுச்சொல் மீட்டமைப்பு", - "emails.recovery.hello": "வணக்கம் {{name}}", + "emails.recovery.hello": "வணக்கம் {{user}}", "emails.recovery.body": "மீட்டமைக்க இந்த இணைப்பைப் பின்தொடரவும் {{project}} கடவுச்சொல்.", "emails.recovery.footer": "உங்கள் கடவுச்சொல்லை மீட்டமைக்கும்படி உங்களிடம் கேட்கப்படவில்லை என்றால், இந்தச் செய்தியை நீங்கள் புறக்கணிக்கலாம்.", "emails.recovery.thanks": "நன்றி", diff --git a/app/config/locale/translations/te.json b/app/config/locale/translations/te.json index e9c2a6636a..7cc5cf607b 100644 --- a/app/config/locale/translations/te.json +++ b/app/config/locale/translations/te.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s జట్టు", "emails.verification.subject": "ఖాతా ధృవీకరణ", - "emails.verification.hello": "నమస్కారము {{name}}", + "emails.verification.hello": "నమస్కారము {{user}}", "emails.verification.body": "ఈ లింక్ ద్వారా ఇమెయిల్ ని ధృవీకరించండి", "emails.verification.footer": "మీరు ఈ చిరునామాను ధృవీకరించమని అడగనట్లయితే, మీరు ఈ సందేశాన్ని విస్మరించవచ్చు", "emails.verification.thanks": "ధన్యవాదాలు", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "ధన్యవాదాలు", "emails.magicSession.signature": "{{project}} జట్", "emails.recovery.subject": "పాస్వర్డ్ రీసెట్", - "emails.recovery.hello": "నమస్కారమ {{name}}", + "emails.recovery.hello": "నమస్కారమ {{user}}", "emails.recovery.body": "మీ {{project}} పాస్వర్డ్ ని రీసెట్ చేయడానికి ఈ లింక్ ని అనుసరించండి", "emails.recovery.footer": "మీరు మీ పాస్వర్డ్ ని రీసెట్ చేయమని అడగనట్లయితే, మీరు ఈ సందేశాన్ని విస్మరించవచ్చు", "emails.recovery.thanks": "ధన్యవాదాల", diff --git a/app/config/locale/translations/th.json b/app/config/locale/translations/th.json index 62b8f17cdb..750c173e80 100644 --- a/app/config/locale/translations/th.json +++ b/app/config/locale/translations/th.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "ทีม %s", "emails.verification.subject": "การยืนยันบัญชีผู้ใช้", - "emails.verification.hello": "เรียนคุณ {{name}}", + "emails.verification.hello": "เรียนคุณ {{user}}", "emails.verification.body": "กดเข้าไปที่ลิงก์นี้เพื่อยืนยันอีเมลของท่าน", "emails.verification.footer": "หากท่านไม่ได้ต้องการที่จะยืนยันอีเมลนี้ ท่านสามารถเพิกเฉยข้อความนี้ได้", "emails.verification.thanks": "ขอบคุณ", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "ขอบคุณ", "emails.magicSession.signature": "ทีม {{project}}", "emails.recovery.subject": "รีเซ็ตรหัสผ่าน", - "emails.recovery.hello": "เรียนคุณ {{name}}", + "emails.recovery.hello": "เรียนคุณ {{user}}", "emails.recovery.body": "กดเข้าไปที่ลิงก์นี้เพื่อรีเซ็ตรหัสผ่านสำหรับโปรเจกต์ {{project}} ของท่าน", "emails.recovery.footer": "หากท่านไม่ได้ต้องการที่จะรีเซ็ตรหัสผ่านของท่าน ท่านสามารถเพิกเฉยข้อความนี้ได้", "emails.recovery.thanks": "ขอบคุณ", diff --git a/app/config/locale/translations/tl.json b/app/config/locale/translations/tl.json index 5c88e4cf69..5e45857bfd 100644 --- a/app/config/locale/translations/tl.json +++ b/app/config/locale/translations/tl.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Pangkat ng %s", "emails.verification.subject": "Pagpapatunay ng account", - "emails.verification.hello": "Kamusta {{name}}", + "emails.verification.hello": "Kamusta {{user}}", "emails.verification.body": "Sundin ang link na ito upang ma-verify ang iyong email address.", "emails.verification.footer": "Kung hindi mo hiningi na i-verify ang address na ito, maaari mong balewalain ang mensahe na ito.", "emails.verification.thanks": "Salamat", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Salamat", "emails.magicSession.signature": "Pangkat ng {{project}}", "emails.recovery.subject": "I-reset ang password", - "emails.recovery.hello": "Kamusta {{name}}", + "emails.recovery.hello": "Kamusta {{user}}", "emails.recovery.body": "Sundin ang link na ito upang i-reset ang password ng iyong {{project}}.", "emails.recovery.footer": "Kung hindi mo hiningi na i-reset ang iyong password, maaari mong balewalain ang mensahe na ito.", "emails.recovery.thanks": "Salamat", diff --git a/app/config/locale/translations/uk.json b/app/config/locale/translations/uk.json index ed87f08467..b8269afc1f 100644 --- a/app/config/locale/translations/uk.json +++ b/app/config/locale/translations/uk.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Команда %s", "emails.verification.subject": "Верифікація акаунта", - "emails.verification.hello": "Вітаємо, {{name}}", + "emails.verification.hello": "Вітаємо, {{user}}", "emails.verification.body": "Перейдіть за цим посиланням, щоб підтвердити свою електронну адресу.", "emails.verification.footer": "Якщо ви не запитували підтвердження цієї адреси, ви можете ігнорувати це повідомлення.", "emails.verification.thanks": "Дякуємо", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Дякуємо", "emails.magicSession.signature": "команда {{project}}", "emails.recovery.subject": "Скидання пароля", - "emails.recovery.hello": "Вітаємо, {{name}}", + "emails.recovery.hello": "Вітаємо, {{user}}", "emails.recovery.body": "Перейдіть за цим посиланням для того щоб скинути свій пароль для проекту {{project}}", "emails.recovery.footer": "Якщо ви не запитували скидання паролю, проігноруйте це повідомлення.", "emails.recovery.thanks": "Дякуємо", diff --git a/app/config/locale/translations/ur.json b/app/config/locale/translations/ur.json index 4d92add049..6f769fc604 100644 --- a/app/config/locale/translations/ur.json +++ b/app/config/locale/translations/ur.json @@ -4,7 +4,7 @@ "settings.direction": "rtl", "emails.sender": "%s ٹیم", "emails.verification.subject": "اکاؤنٹ کی تصدیق", - "emails.verification.hello": "خوش آمدید {{name}}", + "emails.verification.hello": "خوش آمدید {{user}}", "emails.verification.body": "براہ کرم اپنے ای میل کی تصدیق کے لیے درج ذیل لنک پر عمل کریں۔", "emails.verification.footer": "اگر آپ نے اس پتے کی تصدیق کے لیے نہیں کہا تو آپ اس پیغام کو نظر انداز کر سکتے ہیں۔", "emails.verification.thanks": "شکریہ", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "شکریہ", "emails.magicSession.signature": "ٹیم۔ {{project}}", "emails.recovery.subject": "پاس ورڈ ری سیٹ۔", - "emails.recovery.hello": "ہیلو {{name}}", + "emails.recovery.hello": "ہیلو {{user}}", "emails.recovery.body": "{{project}} کا پاس ورڈ تبدیل کرنے کے لیے درج ذیل لنک پر عمل کریں", "emails.recovery.footer": "اگر آپ نے اپنا پاس ورڈ دوبارہ ترتیب دینے کے لیے نہیں کہا تو آپ اس پیغام کو نظر انداز کر سکتے ہیں۔", "emails.recovery.thanks": "شکریہ", diff --git a/app/config/locale/translations/vi.json b/app/config/locale/translations/vi.json index 8c72832d2f..3d946fcde4 100644 --- a/app/config/locale/translations/vi.json +++ b/app/config/locale/translations/vi.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "Nhóm %s", "emails.verification.subject": "Xác minh tài khoản", - "emails.verification.hello": "Chào {{name}}", + "emails.verification.hello": "Chào {{user}}", "emails.verification.body": "Nhấn vào đường dẫn sau để xác minh địa chỉ email của bạn.", "emails.verification.footer": "Nếu bạn không yêu cầu xác minh tài khoản, bạn có thể bỏ qua email này.", "emails.verification.thanks": "Cảm ơn", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "Cảm ơn", "emails.magicSession.signature": "Nhóm {{project}}", "emails.recovery.subject": "Thiết lập lại mật khẩu", - "emails.recovery.hello": "Chào {{name}}", + "emails.recovery.hello": "Chào {{user}}", "emails.recovery.body": "Nhấn vào đường dẫn sau để thiết lập lại mật khẩu {{project}} của bạn.", "emails.recovery.footer": "Nếu bạn không yêu cầu thiết lập lại mật khẩu, bạn có thể bỏ qua email này.", "emails.recovery.thanks": "Cảm ơn", diff --git a/app/config/locale/translations/zh-cn.json b/app/config/locale/translations/zh-cn.json index fa997c07f6..289f40dd74 100644 --- a/app/config/locale/translations/zh-cn.json +++ b/app/config/locale/translations/zh-cn.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s 小组", "emails.verification.subject": "帐户验证", - "emails.verification.hello": "你好 {{name}}", + "emails.verification.hello": "你好 {{user}}", "emails.verification.body": "点此链接验证您的电子邮件地址。", "emails.verification.footer": "如果您没有要求验证此地址,则可忽略此消息。", "emails.verification.thanks": "谢谢", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "谢谢", "emails.magicSession.signature": "{{project}} 团队", "emails.recovery.subject": "重设密码", - "emails.recovery.hello": "你好 {{name}}", + "emails.recovery.hello": "你好 {{user}}", "emails.recovery.body": "点此链接重置您的 {{project}} 密码。", "emails.recovery.footer": "如果您没有要求重置密码,则可以忽略此消息。", "emails.recovery.thanks": "谢谢", diff --git a/app/config/locale/translations/zh-tw.json b/app/config/locale/translations/zh-tw.json index 5d3e7141fb..67282e7591 100644 --- a/app/config/locale/translations/zh-tw.json +++ b/app/config/locale/translations/zh-tw.json @@ -4,7 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s 小組", "emails.verification.subject": "帳戶驗證", - "emails.verification.hello": "嗨 {{name}}", + "emails.verification.hello": "嗨 {{user}}", "emails.verification.body": "按照此連結驗證您的電子郵件地址。", "emails.verification.footer": "如果您沒有要求驗證此地址,則可以忽略此消息。", "emails.verification.thanks": "謝謝", @@ -16,7 +16,7 @@ "emails.magicSession.thanks": "謝謝", "emails.magicSession.signature": "{{project}} 團隊", "emails.recovery.subject": "重設密碼", - "emails.recovery.hello": "您好 {{name}}", + "emails.recovery.hello": "您好 {{user}}", "emails.recovery.body": "按照此連結重置您的 {{project}} 密碼。", "emails.recovery.footer": "如果您沒有要求重置密碼,則可以忽略此消息。", "emails.recovery.thanks": "謝謝", diff --git a/app/config/platforms.php b/app/config/platforms.php index 56103fad4a..6efaa3b50d 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -15,7 +15,7 @@ return [ [ 'key' => 'web', 'name' => 'Web', - 'version' => '11.0.0', + 'version' => '12.0.0', 'url' => 'https://github.com/appwrite/sdk-for-web', 'package' => 'https://www.npmjs.com/package/appwrite', 'enabled' => true, @@ -63,7 +63,7 @@ return [ [ 'key' => 'flutter', 'name' => 'Flutter', - 'version' => '9.0.0', + 'version' => '10.0.0', 'url' => 'https://github.com/appwrite/sdk-for-flutter', 'package' => 'https://pub.dev/packages/appwrite', 'enabled' => true, @@ -81,7 +81,7 @@ return [ [ 'key' => 'apple', 'name' => 'Apple', - 'version' => '2.0.0', + 'version' => '3.0.0', 'url' => 'https://github.com/appwrite/sdk-for-apple', 'package' => 'https://github.com/appwrite/sdk-for-apple', 'enabled' => true, @@ -116,7 +116,7 @@ return [ [ 'key' => 'android', 'name' => 'Android', - 'version' => '2.0.0', + 'version' => '3.0.0', 'url' => 'https://github.com/appwrite/sdk-for-android', 'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android', 'enabled' => true, @@ -185,7 +185,7 @@ return [ [ 'key' => 'web', 'name' => 'Console', - 'version' => '0.1.0', + 'version' => '0.3.0', 'url' => 'https://github.com/appwrite/sdk-for-console', 'package' => '', 'enabled' => true, @@ -203,7 +203,7 @@ return [ [ 'key' => 'cli', 'name' => 'Command Line', - 'version' => '2.0.2', + 'version' => '3.0.0', 'url' => 'https://github.com/appwrite/sdk-for-cli', 'package' => 'https://www.npmjs.com/package/appwrite-cli', 'enabled' => true, @@ -231,7 +231,7 @@ return [ [ 'key' => 'nodejs', 'name' => 'Node.js', - 'version' => '9.0.0', + 'version' => '10.0.0', 'url' => 'https://github.com/appwrite/sdk-for-node', 'package' => 'https://www.npmjs.com/package/node-appwrite', 'enabled' => true, @@ -249,7 +249,7 @@ return [ [ 'key' => 'deno', 'name' => 'Deno', - 'version' => '7.0.0', + 'version' => '8.0.0', 'url' => 'https://github.com/appwrite/sdk-for-deno', 'package' => 'https://deno.land/x/appwrite', 'enabled' => true, @@ -267,7 +267,7 @@ return [ [ 'key' => 'php', 'name' => 'PHP', - 'version' => '8.0.0', + 'version' => '9.0.0', 'url' => 'https://github.com/appwrite/sdk-for-php', 'package' => 'https://packagist.org/packages/appwrite/appwrite', 'enabled' => true, @@ -285,7 +285,7 @@ return [ [ 'key' => 'python', 'name' => 'Python', - 'version' => '2.0.2', + 'version' => '3.0.0', 'url' => 'https://github.com/appwrite/sdk-for-python', 'package' => 'https://pypi.org/project/appwrite/', 'enabled' => true, @@ -303,7 +303,7 @@ return [ [ 'key' => 'ruby', 'name' => 'Ruby', - 'version' => '8.0.0', + 'version' => '9.0.0', 'url' => 'https://github.com/appwrite/sdk-for-ruby', 'package' => 'https://rubygems.org/gems/appwrite', 'enabled' => true, @@ -357,7 +357,7 @@ return [ [ 'key' => 'dotnet', 'name' => '.NET', - 'version' => '0.4.2', + 'version' => '0.5.0', 'url' => 'https://github.com/appwrite/sdk-for-dotnet', 'package' => 'https://www.nuget.org/packages/Appwrite', 'enabled' => true, @@ -375,7 +375,7 @@ return [ [ 'key' => 'dart', 'name' => 'Dart', - 'version' => '8.0.0', + 'version' => '9.0.0', 'url' => 'https://github.com/appwrite/sdk-for-dart', 'package' => 'https://pub.dev/packages/dart_appwrite', 'enabled' => true, @@ -393,7 +393,7 @@ return [ [ 'key' => 'kotlin', 'name' => 'Kotlin', - 'version' => '2.0.0', + 'version' => '3.0.0', 'url' => 'https://github.com/appwrite/sdk-for-kotlin', 'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin', 'enabled' => true, @@ -415,7 +415,7 @@ return [ [ 'key' => 'swift', 'name' => 'Swift', - 'version' => '2.0.0', + 'version' => '3.0.0', 'url' => 'https://github.com/appwrite/sdk-for-swift', 'package' => 'https://github.com/appwrite/sdk-for-swift', 'enabled' => true, diff --git a/app/config/providers.php b/app/config/providers.php index dedb4ec665..6ba54f28e4 100644 --- a/app/config/providers.php +++ b/app/config/providers.php @@ -1,6 +1,7 @@ [ 'name' => 'Amazon', 'developers' => 'https://developer.amazon.com/apps-and-games/services-and-apis', diff --git a/app/config/roles.php b/app/config/roles.php index f0039841d2..abc00b55bf 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -3,6 +3,7 @@ use Appwrite\Auth\Auth; $member = [ + 'global', 'public', 'home', 'console', @@ -23,6 +24,7 @@ $member = [ ]; $admins = [ + 'global', 'graphql', 'teams.read', 'teams.write', @@ -51,6 +53,13 @@ $admins = [ 'functions.write', 'execution.read', 'execution.write', + 'rules.read', + 'rules.write', + 'migrations.read', + 'migrations.write', + 'vcs.read', + 'vcs.write', + 'assistant.read', ]; return [ @@ -72,22 +81,22 @@ return [ ], Auth::USER_ROLE_USERS => [ 'label' => 'Users', - 'scopes' => \array_merge($member, []), + 'scopes' => \array_merge($member), ], Auth::USER_ROLE_ADMIN => [ 'label' => 'Admin', - 'scopes' => \array_merge($admins, []), + 'scopes' => \array_merge($admins), ], Auth::USER_ROLE_DEVELOPER => [ 'label' => 'Developer', - 'scopes' => \array_merge($admins, []), + 'scopes' => \array_merge($admins), ], Auth::USER_ROLE_OWNER => [ 'label' => 'Owner', - 'scopes' => \array_merge($member, $admins, []), + 'scopes' => \array_merge($member, $admins), ], Auth::USER_ROLE_APPS => [ 'label' => 'Applications', - 'scopes' => ['health.read', 'graphql'], + 'scopes' => ['global', 'health.read', 'graphql'], ], ]; diff --git a/app/config/runtimes.php b/app/config/runtimes.php index c24aaa109e..2cd73c1b70 100644 --- a/app/config/runtimes.php +++ b/app/config/runtimes.php @@ -7,7 +7,7 @@ use Utopia\App; use Appwrite\Runtimes\Runtimes; -$runtimes = new Runtimes('v2'); +$runtimes = new Runtimes('v3'); $allowList = empty(App::getEnv('_APP_FUNCTIONS_RUNTIMES')) ? [] : \explode(',', App::getEnv('_APP_FUNCTIONS_RUNTIMES')); diff --git a/app/config/scopes.php b/app/config/scopes.php index f62090cdd5..ddc1de21f3 100644 --- a/app/config/scopes.php +++ b/app/config/scopes.php @@ -106,4 +106,25 @@ return [ // List of publicly visible scopes 'targets.write' => [ 'description' => 'Access to create, update, and delete your project\'s targets', ], + 'rules.read' => [ + 'description' => 'Access to read your project\'s proxy rules', + ], + 'rules.write' => [ + 'description' => 'Access to create, update, and delete your project\'s proxy rules', + ], + 'migrations.read' => [ + 'description' => 'Access to read your project\'s migrations', + ], + 'migrations.write' => [ + 'description' => 'Access to create, update, and delete your project\'s migrations.', + ], + 'vcs.read' => [ + 'description' => 'Access to read your project\'s VCS repositories', + ], + 'vcs.write' => [ + 'description' => 'Access to create, update, and delete your project\'s VCS repositories', + ], + 'assistant.read' => [ + 'description' => 'Access to read the Assistant service', + ], ]; diff --git a/app/config/services.php b/app/config/services.php index f76c46b013..3700af659a 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -160,6 +160,19 @@ return [ 'optional' => true, 'icon' => '/images/services/users.png', ], + 'vcs' => [ + 'key' => 'vcs', + 'name' => 'VCS', + 'subtitle' => 'The VCS service allows you to interact with providers like GitHub, GitLab etc.', + 'description' => '', + 'controller' => 'api/vcs.php', + 'sdk' => false, + 'docs' => false, + 'docsUrl' => '', + 'tests' => false, + 'optional' => true, + 'icon' => '', + ], 'functions' => [ 'key' => 'functions', 'name' => 'Functions', @@ -173,6 +186,19 @@ return [ 'optional' => true, 'icon' => '/images/services/functions.png', ], + 'proxy' => [ + 'key' => 'proxy', + 'name' => 'Proxy', + 'subtitle' => 'The Proxy Service allows you to configure actions for your domains beyond DNS configuration.', + 'description' => '/docs/services/proxy.md', + 'controller' => 'api/proxy.php', + 'sdk' => true, + 'docs' => true, + 'docsUrl' => 'https://appwrite.io/docs/proxy', + 'tests' => false, + 'optional' => true, + 'icon' => '/images/services/proxy.png', + ], 'mock' => [ 'key' => 'mock', 'name' => 'Mock', @@ -212,4 +238,17 @@ return [ 'optional' => false, 'icon' => '', ], + 'migrations' => [ + 'key' => 'migrations', + 'name' => 'Migrations', + 'subtitle' => 'The Migrations service allows you to migrate third-party data to your Appwrite project.', + 'description' => '/docs/services/migrations.md', + 'controller' => 'api/migrations.php', + 'sdk' => true, + 'docs' => true, + 'docsUrl' => 'https://appwrite.io/docs/migrations', + 'tests' => true, + 'optional' => true, + 'icon' => '/images/services/migrations.png', + ], ]; diff --git a/app/config/specs/open-api3-1.4.x-client.json b/app/config/specs/open-api3-1.4.x-client.json index 91759a2ed8..f3e8254dde 100644 --- a/app/config/specs/open-api3-1.4.x-client.json +++ b/app/config/specs/open-api3-1.4.x-client.json @@ -1 +1 @@ -{"openapi":"3.0.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/jwt"}}}}},"x-appwrite":{"method":"createJWT","weight":18,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createAnonymousSession","weight":17,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createMagicURLSession","weight":13,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}}}},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateMagicURLSession","weight":14,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"File"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"schema":{"type":"string","x-example":"amazon"},"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneSession","weight":15,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"}},"required":["userId","phone"]}}}}},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updatePhoneSession","weight":16,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa"},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex"},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af"},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","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](\/docs\/permissions).","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"openapi":"3.0.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":21,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":28,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","weight":13,"cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":14,"cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/jwt"}}}}},"x-appwrite":{"method":"createJWT","weight":20,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":24,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":26,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":27,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":29,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":22,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":30,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":35,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":36,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":23,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":34,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createAnonymousSession","weight":19,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createMagicURLSession","weight":15,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}}}},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateMagicURLSession","weight":16,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"File"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"schema":{"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[]},"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneSession","weight":17,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"}},"required":["userId","phone"]}}}}},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updatePhoneSession","weight":18,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":25,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":33,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":32,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":31,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":39,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":40,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":47,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":46,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":91,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":90,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":92,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":94,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":95,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":253,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":252,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","x-example":"[BODY]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false},"path":{"type":"string","description":"HTTP path of execution. Path can include query params. Default value is \/","x-example":"[PATH]"},"method":{"type":"string","description":"HTTP method of execution. Default value is GET.","x-example":"GET","enum":["GET","POST","PUT","PATCH","DELETE","OPTIONS"],"x-enum-name":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","x-example":"{}"}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":254,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":293,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":292,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":99,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":100,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":104,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":102,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":103,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":105,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":106,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":173,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":172,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":174,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":178,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":179,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":176,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":175,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":177,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":183,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":182,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":184,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":186,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":188,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":190,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":189,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":191,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembership","weight":192,"cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":194,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":193,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":185,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":187,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"$ref":"#\/components\/schemas\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/open-api3-1.4.x-console.json b/app/config/specs/open-api3-1.4.x-console.json index 127a83be89..fd8212e58e 100644 --- a/app/config/specs/open-api3-1.4.x-console.json +++ b/app/config/specs/open-api3-1.4.x-console.json @@ -1 +1 @@ -{"openapi":"3.0.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/invite":{"post":{"summary":"Create account using an invite code","operationId":"accountCreateWithInviteCode","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"Account","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/account"}}}}},"x-appwrite":{"method":"createWithInviteCode","weight":6,"cookies":false,"type":"","demo":"account\/create-with-invite-code.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose your own unique ID or pass the string `ID.unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"},"code":{"type":"string","description":"An invite code to restrict user signups on the Appwrite console. Users with an invite code will be able to create accounts irrespective of email and IP whitelists.","x-example":"[CODE]"}},"required":["userId","email","password"]}}}}}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/jwt"}}}}},"x-appwrite":{"method":"createJWT","weight":18,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createAnonymousSession","weight":17,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createMagicURLSession","weight":13,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}}}},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateMagicURLSession","weight":14,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"File"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"schema":{"type":"string","x-example":"amazon"},"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneSession","weight":15,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"}},"required":["userId","phone"]}}}}},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updatePhoneSession","weight":16,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa"},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex"},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af"},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/console\/variables":{"get":{"summary":"Get Variables","operationId":"consoleVariables","tags":["console"],"description":"Get all Environment Variables that are relevant for the console.","responses":{"200":{"description":"Console Variables","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/consoleVariables"}}}}},"x-appwrite":{"method":"variables","weight":274,"cookies":false,"type":"","demo":"console\/variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/console\/variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/databaseList"}}}}},"x-appwrite":{"method":"list","weight":50,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"create","weight":49,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","x-example":false}},"required":["databaseId","name"]}}}}}},"\/databases\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabases","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageDatabases"}}}}},"x-appwrite":{"method":"getUsage","weight":94,"cookies":false,"type":"","demo":"databases\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"`Date range.","required":false,"schema":{"type":"string","x-example":"24h","default":"30d"},"in":"query"}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"get","weight":51,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"update","weight":53,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Database","operationId":"databasesDelete","tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":54,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collectionList"}}}}},"x-appwrite":{"method":"listCollections","weight":56,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"createCollection","weight":55,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","x-example":false}},"required":["collectionId","name"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"getCollection","weight":57,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"updateCollection","weight":59,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":60,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeList"}}}}},"x-appwrite":{"method":"listAttributes","weight":71,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"createBooleanAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"createEmailAttribute","weight":62,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"updateEmailAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"createEnumAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","elements","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"updateEnumAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"createFloatAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"updateFloatAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"createIntegerAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"createIpAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"updateIpAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","x-example":"oneToOne"},"twoWay":{"type":"boolean","description":"Is Two Way?","x-example":false},"key":{"type":"string","description":"Attribute Key.","x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","x-example":null},"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade"}},"required":["relatedCollectionId","type"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"createStringAttribute","weight":61,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","x-example":1},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","size","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"updateStringAttribute","weight":73,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"createUrlAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"updateUrlAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","content":{"application\/json":{"schema":{"oneOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]}}}}},"x-appwrite":{"method":"getAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade"}}}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/logs":{"get":{"summary":"List Document Logs","operationId":"databasesListDocumentLogs","tags":["databases"],"description":"Get the document activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listDocumentLogs","weight":91,"cookies":false,"type":"","demo":"databases\/list-document-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/indexList"}}}}},"x-appwrite":{"method":"listIndexes","weight":85,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","tags":["databases"],"description":"","responses":{"202":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"createIndex","weight":84,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":null},"type":{"type":"string","description":"Index type.","x-example":"key"},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","tags":["databases"],"description":"","responses":{"200":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"getIndex","weight":86,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":87,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/logs":{"get":{"summary":"List Collection Logs","operationId":"databasesListCollectionLogs","tags":["databases"],"description":"Get the collection activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listCollectionLogs","weight":58,"cookies":false,"type":"","demo":"databases\/list-collection-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/usage":{"get":{"summary":"Get usage stats for a collection","operationId":"databasesGetCollectionUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageCollection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageCollection"}}}}},"x-appwrite":{"method":"getCollectionUsage","weight":96,"cookies":false,"type":"","demo":"databases\/get-collection-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","default":"30d"},"in":"query"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/logs":{"get":{"summary":"List Database Logs","operationId":"databasesListLogs","tags":["databases"],"description":"Get the database activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":52,"cookies":false,"type":"","demo":"databases\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetDatabaseUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabase","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageDatabase"}}}}},"x-appwrite":{"method":"getDatabaseUsage","weight":95,"cookies":false,"type":"","demo":"databases\/get-database-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"range","description":"`Date range.","required":false,"schema":{"type":"string","x-example":"24h","default":"30d"},"in":"query"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/functionList"}}}}},"x-appwrite":{"method":"list","weight":222,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"create","weight":221,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","x-example":false}},"required":["functionId","name","runtime"]}}}}}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/runtimeList"}}}}},"x-appwrite":{"method":"listRuntimes","weight":223,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/usage":{"get":{"summary":"Get Functions Usage","operationId":"functionsGetUsage","tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageFunctions"}}}}},"x-appwrite":{"method":"getUsage","weight":226,"cookies":false,"type":"","demo":"functions\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","default":"30d"},"in":"query"}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"get","weight":224,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"update","weight":227,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Function","operationId":"functionsDelete","tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":229,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deploymentList"}}}}},"x-appwrite":{"method":"listDeployments","weight":231,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: entrypoint, size, buildId, activate","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","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](\/docs\/functions).\n\nUse the \"command\" param to set the entry point used to execute your code.","responses":{"202":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"createDeployment","weight":230,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"entrypoint":{"type":"string","description":"Entrypoint File.","x-example":"[ENTRYPOINT]"},"code":{"type":"string","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","x-example":null},"activate":{"type":"boolean","description":"Automatically activate the deployment when it is finished building.","x-example":false}},"required":["entrypoint","code","activate"]}}}}}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"getDeployment","weight":232,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"updateDeployment","weight":228,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":233,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","tags":["functions"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":234,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"schema":{"type":"string","x-example":"[BUILD_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/usage":{"get":{"summary":"Get Function Usage","operationId":"functionsGetFunctionUsage","tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageFunctions"}}}}},"x-appwrite":{"method":"getFunctionUsage","weight":225,"cookies":false,"type":"","demo":"functions\/get-function-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","default":"30d"},"in":"query"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","weight":239,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","tags":["functions"],"description":"Create a new function variable. These variables can be accessed within function in the `env` object under the request variable.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","weight":238,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","weight":240,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","weight":241,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":242,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"get","weight":105,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthAntivirus"}}}}},"x-appwrite":{"method":"getAntivirus","weight":117,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getCache","weight":108,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getDB","weight":107,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getPubSub","weight":110,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getQueue","weight":109,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueCertificates","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueFunctions","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueLogs","weight":113,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueWebhooks","weight":112,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getStorageLocal","weight":116,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthTime"}}}}},"x-appwrite":{"method":"getTime","weight":111,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/project\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectGetUsage","tags":["project"],"description":"","responses":{"200":{"description":"UsageProject","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageProject"}}}}},"x-appwrite":{"method":"getUsage","weight":163,"cookies":false,"type":"","demo":"project\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","default":"30d"},"in":"query"}]}},"\/projects":{"get":{"summary":"List Projects","operationId":"projectsList","tags":["projects"],"description":"","responses":{"200":{"description":"Projects List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/projectList"}}}}},"x-appwrite":{"method":"list","weight":120,"cookies":false,"type":"","demo":"projects\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Project","operationId":"projectsCreate","tags":["projects"],"description":"","responses":{"201":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"create","weight":119,"cookies":false,"type":"","demo":"projects\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.","x-example":null},"name":{"type":"string","description":"Project name. Max length: 128 chars.","x-example":"[NAME]"},"teamId":{"type":"string","description":"Team unique ID.","x-example":"[TEAM_ID]"},"region":{"type":"string","description":"Project Region.","x-example":"default"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal Name. Max length: 256 chars.","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal Country. Max length: 256 chars.","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal State. Max length: 256 chars.","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal City. Max length: 256 chars.","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal Address. Max length: 256 chars.","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal Tax ID. Max length: 256 chars.","x-example":"[LEGAL_TAX_ID]"}},"required":["projectId","name","teamId"]}}}}}},"\/projects\/{projectId}":{"get":{"summary":"Get Project","operationId":"projectsGet","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"get","weight":121,"cookies":false,"type":"","demo":"projects\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"patch":{"summary":"Update Project","operationId":"projectsUpdate","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"update","weight":122,"cookies":false,"type":"","demo":"projects\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name. Max length: 128 chars.","x-example":"[NAME]"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal name. Max length: 256 chars.","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal country. Max length: 256 chars.","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal state. Max length: 256 chars.","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal city. Max length: 256 chars.","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal address. Max length: 256 chars.","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal tax ID. Max length: 256 chars.","x-example":"[LEGAL_TAX_ID]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Project","operationId":"projectsDelete","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":134,"cookies":false,"type":"","demo":"projects\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/auth\/duration":{"patch":{"summary":"Update Project Authentication Duration","operationId":"projectsUpdateAuthDuration","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthDuration","weight":128,"cookies":false,"type":"","demo":"projects\/update-auth-duration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"duration":{"type":"integer","description":"Project session length in seconds. Max length: 31536000 seconds.","x-example":0}},"required":["duration"]}}}}}},"\/projects\/{projectId}\/auth\/limit":{"patch":{"summary":"Update Project users limit","operationId":"projectsUpdateAuthLimit","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthLimit","weight":127,"cookies":false,"type":"","demo":"projects\/update-auth-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Use 0 for unlimited.","x-example":0}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/max-sessions":{"patch":{"summary":"Update Project user sessions limit","operationId":"projectsUpdateAuthSessionsLimit","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthSessionsLimit","weight":133,"cookies":false,"type":"","demo":"projects\/update-auth-sessions-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10","x-example":1}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/password-dictionary":{"patch":{"summary":"Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password","operationId":"projectsUpdateAuthPasswordDictionary","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthPasswordDictionary","weight":131,"cookies":false,"type":"","demo":"projects\/update-auth-password-dictionary.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to enable checking user's password against most commonly used passwords. Default is false.","x-example":false}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/auth\/password-history":{"patch":{"summary":"Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.","operationId":"projectsUpdateAuthPasswordHistory","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthPasswordHistory","weight":130,"cookies":false,"type":"","demo":"projects\/update-auth-password-history.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0","x-example":0}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/personal-data":{"patch":{"summary":"Enable or disable checking user passwords for similarity with their personal data.","operationId":"projectsUpdatePersonalDataCheck","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updatePersonalDataCheck","weight":132,"cookies":false,"type":"","demo":"projects\/update-personal-data-check.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to check a password for similarity with personal data. Default is false.","x-example":false}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/auth\/{method}":{"patch":{"summary":"Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.","operationId":"projectsUpdateAuthStatus","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthStatus","weight":129,"cookies":false,"type":"","demo":"projects\/update-auth-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"method","description":"Auth Method. Possible values: email-password,magic-url,anonymous,invites,jwt,phone","required":true,"schema":{"type":"string","x-example":"email-password"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Set the status of this auth method.","x-example":false}},"required":["status"]}}}}}},"\/projects\/{projectId}\/domains":{"get":{"summary":"List Domains","operationId":"projectsListDomains","tags":["projects"],"description":"","responses":{"200":{"description":"Domains List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/domainList"}}}}},"x-appwrite":{"method":"listDomains","weight":152,"cookies":false,"type":"","demo":"projects\/list-domains.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Domain","operationId":"projectsCreateDomain","tags":["projects"],"description":"","responses":{"201":{"description":"Domain","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/domain"}}}}},"x-appwrite":{"method":"createDomain","weight":151,"cookies":false,"type":"","demo":"projects\/create-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain name.","x-example":null}},"required":["domain"]}}}}}},"\/projects\/{projectId}\/domains\/{domainId}":{"get":{"summary":"Get Domain","operationId":"projectsGetDomain","tags":["projects"],"description":"","responses":{"200":{"description":"Domain","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/domain"}}}}},"x-appwrite":{"method":"getDomain","weight":153,"cookies":false,"type":"","demo":"projects\/get-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"schema":{"type":"string","x-example":"[DOMAIN_ID]"},"in":"path"}]},"delete":{"summary":"Delete Domain","operationId":"projectsDeleteDomain","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDomain","weight":155,"cookies":false,"type":"","demo":"projects\/delete-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"schema":{"type":"string","x-example":"[DOMAIN_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/domains\/{domainId}\/verification":{"patch":{"summary":"Update Domain Verification Status","operationId":"projectsUpdateDomainVerification","tags":["projects"],"description":"","responses":{"200":{"description":"Domain","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/domain"}}}}},"x-appwrite":{"method":"updateDomainVerification","weight":154,"cookies":false,"type":"","demo":"projects\/update-domain-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"schema":{"type":"string","x-example":"[DOMAIN_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/keys":{"get":{"summary":"List Keys","operationId":"projectsListKeys","tags":["projects"],"description":"","responses":{"200":{"description":"API Keys List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/keyList"}}}}},"x-appwrite":{"method":"listKeys","weight":142,"cookies":false,"type":"","demo":"projects\/list-keys.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Key","operationId":"projectsCreateKey","tags":["projects"],"description":"","responses":{"201":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"createKey","weight":141,"cookies":false,"type":"","demo":"projects\/create-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 scopes are allowed.","x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","x-example":null}},"required":["name","scopes"]}}}}}},"\/projects\/{projectId}\/keys\/{keyId}":{"get":{"summary":"Get Key","operationId":"projectsGetKey","tags":["projects"],"description":"","responses":{"200":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"getKey","weight":143,"cookies":false,"type":"","demo":"projects\/get-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}]},"put":{"summary":"Update Key","operationId":"projectsUpdateKey","tags":["projects"],"description":"","responses":{"200":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"updateKey","weight":144,"cookies":false,"type":"","demo":"projects\/update-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","x-example":null}},"required":["name","scopes"]}}}}},"delete":{"summary":"Delete Key","operationId":"projectsDeleteKey","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteKey","weight":145,"cookies":false,"type":"","demo":"projects\/delete-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/oauth2":{"patch":{"summary":"Update Project OAuth2","operationId":"projectsUpdateOAuth2","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateOAuth2","weight":126,"cookies":false,"type":"","demo":"projects\/update-o-auth2.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","description":"Provider Name","x-example":"amazon"},"appId":{"type":"string","description":"Provider app ID. Max length: 256 chars.","x-example":"[APP_ID]"},"secret":{"type":"string","description":"Provider secret key. Max length: 512 chars.","x-example":"[SECRET]"},"enabled":{"type":"boolean","description":"Provider status. Set to 'false' to disable new session creation.","x-example":false}},"required":["provider"]}}}}}},"\/projects\/{projectId}\/platforms":{"get":{"summary":"List Platforms","operationId":"projectsListPlatforms","tags":["projects"],"description":"","responses":{"200":{"description":"Platforms List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platformList"}}}}},"x-appwrite":{"method":"listPlatforms","weight":147,"cookies":false,"type":"","demo":"projects\/list-platforms.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Platform","operationId":"projectsCreatePlatform","tags":["projects"],"description":"","responses":{"201":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"createPlatform","weight":146,"cookies":false,"type":"","demo":"projects\/create-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"Platform type.","x-example":"web"},"name":{"type":"string","description":"Platform name. Max length: 128 chars.","x-example":"[NAME]"},"key":{"type":"string","description":"Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client hostname. Max length: 256 chars.","x-example":null}},"required":["type","name"]}}}}}},"\/projects\/{projectId}\/platforms\/{platformId}":{"get":{"summary":"Get Platform","operationId":"projectsGetPlatform","tags":["projects"],"description":"","responses":{"200":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"getPlatform","weight":148,"cookies":false,"type":"","demo":"projects\/get-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}]},"put":{"summary":"Update Platform","operationId":"projectsUpdatePlatform","tags":["projects"],"description":"","responses":{"200":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"updatePlatform","weight":149,"cookies":false,"type":"","demo":"projects\/update-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Platform name. Max length: 128 chars.","x-example":"[NAME]"},"key":{"type":"string","description":"Package name for android or bundle ID for iOS. Max length: 256 chars.","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client URL. Max length: 256 chars.","x-example":null}},"required":["name"]}}}}},"delete":{"summary":"Delete Platform","operationId":"projectsDeletePlatform","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deletePlatform","weight":150,"cookies":false,"type":"","demo":"projects\/delete-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/service":{"patch":{"summary":"Update service status","operationId":"projectsUpdateServiceStatus","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateServiceStatus","weight":124,"cookies":false,"type":"","demo":"projects\/update-service-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"service":{"type":"string","description":"Service name.","x-example":"account"},"status":{"type":"boolean","description":"Service status.","x-example":false}},"required":["service","status"]}}}}}},"\/projects\/{projectId}\/service\/all":{"patch":{"summary":"Update all service status","operationId":"projectsUpdateServiceStatusAll","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateServiceStatusAll","weight":125,"cookies":false,"type":"","demo":"projects\/update-service-status-all.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Service status.","x-example":false}},"required":["status"]}}}}}},"\/projects\/{projectId}\/smtp":{"patch":{"summary":"Update SMTP configuration","operationId":"projectsUpdateSmtpConfiguration","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateSmtpConfiguration","weight":156,"cookies":false,"type":"","demo":"projects\/update-smtp-configuration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable custom SMTP service","x-example":false},"sender":{"type":"string","description":"SMTP sender email","x-example":"email@example.com"},"host":{"type":"string","description":"SMTP server host name","x-example":null},"port":{"type":"integer","description":"SMTP server port","x-example":null},"username":{"type":"string","description":"SMTP server username","x-example":"[USERNAME]"},"password":{"type":"string","description":"SMTP server password","x-example":"[PASSWORD]"},"secure":{"type":"string","description":"Does SMTP server use secure connection","x-example":"tls"}},"required":["enabled","sender","host","port","username","password"]}}}}}},"\/projects\/{projectId}\/team":{"patch":{"summary":"Update Project Team","operationId":"projectsUpdateTeam","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateTeam","weight":123,"cookies":false,"type":"","demo":"projects\/update-team.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID of the team to transfer project to.","x-example":"[TEAM_ID]"}},"required":["teamId"]}}}}}},"\/projects\/{projectId}\/templates\/email\/{type}\/{locale}":{"get":{"summary":"Get custom email template","operationId":"projectsGetEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/emailTemplate"}}}}},"x-appwrite":{"method":"getEmailTemplate","weight":158,"cookies":false,"type":"","demo":"projects\/get-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification"},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af"},"in":"path"}]},"patch":{"summary":"Update custom email templates","operationId":"projectsUpdateEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateEmailTemplate","weight":160,"cookies":false,"type":"","demo":"projects\/update-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification"},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"senderName":{"type":"string","description":"Name of the email sender","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"email@example.com"},"subject":{"type":"string","description":"Email Subject","x-example":"[SUBJECT]"},"message":{"type":"string","description":"Template message","x-example":"[MESSAGE]"},"replyTo":{"type":"string","description":"Reply to email","x-example":"email@example.com"}},"required":["senderName","senderEmail","subject","message"]}}}}},"delete":{"summary":"Reset custom email template","operationId":"projectsDeleteEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/emailTemplate"}}}}},"x-appwrite":{"method":"deleteEmailTemplate","weight":162,"cookies":false,"type":"","demo":"projects\/delete-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification"},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af"},"in":"path"}]}},"\/projects\/{projectId}\/templates\/sms\/{type}\/{locale}":{"get":{"summary":"Get custom SMS template","operationId":"projectsGetSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"getSmsTemplate","weight":157,"cookies":false,"type":"","demo":"projects\/get-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification"},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af"},"in":"path"}]},"patch":{"summary":"Update custom SMS template","operationId":"projectsUpdateSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"updateSmsTemplate","weight":159,"cookies":false,"type":"","demo":"projects\/update-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification"},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Template message","x-example":"[MESSAGE]"}},"required":["message"]}}}}},"delete":{"summary":"Reset custom SMS template","operationId":"projectsDeleteSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"deleteSmsTemplate","weight":161,"cookies":false,"type":"","demo":"projects\/delete-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification"},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af"},"in":"path"}]}},"\/projects\/{projectId}\/webhooks":{"get":{"summary":"List Webhooks","operationId":"projectsListWebhooks","tags":["projects"],"description":"","responses":{"200":{"description":"Webhooks List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhookList"}}}}},"x-appwrite":{"method":"listWebhooks","weight":136,"cookies":false,"type":"","demo":"projects\/list-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Webhook","operationId":"projectsCreateWebhook","tags":["projects"],"description":"","responses":{"201":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"createWebhook","weight":135,"cookies":false,"type":"","demo":"projects\/create-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}}}}},"\/projects\/{projectId}\/webhooks\/{webhookId}":{"get":{"summary":"Get Webhook","operationId":"projectsGetWebhook","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"getWebhook","weight":137,"cookies":false,"type":"","demo":"projects\/get-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]},"put":{"summary":"Update Webhook","operationId":"projectsUpdateWebhook","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"updateWebhook","weight":138,"cookies":false,"type":"","demo":"projects\/update-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}}}},"delete":{"summary":"Delete Webhook","operationId":"projectsDeleteWebhook","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteWebhook","weight":140,"cookies":false,"type":"","demo":"projects\/delete-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}\/signature":{"patch":{"summary":"Update Webhook Signature Key","operationId":"projectsUpdateWebhookSignature","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"updateWebhookSignature","weight":139,"cookies":false,"type":"","demo":"projects\/update-webhook-signature.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucketList"}}}}},"x-appwrite":{"method":"listBuckets","weight":165,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"createBucket","weight":164,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none"},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["bucketId","name"]}}}}}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"getBucket","weight":166,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"updateBucket","weight":167,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none"},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":168,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/usage":{"get":{"summary":"Get usage stats for storage","operationId":"storageGetUsage","tags":["storage"],"description":"","responses":{"200":{"description":"StorageUsage","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageStorage"}}}}},"x-appwrite":{"method":"getUsage","weight":177,"cookies":false,"type":"","demo":"storage\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","default":"30d"},"in":"query"}]}},"\/storage\/{bucketId}\/usage":{"get":{"summary":"Get usage stats for storage bucket","operationId":"storageGetBucketUsage","tags":["storage"],"description":"","responses":{"200":{"description":"UsageBuckets","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageBuckets"}}}}},"x-appwrite":{"method":"getBucketUsage","weight":178,"cookies":false,"type":"","demo":"storage\/get-bucket-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"bucketId","description":"Bucket ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","default":"30d"},"in":"query"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/logs":{"get":{"summary":"List Team Logs","operationId":"teamsListLogs","tags":["teams"],"description":"Get the team activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":192,"cookies":false,"type":"","demo":"teams\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","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](\/docs\/permissions).","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/userList"}}}}},"x-appwrite":{"method":"list","weight":201,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":193,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId"]}}}}}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createArgon2User","weight":196,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createBcryptUser","weight":194,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createMD5User","weight":195,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createPHPassUser","weight":198,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptUser","weight":199,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}}}}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":200,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}}}}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createSHAUser","weight":197,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","x-example":"sha1"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/usage":{"get":{"summary":"Get usage stats for the users API","operationId":"usersGetUsage","tags":["users"],"description":"","responses":{"200":{"description":"UsageUsers","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageUsers"}}}}},"x-appwrite":{"method":"getUsage","weight":220,"cookies":false,"type":"","demo":"users\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","default":"30d"},"in":"query"}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":202,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":219,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":213,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"}},"required":["email"]}}}}}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateLabels","weight":208,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","x-example":null,"items":{"type":"string"}}},"required":["labels"]}}}}}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":206,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":205,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":211,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":212,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null}},"required":["password"]}}}}}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":214,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","x-example":"+12065550100"}},"required":["number"]}}}}}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":203,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":216,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":204,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":218,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":217,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":207,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","x-example":false}},"required":["status"]}}}}}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmailVerification","weight":215,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","x-example":false}},"required":["emailVerification"]}}}}}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":210,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","x-example":false}},"required":["phoneVerification"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"$ref":"#\/components\/schemas\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"$ref":"#\/components\/schemas\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"$ref":"#\/components\/schemas\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"$ref":"#\/components\/schemas\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"$ref":"#\/components\/schemas\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"$ref":"#\/components\/schemas\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"$ref":"#\/components\/schemas\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"projectList":{"description":"Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"$ref":"#\/components\/schemas\/project"},"x-example":""}},"required":["total","projects"]},"webhookList":{"description":"Webhooks List","type":"object","properties":{"total":{"type":"integer","description":"Total number of webhooks documents that matched your query.","x-example":5,"format":"int32"},"webhooks":{"type":"array","description":"List of webhooks.","items":{"$ref":"#\/components\/schemas\/webhook"},"x-example":""}},"required":["total","webhooks"]},"keyList":{"description":"API Keys List","type":"object","properties":{"total":{"type":"integer","description":"Total number of keys documents that matched your query.","x-example":5,"format":"int32"},"keys":{"type":"array","description":"List of keys.","items":{"$ref":"#\/components\/schemas\/key"},"x-example":""}},"required":["total","keys"]},"platformList":{"description":"Platforms List","type":"object","properties":{"total":{"type":"integer","description":"Total number of platforms documents that matched your query.","x-example":5,"format":"int32"},"platforms":{"type":"array","description":"List of platforms.","items":{"$ref":"#\/components\/schemas\/platform"},"x-example":""}},"required":["total","platforms"]},"domainList":{"description":"Domains List","type":"object","properties":{"total":{"type":"integer","description":"Total number of domains documents that matched your query.","x-example":5,"format":"int32"},"domains":{"type":"array","description":"List of domains.","items":{"$ref":"#\/components\/schemas\/domain"},"x-example":""}},"required":["total","domains"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"Database enabled.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"account":{"description":"Account","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":15,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","runtime","deployment","vars","events","schedule","timeout"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"enabled"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"pending\", \"ready\", and \"failed\".","x-example":"ready"},"buildStdout":{"type":"string","description":"The build stdout.","x-example":"enabled"},"buildStderr":{"type":"string","description":"The build stderr.","x-example":"enabled"},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildStdout","buildStderr","buildTime"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"project":{"description":"Project","type":"object","properties":{"$id":{"type":"string","description":"Project ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Project creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Project update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Project name.","x-example":"New Project"},"description":{"type":"string","description":"Project description.","x-example":"This is a new project."},"teamId":{"type":"string","description":"Project team ID.","x-example":"1592981250"},"logo":{"type":"string","description":"Project logo file ID.","x-example":"5f5c451b403cb"},"url":{"type":"string","description":"Project website URL.","x-example":"5f5c451b403cb"},"legalName":{"type":"string","description":"Company legal name.","x-example":"Company LTD."},"legalCountry":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format.","x-example":"US"},"legalState":{"type":"string","description":"State name.","x-example":"New York"},"legalCity":{"type":"string","description":"City name.","x-example":"New York City."},"legalAddress":{"type":"string","description":"Company Address.","x-example":"620 Eighth Avenue, New York, NY 10018"},"legalTaxId":{"type":"string","description":"Company Tax ID.","x-example":"131102020"},"authDuration":{"type":"integer","description":"Session duration in seconds.","x-example":60,"format":"int32"},"authLimit":{"type":"integer","description":"Max users allowed. 0 is unlimited.","x-example":100,"format":"int32"},"authSessionsLimit":{"type":"integer","description":"Max sessions allowed per user. 100 maximum.","x-example":10,"format":"int32"},"authPasswordHistory":{"type":"integer","description":"Max allowed passwords in the history list per user. Max passwords limit allowed in history is 20. Use 0 for disabling password history.","x-example":5,"format":"int32"},"authPasswordDictionary":{"type":"boolean","description":"Whether or not to check user's password against most commonly used passwords.","x-example":true},"authPersonalDataCheck":{"type":"boolean","description":"Whether or not to check the user password for similarity with their personal data.","x-example":true},"providers":{"type":"array","description":"List of Providers.","items":{"$ref":"#\/components\/schemas\/provider"},"x-example":[{}]},"platforms":{"type":"array","description":"List of Platforms.","items":{"$ref":"#\/components\/schemas\/platform"},"x-example":{}},"webhooks":{"type":"array","description":"List of Webhooks.","items":{"$ref":"#\/components\/schemas\/webhook"},"x-example":{}},"keys":{"type":"array","description":"List of API Keys.","items":{"$ref":"#\/components\/schemas\/key"},"x-example":{}},"domains":{"type":"array","description":"List of Domains.","items":{"$ref":"#\/components\/schemas\/domain"},"x-example":{}},"smtpEnabled":{"type":"boolean","description":"Status for custom SMTP","x-example":false},"smtpSender":{"type":"string","description":"SMTP sender email","x-example":"john@appwrite.io"},"smtpHost":{"type":"string","description":"SMTP server host name","x-example":"mail.appwrite.io"},"smtpPort":{"type":"integer","description":"SMTP server port","x-example":25,"format":"int32"},"smtpUsername":{"type":"string","description":"SMTP server username","x-example":"emailuser"},"smtpPassword":{"type":"string","description":"SMTP server password","x-example":"securepassword"},"smtpSecure":{"type":"string","description":"SMTP server secure protocol","x-example":"tls"},"authEmailPassword":{"type":"boolean","description":"Email\/Password auth method status","x-example":true},"authUsersAuthMagicURL":{"type":"boolean","description":"Magic URL auth method status","x-example":true},"authAnonymous":{"type":"boolean","description":"Anonymous auth method status","x-example":true},"authInvites":{"type":"boolean","description":"Invites auth method status","x-example":true},"authJWT":{"type":"boolean","description":"JWT auth method status","x-example":true},"authPhone":{"type":"boolean","description":"Phone auth method status","x-example":true},"serviceStatusForAccount":{"type":"boolean","description":"Account service status","x-example":true},"serviceStatusForAvatars":{"type":"boolean","description":"Avatars service status","x-example":true},"serviceStatusForDatabases":{"type":"boolean","description":"Databases service status","x-example":true},"serviceStatusForLocale":{"type":"boolean","description":"Locale service status","x-example":true},"serviceStatusForHealth":{"type":"boolean","description":"Health service status","x-example":true},"serviceStatusForStorage":{"type":"boolean","description":"Storage service status","x-example":true},"serviceStatusForTeams":{"type":"boolean","description":"Teams service status","x-example":true},"serviceStatusForUsers":{"type":"boolean","description":"Users service status","x-example":true},"serviceStatusForFunctions":{"type":"boolean","description":"Functions service status","x-example":true},"serviceStatusForGraphql":{"type":"boolean","description":"GraphQL service status","x-example":true}},"required":["$id","$createdAt","$updatedAt","name","description","teamId","logo","url","legalName","legalCountry","legalState","legalCity","legalAddress","legalTaxId","authDuration","authLimit","authSessionsLimit","authPasswordHistory","authPasswordDictionary","authPersonalDataCheck","providers","platforms","webhooks","keys","domains","smtpEnabled","smtpSender","smtpHost","smtpPort","smtpUsername","smtpPassword","smtpSecure","authEmailPassword","authUsersAuthMagicURL","authAnonymous","authInvites","authJWT","authPhone","serviceStatusForAccount","serviceStatusForAvatars","serviceStatusForDatabases","serviceStatusForLocale","serviceStatusForHealth","serviceStatusForStorage","serviceStatusForTeams","serviceStatusForUsers","serviceStatusForFunctions","serviceStatusForGraphql"]},"webhook":{"description":"Webhook","type":"object","properties":{"$id":{"type":"string","description":"Webhook ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Webhook creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Webhook update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Webhook name.","x-example":"My Webhook"},"url":{"type":"string","description":"Webhook URL endpoint.","x-example":"https:\/\/example.com\/webhook"},"events":{"type":"array","description":"Webhook trigger events.","items":{"type":"string"},"x-example":"database.collections.update"},"security":{"type":"boolean","description":"Indicated if SSL \/ TLS Certificate verification is enabled.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"},"signatureKey":{"type":"string","description":"Signature key which can be used to validated incoming","x-example":"ad3d581ca230e2b7059c545e5a"}},"required":["$id","$createdAt","$updatedAt","name","url","events","security","httpUser","httpPass","signatureKey"]},"key":{"description":"Key","type":"object","properties":{"$id":{"type":"string","description":"Key ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Key creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Key update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Key name.","x-example":"My API Key"},"expire":{"type":"string","description":"Key expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"scopes":{"type":"array","description":"Allowed permission scopes.","items":{"type":"string"},"x-example":"users.read"},"secret":{"type":"string","description":"Secret key.","x-example":"919c2d18fb5d4...a2ae413da83346ad2"},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"},"sdks":{"type":"array","description":"List of SDK user agents that used this key.","items":{"type":"string"},"x-example":"appwrite:flutter"}},"required":["$id","$createdAt","$updatedAt","name","expire","scopes","secret","accessedAt","sdks"]},"domain":{"description":"Domain","type":"object","properties":{"$id":{"type":"string","description":"Domain ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Domain creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Domain update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"domain":{"type":"string","description":"Domain name.","x-example":"appwrite.company.com"},"registerable":{"type":"string","description":"Registerable domain name.","x-example":"company.com"},"tld":{"type":"string","description":"TLD name.","x-example":"com"},"verification":{"type":"boolean","description":"Verification process status.","x-example":true},"certificateId":{"type":"string","description":"Certificate ID.","x-example":"6ejea5c13377e"}},"required":["$id","$createdAt","$updatedAt","domain","registerable","tld","verification","certificateId"]},"provider":{"description":"Provider","type":"object","properties":{"key":{"type":"string","description":"Provider.","x-example":"github"},"name":{"type":"string","description":"Provider name.","x-example":"GitHub"},"appId":{"type":"string","description":"OAuth 2.0 application ID.","x-example":"259125845563242502"},"secret":{"type":"string","description":"OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.","x-example":"Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ"},"enabled":{"type":"boolean","description":"Provider is active and can be used to create session.","x-example":""}},"required":["key","name","appId","secret","enabled"]},"platform":{"description":"Platform","type":"object","properties":{"$id":{"type":"string","description":"Platform ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Platform creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Platform update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Platform name.","x-example":"My Web App"},"type":{"type":"string","description":"Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, and unity.","x-example":"web"},"key":{"type":"string","description":"Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.","x-example":"com.company.appname"},"store":{"type":"string","description":"App store or Google Play store ID.","x-example":""},"hostname":{"type":"string","description":"Web app hostname. Empty string for other platforms.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"}},"required":["$id","$createdAt","$updatedAt","name","type","key","store","hostname","httpUser","httpPass"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"}},"required":["$id","$createdAt","$updatedAt","key","value","functionId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"metric":{"description":"Metric","type":"object","properties":{"value":{"type":"integer","description":"The value of this metric at the timestamp.","x-example":1,"format":"int32"},"date":{"type":"string","description":"The date at which this metric was aggregated in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["value","date"]},"usageDatabases":{"description":"UsageDatabases","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"databasesTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsTotal":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","databasesTotal","collectionsTotal","documentsTotal"]},"usageDatabase":{"description":"UsageDatabase","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"collectionsTotal":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","collectionsTotal","documentsTotal"]},"usageCollection":{"description":"UsageCollection","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","documentsTotal"]},"usageUsers":{"description":"UsageUsers","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"usersTotal":{"type":"array","description":"Aggregated stats for total number of users.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"sessionsTotal":{"type":"array","description":"Aggregated stats for sessions created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","usersTotal","sessionsTotal"]},"usageStorage":{"description":"StorageUsage","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"bucketsTotal":{"type":"array","description":"Aggregated stats for total number of buckets.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesTotal":{"type":"array","description":"Aggregated stats for total number of files.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","bucketsTotal","filesTotal","filesStorage"]},"usageBuckets":{"description":"UsageBuckets","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"filesTotal":{"type":"array","description":"Aggregated stats for total number of files in this bucket.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for total storage of files in this bucket.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","filesTotal","filesStorage"]},"usageFunctions":{"description":"UsageFunctions","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"functionsTotal":{"type":"array","description":"Aggregated stats for number of functions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"deploymentsTotal":{"type":"array","description":"Aggregated stats for number of function deployments.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"deploymentsStorage":{"type":"array","description":"Aggregated stats for function deployments storage.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsTotal":{"type":"array","description":"Aggregated stats for number of function builds.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsStorage":{"type":"array","description":"Aggregated stats for builds storage.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsTime":{"type":"array","description":"Aggregated stats for function build compute.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsTotal":{"type":"array","description":"Aggregated stats for number of function executions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsTime":{"type":"array","description":"Aggregated stats for function execution compute.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","functionsTotal","deploymentsTotal","deploymentsStorage","buildsTotal","buildsStorage","buildsTime","executionsTotal","executionsTime"]},"usageProject":{"description":"UsageProject","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"requestsTotal":{"type":"array","description":"Aggregated stats for number of requests.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"network":{"type":"array","description":"Aggregated stats for consumed bandwidth.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsTotal":{"type":"array","description":"Aggregated stats for function executions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesTotal":{"type":"array","description":"Aggregated stats for number of databases.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersTotal":{"type":"array","description":"Aggregated stats for number of users.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsTotal":{"type":"array","description":"Aggregated stats for number of buckets.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","requestsTotal","network","executionsTotal","documentsTotal","databasesTotal","usersTotal","filesStorage","bucketsTotal"]},"smsTemplate":{"description":"SmsTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."}},"required":["type","locale","message"]},"emailTemplate":{"description":"EmailTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."},"senderName":{"type":"string","description":"Name of the sender","x-example":"My User"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"mail@appwrite.io"},"replyTo":{"type":"string","description":"Reply to email address","x-example":"emails@appwrite.io"},"subject":{"type":"string","description":"Email subject","x-example":"Please verify your email address"}},"required":["type","locale","message","senderName","senderEmail","replyTo","subject"]},"consoleVariables":{"description":"Console Variables","type":"object","properties":{"_APP_DOMAIN_TARGET":{"type":"string","description":"CNAME target for your Appwrite custom domains.","x-example":"appwrite.io"},"_APP_STORAGE_LIMIT":{"type":"integer","description":"Maximum file size allowed for file upload in bytes.","x-example":"30000000","format":"int32"},"_APP_FUNCTIONS_SIZE_LIMIT":{"type":"integer","description":"Maximum file size allowed for deployment in bytes.","x-example":"30000000","format":"int32"},"_APP_USAGE_STATS":{"type":"string","description":"Defines if usage stats are enabled. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'.","x-example":"enabled"}},"required":["_APP_DOMAIN_TARGET","_APP_STORAGE_LIMIT","_APP_FUNCTIONS_SIZE_LIMIT","_APP_USAGE_STATS"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}},"Mode":{"type":"apiKey","name":"X-Appwrite-Mode","description":"","in":"header","x-appwrite":{"demo":""}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"openapi":"3.0.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/jwt"}}}}},"x-appwrite":{"method":"createJWT","cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createAnonymousSession","cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createEmailSession","cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createMagicURLSession","cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}}}},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateMagicURLSession","cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"File"}},"x-appwrite":{"method":"createOAuth2Session","cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"schema":{"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[]},"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneSession","cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"}},"required":["userId","phone"]}}}}},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updatePhoneSession","cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/console\/assistant":{"post":{"summary":"Ask Query","operationId":"assistantChat","tags":["assistant"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"chat","cookies":false,"type":"","demo":"assistant\/chat.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/assistant\/chat.md","rate-limit":15,"rate-time":3600,"rate-key":"userId:{userId}","scope":"assistant.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","description":"Prompt. A string containing questions asked to the AI assistant.","x-example":"[PROMPT]"}},"required":["prompt"]}}}}}},"\/console\/variables":{"get":{"summary":"Get Variables","operationId":"consoleVariables","tags":["console"],"description":"Get all Environment Variables that are relevant for the console.","responses":{"200":{"description":"Console Variables","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/consoleVariables"}}}}},"x-appwrite":{"method":"variables","cookies":false,"type":"","demo":"console\/variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/console\/variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/databaseList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","x-example":false}},"required":["databaseId","name"]}}}}}},"\/databases\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabases","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageDatabases"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"databases\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"`Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Database","operationId":"databasesDelete","tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collectionList"}}}}},"x-appwrite":{"method":"listCollections","cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"createCollection","cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","x-example":false}},"required":["collectionId","name"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"getCollection","cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"updateCollection","cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeList"}}}}},"x-appwrite":{"method":"listAttributes","cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"createBooleanAttribute","cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"updateBooleanAttribute","cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"createDatetimeAttribute","cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"updateDatetimeAttribute","cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"createEmailAttribute","cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"updateEmailAttribute","cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"createEnumAttribute","cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","elements","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"updateEnumAttribute","cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"createFloatAttribute","cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"updateFloatAttribute","cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"createIntegerAttribute","cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"updateIntegerAttribute","cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"createIpAttribute","cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"updateIpAttribute","cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"createRelationshipAttribute","cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","x-example":false},"key":{"type":"string","description":"Attribute Key.","x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","x-example":null},"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"createStringAttribute","cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","x-example":1},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false},"encrypt":{"type":"boolean","description":"Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.","x-example":false}},"required":["key","size","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"updateStringAttribute","cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"createUrlAttribute","cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"updateUrlAttribute","cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","content":{"application\/json":{"schema":{"oneOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]}}}}},"x-appwrite":{"method":"getAttribute","cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"updateRelationshipAttribute","cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/logs":{"get":{"summary":"List Document Logs","operationId":"databasesListDocumentLogs","tags":["databases"],"description":"Get the document activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listDocumentLogs","cookies":false,"type":"","demo":"databases\/list-document-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/indexList"}}}}},"x-appwrite":{"method":"listIndexes","cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","tags":["databases"],"description":"","responses":{"202":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"createIndex","cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":null},"type":{"type":"string","description":"Index type.","x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","tags":["databases"],"description":"","responses":{"200":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"getIndex","cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/logs":{"get":{"summary":"List Collection Logs","operationId":"databasesListCollectionLogs","tags":["databases"],"description":"Get the collection activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listCollectionLogs","cookies":false,"type":"","demo":"databases\/list-collection-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/usage":{"get":{"summary":"Get usage stats for a collection","operationId":"databasesGetCollectionUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageCollection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageCollection"}}}}},"x-appwrite":{"method":"getCollectionUsage","cookies":false,"type":"","demo":"databases\/get-collection-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/logs":{"get":{"summary":"List Database Logs","operationId":"databasesListLogs","tags":["databases"],"description":"Get the database activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"databases\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetDatabaseUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabase","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageDatabase"}}}}},"x-appwrite":{"method":"getDatabaseUsage","cookies":false,"type":"","demo":"databases\/get-database-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"range","description":"`Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/functionList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Control System) deployment.","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function.","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function.","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","x-example":"[PROVIDER_ROOT_DIRECTORY]"},"templateRepository":{"type":"string","description":"Repository name of the template.","x-example":"[TEMPLATE_REPOSITORY]"},"templateOwner":{"type":"string","description":"The name of the owner of the template.","x-example":"[TEMPLATE_OWNER]"},"templateRootDirectory":{"type":"string","description":"Path to function code in the template repo.","x-example":"[TEMPLATE_ROOT_DIRECTORY]"},"templateBranch":{"type":"string","description":"Production branch for the repo linked to the function template.","x-example":"[TEMPLATE_BRANCH]"}},"required":["functionId","name","runtime"]}}}}}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/runtimeList"}}}}},"x-appwrite":{"method":"listRuntimes","cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/usage":{"get":{"summary":"Get Functions Usage","operationId":"functionsGetUsage","tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageFunctions"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"functions\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Controle System) deployment.","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","x-example":"[PROVIDER_ROOT_DIRECTORY]"}},"required":["name","runtime"]}}}}},"delete":{"summary":"Delete Function","operationId":"functionsDelete","tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deploymentList"}}}}},"x-appwrite":{"method":"listDeployments","cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: size, buildId, activate, entrypoint, commands","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","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](\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.","responses":{"202":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"createDeployment","cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"entrypoint":{"type":"string","description":"Entrypoint File.","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"code":{"type":"string","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","x-example":null},"activate":{"type":"boolean","description":"Automatically activate the deployment when it is finished building.","x-example":false}},"required":["code","activate"]}}}}}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"getDeployment","cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"updateDeployment","cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","tags":["functions"],"description":"Create a new build for an Appwrite Function deployment. This endpoint can be used to retry a failed build.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"schema":{"type":"string","x-example":"[BUILD_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/download":{"get":{"summary":"Download Deployment","operationId":"functionsDownloadDeployment","tags":["functions"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"downloadDeployment","cookies":false,"type":"location","demo":"functions\/download-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/download-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","x-example":"[BODY]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false},"path":{"type":"string","description":"HTTP path of execution. Path can include query params. Default value is \/","x-example":"[PATH]"},"method":{"type":"string","description":"HTTP method of execution. Default value is GET.","x-example":"GET","enum":["GET","POST","PUT","PATCH","DELETE","OPTIONS"],"x-enum-name":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","x-example":"{}"}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/usage":{"get":{"summary":"Get Function Usage","operationId":"functionsGetFunctionUsage","tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageFunctions"}}}}},"x-appwrite":{"method":"getFunctionUsage","cookies":false,"type":"","demo":"functions\/get-function-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","tags":["functions"],"description":"Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthAntivirus"}}}}},"x-appwrite":{"method":"getAntivirus","cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getCache","cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getDB","cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getPubSub","cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getQueue","cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueCertificates","cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueFunctions","cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueLogs","cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueWebhooks","cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getStorageLocal","cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthTime"}}}}},"x-appwrite":{"method":"getTime","cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/migrations":{"get":{"summary":"List Migrations","operationId":"migrationsList","tags":["migrations"],"description":"","responses":{"200":{"description":"Migrations List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"migrations\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/list-migrations.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: status, stage, source, resources, statusCounters, resourceData, errors","required":false,"schema":{"type":"string","default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]}},"\/migrations\/appwrite":{"post":{"summary":"Migrate Appwrite Data","operationId":"migrationsCreateAppwriteMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createAppwriteMigration","cookies":false,"type":"","demo":"migrations\/create-appwrite-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-appwrite.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"endpoint":{"type":"string","description":"Source's Appwrite Endpoint","x-example":"https:\/\/example.com"},"projectId":{"type":"string","description":"Source's Project ID","x-example":"[PROJECT_ID]"},"apiKey":{"type":"string","description":"Source's API Key","x-example":"[API_KEY]"}},"required":["resources","endpoint","projectId","apiKey"]}}}}}},"\/migrations\/appwrite\/report":{"get":{"summary":"Generate a report on Appwrite Data","operationId":"migrationsGetAppwriteReport","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getAppwriteReport","cookies":false,"type":"","demo":"migrations\/get-appwrite-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-appwrite-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"endpoint","description":"Source's Appwrite Endpoint","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"projectID","description":"Source's Project ID","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"query"},{"name":"key","description":"Source's API Key","required":true,"schema":{"type":"string","x-example":"[KEY]"},"in":"query"}]}},"\/migrations\/firebase":{"post":{"summary":"Migrate Firebase Data (Service Account)","operationId":"migrationsCreateFirebaseMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createFirebaseMigration","cookies":false,"type":"","demo":"migrations\/create-firebase-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"serviceAccount":{"type":"string","description":"JSON of the Firebase service account credentials","x-example":"[SERVICE_ACCOUNT]"}},"required":["resources","serviceAccount"]}}}}}},"\/migrations\/firebase\/deauthorize":{"get":{"summary":"Revoke Appwrite's authorization to access Firebase Projects","operationId":"migrationsDeleteFirebaseAuth","tags":["migrations"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"deleteFirebaseAuth","cookies":false,"type":"","demo":"migrations\/delete-firebase-auth.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/migrations\/firebase\/oauth":{"post":{"summary":"Migrate Firebase Data (OAuth)","operationId":"migrationsCreateFirebaseOAuthMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createFirebaseOAuthMigration","cookies":false,"type":"","demo":"migrations\/create-firebase-o-auth-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"projectId":{"type":"string","description":"Project ID of the Firebase Project","x-example":"[PROJECT_ID]"}},"required":["resources","projectId"]}}}}}},"\/migrations\/firebase\/projects":{"get":{"summary":"List Firebase Projects","operationId":"migrationsListFirebaseProjects","tags":["migrations"],"description":"","responses":{"200":{"description":"Migrations Firebase Projects List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/firebaseProjectList"}}}}},"x-appwrite":{"method":"listFirebaseProjects","cookies":false,"type":"","demo":"migrations\/list-firebase-projects.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/migrations\/firebase\/report":{"get":{"summary":"Generate a report on Firebase Data","operationId":"migrationsGetFirebaseReport","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getFirebaseReport","cookies":false,"type":"","demo":"migrations\/get-firebase-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"serviceAccount","description":"JSON of the Firebase service account credentials","required":true,"schema":{"type":"string","x-example":"[SERVICE_ACCOUNT]"},"in":"query"}]}},"\/migrations\/firebase\/report\/oauth":{"get":{"summary":"Generate a report on Firebase Data using OAuth","operationId":"migrationsGetFirebaseReportOAuth","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getFirebaseReportOAuth","cookies":false,"type":"","demo":"migrations\/get-firebase-report-o-auth.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"projectId","description":"Project ID","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"query"}]}},"\/migrations\/nhost":{"post":{"summary":"Migrate NHost Data","operationId":"migrationsCreateNHostMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createNHostMigration","cookies":false,"type":"","demo":"migrations\/create-n-host-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-nhost.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"subdomain":{"type":"string","description":"Source's Subdomain","x-example":"[SUBDOMAIN]"},"region":{"type":"string","description":"Source's Region","x-example":"[REGION]"},"adminSecret":{"type":"string","description":"Source's Admin Secret","x-example":"[ADMIN_SECRET]"},"database":{"type":"string","description":"Source's Database Name","x-example":"[DATABASE]"},"username":{"type":"string","description":"Source's Database Username","x-example":"[USERNAME]"},"password":{"type":"string","description":"Source's Database Password","x-example":"[PASSWORD]"},"port":{"type":"integer","description":"Source's Database Port","x-example":null}},"required":["resources","subdomain","region","adminSecret","database","username","password"]}}}}}},"\/migrations\/nhost\/report":{"get":{"summary":"Generate a report on NHost Data","operationId":"migrationsGetNHostReport","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getNHostReport","cookies":false,"type":"","demo":"migrations\/get-n-host-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-nhost-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate.","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"subdomain","description":"Source's Subdomain.","required":true,"schema":{"type":"string","x-example":"[SUBDOMAIN]"},"in":"query"},{"name":"region","description":"Source's Region.","required":true,"schema":{"type":"string","x-example":"[REGION]"},"in":"query"},{"name":"adminSecret","description":"Source's Admin Secret.","required":true,"schema":{"type":"string","x-example":"[ADMIN_SECRET]"},"in":"query"},{"name":"database","description":"Source's Database Name.","required":true,"schema":{"type":"string","x-example":"[DATABASE]"},"in":"query"},{"name":"username","description":"Source's Database Username.","required":true,"schema":{"type":"string","x-example":"[USERNAME]"},"in":"query"},{"name":"password","description":"Source's Database Password.","required":true,"schema":{"type":"string","x-example":"[PASSWORD]"},"in":"query"},{"name":"port","description":"Source's Database Port.","required":false,"schema":{"type":"integer","format":"int32","default":5432},"in":"query"}]}},"\/migrations\/supabase":{"post":{"summary":"Migrate Supabase Data","operationId":"migrationsCreateSupabaseMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createSupabaseMigration","cookies":false,"type":"","demo":"migrations\/create-supabase-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-supabase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"endpoint":{"type":"string","description":"Source's Supabase Endpoint","x-example":"https:\/\/example.com"},"apiKey":{"type":"string","description":"Source's API Key","x-example":"[API_KEY]"},"databaseHost":{"type":"string","description":"Source's Database Host","x-example":"[DATABASE_HOST]"},"username":{"type":"string","description":"Source's Database Username","x-example":"[USERNAME]"},"password":{"type":"string","description":"Source's Database Password","x-example":"[PASSWORD]"},"port":{"type":"integer","description":"Source's Database Port","x-example":null}},"required":["resources","endpoint","apiKey","databaseHost","username","password"]}}}}}},"\/migrations\/supabase\/report":{"get":{"summary":"Generate a report on Supabase Data","operationId":"migrationsGetSupabaseReport","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getSupabaseReport","cookies":false,"type":"","demo":"migrations\/get-supabase-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-supabase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"endpoint","description":"Source's Supabase Endpoint.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"apiKey","description":"Source's API Key.","required":true,"schema":{"type":"string","x-example":"[API_KEY]"},"in":"query"},{"name":"databaseHost","description":"Source's Database Host.","required":true,"schema":{"type":"string","x-example":"[DATABASE_HOST]"},"in":"query"},{"name":"username","description":"Source's Database Username.","required":true,"schema":{"type":"string","x-example":"[USERNAME]"},"in":"query"},{"name":"password","description":"Source's Database Password.","required":true,"schema":{"type":"string","x-example":"[PASSWORD]"},"in":"query"},{"name":"port","description":"Source's Database Port.","required":false,"schema":{"type":"integer","format":"int32","default":5432},"in":"query"}]}},"\/migrations\/{migrationId}":{"get":{"summary":"Get Migration","operationId":"migrationsGet","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"migrations\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/get-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration unique ID.","required":true,"schema":{"type":"string","x-example":"[MIGRATION_ID]"},"in":"path"}]},"patch":{"summary":"Retry Migration","operationId":"migrationsRetry","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"retry","cookies":false,"type":"","demo":"migrations\/retry.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/retry-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration unique ID.","required":true,"schema":{"type":"string","x-example":"[MIGRATION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Migration","operationId":"migrationsDelete","tags":["migrations"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"migrations\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration ID.","required":true,"schema":{"type":"string","x-example":"[MIGRATION_ID]"},"in":"path"}]}},"\/project\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectGetUsage","tags":["project"],"description":"","responses":{"200":{"description":"UsageProject","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageProject"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"project\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/project\/variables":{"get":{"summary":"List Variables","operationId":"projectListVariables","tags":["project"],"description":"Get a list of all project variables. These variables will be accessible in all Appwrite Functions at runtime.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","cookies":false,"type":"","demo":"project\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]},"post":{"summary":"Create Variable","operationId":"projectCreateVariable","tags":["project"],"description":"Create a new project variable. This variable will be accessible in all Appwrite Functions at runtime.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","cookies":false,"type":"","demo":"project\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/project\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"projectGetVariable","tags":["project"],"description":"Get a project variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","cookies":false,"type":"","demo":"project\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"projectUpdateVariable","tags":["project"],"description":"Update project variable by its unique ID. This variable will be accessible in all Appwrite Functions at runtime.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","cookies":false,"type":"","demo":"project\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"projectDeleteVariable","tags":["project"],"description":"Delete a project variable by its unique ID. ","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","cookies":false,"type":"","demo":"project\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/projects":{"get":{"summary":"List Projects","operationId":"projectsList","tags":["projects"],"description":"","responses":{"200":{"description":"Projects List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/projectList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"projects\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Project","operationId":"projectsCreate","tags":["projects"],"description":"","responses":{"201":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"projects\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.","x-example":null},"name":{"type":"string","description":"Project name. Max length: 128 chars.","x-example":"[NAME]"},"teamId":{"type":"string","description":"Team unique ID.","x-example":"[TEAM_ID]"},"region":{"type":"string","description":"Project Region.","x-example":"default","enum":["default"],"x-enum-name":null,"x-enum-keys":[]},"description":{"type":"string","description":"Project description. Max length: 256 chars.","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal Name. Max length: 256 chars.","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal Country. Max length: 256 chars.","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal State. Max length: 256 chars.","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal City. Max length: 256 chars.","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal Address. Max length: 256 chars.","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal Tax ID. Max length: 256 chars.","x-example":"[LEGAL_TAX_ID]"}},"required":["projectId","name","teamId"]}}}}}},"\/projects\/{projectId}":{"get":{"summary":"Get Project","operationId":"projectsGet","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"projects\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"patch":{"summary":"Update Project","operationId":"projectsUpdate","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"projects\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name. Max length: 128 chars.","x-example":"[NAME]"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal name. Max length: 256 chars.","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal country. Max length: 256 chars.","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal state. Max length: 256 chars.","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal city. Max length: 256 chars.","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal address. Max length: 256 chars.","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal tax ID. Max length: 256 chars.","x-example":"[LEGAL_TAX_ID]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Project","operationId":"projectsDelete","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"projects\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/auth\/duration":{"patch":{"summary":"Update Project Authentication Duration","operationId":"projectsUpdateAuthDuration","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthDuration","cookies":false,"type":"","demo":"projects\/update-auth-duration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"duration":{"type":"integer","description":"Project session length in seconds. Max length: 31536000 seconds.","x-example":0}},"required":["duration"]}}}}}},"\/projects\/{projectId}\/auth\/limit":{"patch":{"summary":"Update Project users limit","operationId":"projectsUpdateAuthLimit","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthLimit","cookies":false,"type":"","demo":"projects\/update-auth-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Use 0 for unlimited.","x-example":0}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/max-sessions":{"patch":{"summary":"Update Project user sessions limit","operationId":"projectsUpdateAuthSessionsLimit","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthSessionsLimit","cookies":false,"type":"","demo":"projects\/update-auth-sessions-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10","x-example":1}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/password-dictionary":{"patch":{"summary":"Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password","operationId":"projectsUpdateAuthPasswordDictionary","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthPasswordDictionary","cookies":false,"type":"","demo":"projects\/update-auth-password-dictionary.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to enable checking user's password against most commonly used passwords. Default is false.","x-example":false}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/auth\/password-history":{"patch":{"summary":"Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.","operationId":"projectsUpdateAuthPasswordHistory","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthPasswordHistory","cookies":false,"type":"","demo":"projects\/update-auth-password-history.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0","x-example":0}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/personal-data":{"patch":{"summary":"Enable or disable checking user passwords for similarity with their personal data.","operationId":"projectsUpdatePersonalDataCheck","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updatePersonalDataCheck","cookies":false,"type":"","demo":"projects\/update-personal-data-check.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to check a password for similarity with personal data. Default is false.","x-example":false}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/auth\/{method}":{"patch":{"summary":"Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.","operationId":"projectsUpdateAuthStatus","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthStatus","cookies":false,"type":"","demo":"projects\/update-auth-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"method","description":"Auth Method. Possible values: email-password,magic-url,anonymous,invites,jwt,phone","required":true,"schema":{"type":"string","x-example":"email-password","enum":["email-password","magic-url","anonymous","invites","jwt","phone"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Set the status of this auth method.","x-example":false}},"required":["status"]}}}}}},"\/projects\/{projectId}\/keys":{"get":{"summary":"List Keys","operationId":"projectsListKeys","tags":["projects"],"description":"","responses":{"200":{"description":"API Keys List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/keyList"}}}}},"x-appwrite":{"method":"listKeys","cookies":false,"type":"","demo":"projects\/list-keys.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Key","operationId":"projectsCreateKey","tags":["projects"],"description":"","responses":{"201":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"createKey","cookies":false,"type":"","demo":"projects\/create-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 scopes are allowed.","x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","x-example":null}},"required":["name","scopes"]}}}}}},"\/projects\/{projectId}\/keys\/{keyId}":{"get":{"summary":"Get Key","operationId":"projectsGetKey","tags":["projects"],"description":"","responses":{"200":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"getKey","cookies":false,"type":"","demo":"projects\/get-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}]},"put":{"summary":"Update Key","operationId":"projectsUpdateKey","tags":["projects"],"description":"","responses":{"200":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"updateKey","cookies":false,"type":"","demo":"projects\/update-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","x-example":null}},"required":["name","scopes"]}}}}},"delete":{"summary":"Delete Key","operationId":"projectsDeleteKey","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteKey","cookies":false,"type":"","demo":"projects\/delete-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/oauth2":{"patch":{"summary":"Update Project OAuth2","operationId":"projectsUpdateOAuth2","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateOAuth2","cookies":false,"type":"","demo":"projects\/update-o-auth2.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","description":"Provider Name","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":null,"x-enum-keys":[]},"appId":{"type":"string","description":"Provider app ID. Max length: 256 chars.","x-example":"[APP_ID]"},"secret":{"type":"string","description":"Provider secret key. Max length: 512 chars.","x-example":"[SECRET]"},"enabled":{"type":"boolean","description":"Provider status. Set to 'false' to disable new session creation.","x-example":false}},"required":["provider"]}}}}}},"\/projects\/{projectId}\/platforms":{"get":{"summary":"List Platforms","operationId":"projectsListPlatforms","tags":["projects"],"description":"","responses":{"200":{"description":"Platforms List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platformList"}}}}},"x-appwrite":{"method":"listPlatforms","cookies":false,"type":"","demo":"projects\/list-platforms.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Platform","operationId":"projectsCreatePlatform","tags":["projects"],"description":"","responses":{"201":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"createPlatform","cookies":false,"type":"","demo":"projects\/create-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"Platform type.","x-example":"web","enum":["web","flutter-web","flutter-ios","flutter-android","flutter-linux","flutter-macos","flutter-windows","apple-ios","apple-macos","apple-watchos","apple-tvos","android","unity"],"x-enum-name":"PlatformType","x-enum-keys":[]},"name":{"type":"string","description":"Platform name. Max length: 128 chars.","x-example":"[NAME]"},"key":{"type":"string","description":"Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client hostname. Max length: 256 chars.","x-example":null}},"required":["type","name"]}}}}}},"\/projects\/{projectId}\/platforms\/{platformId}":{"get":{"summary":"Get Platform","operationId":"projectsGetPlatform","tags":["projects"],"description":"","responses":{"200":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"getPlatform","cookies":false,"type":"","demo":"projects\/get-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}]},"put":{"summary":"Update Platform","operationId":"projectsUpdatePlatform","tags":["projects"],"description":"","responses":{"200":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"updatePlatform","cookies":false,"type":"","demo":"projects\/update-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Platform name. Max length: 128 chars.","x-example":"[NAME]"},"key":{"type":"string","description":"Package name for android or bundle ID for iOS. Max length: 256 chars.","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client URL. Max length: 256 chars.","x-example":null}},"required":["name"]}}}}},"delete":{"summary":"Delete Platform","operationId":"projectsDeletePlatform","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deletePlatform","cookies":false,"type":"","demo":"projects\/delete-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/service":{"patch":{"summary":"Update service status","operationId":"projectsUpdateServiceStatus","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateServiceStatus","cookies":false,"type":"","demo":"projects\/update-service-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"service":{"type":"string","description":"Service name.","x-example":"account","enum":["account","avatars","databases","locale","health","storage","teams","users","vcs","functions","proxy","graphql","migrations"],"x-enum-name":null,"x-enum-keys":[]},"status":{"type":"boolean","description":"Service status.","x-example":false}},"required":["service","status"]}}}}}},"\/projects\/{projectId}\/service\/all":{"patch":{"summary":"Update all service status","operationId":"projectsUpdateServiceStatusAll","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateServiceStatusAll","cookies":false,"type":"","demo":"projects\/update-service-status-all.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Service status.","x-example":false}},"required":["status"]}}}}}},"\/projects\/{projectId}\/smtp":{"patch":{"summary":"Update SMTP configuration","operationId":"projectsUpdateSmtpConfiguration","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateSmtpConfiguration","cookies":false,"type":"","demo":"projects\/update-smtp-configuration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable custom SMTP service","x-example":false},"senderName":{"type":"string","description":"Name of the email sender","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"email@example.com"},"replyTo":{"type":"string","description":"Reply to email","x-example":"email@example.com"},"host":{"type":"string","description":"SMTP server host name","x-example":null},"port":{"type":"integer","description":"SMTP server port","x-example":null},"username":{"type":"string","description":"SMTP server username","x-example":"[USERNAME]"},"password":{"type":"string","description":"SMTP server password","x-example":"[PASSWORD]"},"secure":{"type":"string","description":"Does SMTP server use secure connection","x-example":"tls","enum":["tls"],"x-enum-name":null,"x-enum-keys":[]}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/team":{"patch":{"summary":"Update Project Team","operationId":"projectsUpdateTeam","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateTeam","cookies":false,"type":"","demo":"projects\/update-team.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID of the team to transfer project to.","x-example":"[TEAM_ID]"}},"required":["teamId"]}}}}}},"\/projects\/{projectId}\/templates\/email\/{type}\/{locale}":{"get":{"summary":"Get custom email template","operationId":"projectsGetEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/emailTemplate"}}}}},"x-appwrite":{"method":"getEmailTemplate","cookies":false,"type":"","demo":"projects\/get-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]},"patch":{"summary":"Update custom email templates","operationId":"projectsUpdateEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateEmailTemplate","cookies":false,"type":"","demo":"projects\/update-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"subject":{"type":"string","description":"Email Subject","x-example":"[SUBJECT]"},"message":{"type":"string","description":"Template message","x-example":"[MESSAGE]"},"senderName":{"type":"string","description":"Name of the email sender","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"email@example.com"},"replyTo":{"type":"string","description":"Reply to email","x-example":"email@example.com"}},"required":["subject","message"]}}}}},"delete":{"summary":"Reset custom email template","operationId":"projectsDeleteEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/emailTemplate"}}}}},"x-appwrite":{"method":"deleteEmailTemplate","cookies":false,"type":"","demo":"projects\/delete-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]}},"\/projects\/{projectId}\/templates\/sms\/{type}\/{locale}":{"get":{"summary":"Get custom SMS template","operationId":"projectsGetSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"getSmsTemplate","cookies":false,"type":"","demo":"projects\/get-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]},"patch":{"summary":"Update custom SMS template","operationId":"projectsUpdateSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"updateSmsTemplate","cookies":false,"type":"","demo":"projects\/update-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Template message","x-example":"[MESSAGE]"}},"required":["message"]}}}}},"delete":{"summary":"Reset custom SMS template","operationId":"projectsDeleteSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"deleteSmsTemplate","cookies":false,"type":"","demo":"projects\/delete-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]}},"\/projects\/{projectId}\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectsGetUsage","tags":["projects"],"description":"","responses":{"200":{"description":"UsageProject","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageProject"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"projects\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/projects\/{projectId}\/webhooks":{"get":{"summary":"List Webhooks","operationId":"projectsListWebhooks","tags":["projects"],"description":"","responses":{"200":{"description":"Webhooks List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhookList"}}}}},"x-appwrite":{"method":"listWebhooks","cookies":false,"type":"","demo":"projects\/list-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Webhook","operationId":"projectsCreateWebhook","tags":["projects"],"description":"","responses":{"201":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"createWebhook","cookies":false,"type":"","demo":"projects\/create-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}}}}},"\/projects\/{projectId}\/webhooks\/{webhookId}":{"get":{"summary":"Get Webhook","operationId":"projectsGetWebhook","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"getWebhook","cookies":false,"type":"","demo":"projects\/get-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]},"put":{"summary":"Update Webhook","operationId":"projectsUpdateWebhook","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"updateWebhook","cookies":false,"type":"","demo":"projects\/update-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}}}},"delete":{"summary":"Delete Webhook","operationId":"projectsDeleteWebhook","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteWebhook","cookies":false,"type":"","demo":"projects\/delete-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}\/signature":{"patch":{"summary":"Update Webhook Signature Key","operationId":"projectsUpdateWebhookSignature","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"updateWebhookSignature","cookies":false,"type":"","demo":"projects\/update-webhook-signature.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]}},"\/proxy\/rules":{"get":{"summary":"List Rules","operationId":"proxyListRules","tags":["proxy"],"description":"Get a list of all the proxy rules. You can use the query params to filter your results.","responses":{"200":{"description":"Rule List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/proxyRuleList"}}}}},"x-appwrite":{"method":"listRules","cookies":false,"type":"","demo":"proxy\/list-rules.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/list-rules.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: domain, resourceType, resourceId, url","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Rule","operationId":"proxyCreateRule","tags":["proxy"],"description":"Create a new proxy rule.","responses":{"201":{"description":"Rule","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/proxyRule"}}}}},"x-appwrite":{"method":"createRule","cookies":false,"type":"","demo":"proxy\/create-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/create-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain name.","x-example":null},"resourceType":{"type":"string","description":"Action definition for the rule. Possible values are \"api\", \"function\"","x-example":"api","enum":["api","function"],"x-enum-name":null,"x-enum-keys":[]},"resourceId":{"type":"string","description":"ID of resource for the action type. If resourceType is \"api\", leave empty. If resourceType is \"function\", provide ID of the function.","x-example":"[RESOURCE_ID]"}},"required":["domain","resourceType"]}}}}}},"\/proxy\/rules\/{ruleId}":{"get":{"summary":"Get Rule","operationId":"proxyGetRule","tags":["proxy"],"description":"Get a proxy rule by its unique ID.","responses":{"200":{"description":"Rule","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/proxyRule"}}}}},"x-appwrite":{"method":"getRule","cookies":false,"type":"","demo":"proxy\/get-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/get-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"schema":{"type":"string","x-example":"[RULE_ID]"},"in":"path"}]},"delete":{"summary":"Delete Rule","operationId":"proxyDeleteRule","tags":["proxy"],"description":"Delete a proxy rule by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteRule","cookies":false,"type":"","demo":"proxy\/delete-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/delete-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"schema":{"type":"string","x-example":"[RULE_ID]"},"in":"path"}]}},"\/proxy\/rules\/{ruleId}\/verification":{"patch":{"summary":"Update Rule Verification Status","operationId":"proxyUpdateRuleVerification","tags":["proxy"],"description":"","responses":{"200":{"description":"Rule","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/proxyRule"}}}}},"x-appwrite":{"method":"updateRuleVerification","cookies":false,"type":"","demo":"proxy\/update-rule-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"schema":{"type":"string","x-example":"[RULE_ID]"},"in":"path"}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucketList"}}}}},"x-appwrite":{"method":"listBuckets","cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"createBucket","cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["bucketId","name"]}}}}}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"getBucket","cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"updateBucket","cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/usage":{"get":{"summary":"Get usage stats for storage","operationId":"storageGetUsage","tags":["storage"],"description":"","responses":{"200":{"description":"StorageUsage","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageStorage"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"storage\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/storage\/{bucketId}\/usage":{"get":{"summary":"Get usage stats for a storage bucket","operationId":"storageGetBucketUsage","tags":["storage"],"description":"","responses":{"200":{"description":"UsageBuckets","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageBuckets"}}}}},"x-appwrite":{"method":"getBucketUsage","cookies":false,"type":"","demo":"storage\/get-bucket-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"bucketId","description":"Bucket ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/logs":{"get":{"summary":"List Team Logs","operationId":"teamsListLogs","tags":["teams"],"description":"Get the team activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"teams\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembership","cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/userList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId"]}}}}}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createArgon2User","cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createBcryptUser","cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/identities":{"get":{"summary":"List Identities","operationId":"usersListIdentities","tags":["users"],"description":"Get identities for all users.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","cookies":false,"type":"","demo":"users\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]}},"\/users\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"usersDeleteIdentity","tags":["users"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","cookies":false,"type":"","demo":"users\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createMD5User","cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createPHPassUser","cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptUser","cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}}}}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptModifiedUser","cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}}}}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createSHAUser","cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/usage":{"get":{"summary":"Get usage stats for the users API","operationId":"usersGetUsage","tags":["users"],"description":"","responses":{"200":{"description":"UsageUsers","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageUsers"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"users\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"},{"name":"provider","description":"Provider Name.","required":false,"schema":{"type":"string","x-example":"email","default":""},"in":"query"}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"}},"required":["email"]}}}}}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateLabels","cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","x-example":null,"items":{"type":"string"}}},"required":["labels"]}}}}}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null}},"required":["password"]}}}}}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","x-example":"+12065550100"}},"required":["number"]}}}}}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","x-example":false}},"required":["status"]}}}}}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmailVerification","cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","x-example":false}},"required":["emailVerification"]}}}}}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhoneVerification","cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","x-example":false}},"required":["phoneVerification"]}}}}}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories":{"get":{"summary":"List Repositories","operationId":"vcsListRepositories","tags":["vcs"],"description":"","responses":{"200":{"description":"Provider Repositories List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/providerRepositoryList"}}}}},"x-appwrite":{"method":"listRepositories","cookies":false,"type":"","demo":"vcs\/list-repositories.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create repository","operationId":"vcsCreateRepository","tags":["vcs"],"description":"","responses":{"200":{"description":"ProviderRepository","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/providerRepository"}}}}},"x-appwrite":{"method":"createRepository","cookies":false,"type":"","demo":"vcs\/create-repository.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Repository name (slug)","x-example":"[NAME]"},"private":{"type":"boolean","description":"Mark repository public or private","x-example":false}},"required":["name","private"]}}}}}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}":{"get":{"summary":"Get repository","operationId":"vcsGetRepository","tags":["vcs"],"description":"","responses":{"200":{"description":"ProviderRepository","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/providerRepository"}}}}},"x-appwrite":{"method":"getRepository","cookies":false,"type":"","demo":"vcs\/get-repository.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"schema":{"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]"},"in":"path"}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/branches":{"get":{"summary":"List Repository Branches","operationId":"vcsListRepositoryBranches","tags":["vcs"],"description":"","responses":{"200":{"description":"Branches List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/branchList"}}}}},"x-appwrite":{"method":"listRepositoryBranches","cookies":false,"type":"","demo":"vcs\/list-repository-branches.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"schema":{"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]"},"in":"path"}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/detection":{"post":{"summary":"Detect runtime settings from source code","operationId":"vcsCreateRepositoryDetection","tags":["vcs"],"description":"","responses":{"200":{"description":"Detection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/detection"}}}}},"x-appwrite":{"method":"createRepositoryDetection","cookies":false,"type":"","demo":"vcs\/create-repository-detection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"schema":{"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"providerRootDirectory":{"type":"string","description":"Path to Root Directory","x-example":"[PROVIDER_ROOT_DIRECTORY]"}}}}}}}},"\/vcs\/github\/installations\/{installationId}\/repositories\/{repositoryId}":{"patch":{"summary":"Authorize external deployment","operationId":"vcsUpdateExternalDeployments","tags":["vcs"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"updateExternalDeployments","cookies":false,"type":"","demo":"vcs\/update-external-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"repositoryId","description":"VCS Repository Id","required":true,"schema":{"type":"string","x-example":"[REPOSITORY_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"providerPullRequestId":{"type":"string","description":"GitHub Pull Request Id","x-example":"[PROVIDER_PULL_REQUEST_ID]"}},"required":["providerPullRequestId"]}}}}}},"\/vcs\/installations":{"get":{"summary":"List installations","operationId":"vcsListInstallations","tags":["vcs"],"description":"","responses":{"200":{"description":"Installations List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/installationList"}}}}},"x-appwrite":{"method":"listInstallations","cookies":false,"type":"","demo":"vcs\/list-installations.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/list-installations.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: provider, organization","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]}},"\/vcs\/installations\/{installationId}":{"get":{"summary":"Get installation","operationId":"vcsGetInstallation","tags":["vcs"],"description":"","responses":{"200":{"description":"Installation","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/installation"}}}}},"x-appwrite":{"method":"getInstallation","cookies":false,"type":"","demo":"vcs\/get-installation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/get-installation.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Installation","operationId":"vcsDeleteInstallation","tags":["vcs"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteInstallation","cookies":false,"type":"","demo":"vcs\/delete-installation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/delete-installation.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"$ref":"#\/components\/schemas\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"$ref":"#\/components\/schemas\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"$ref":"#\/components\/schemas\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"$ref":"#\/components\/schemas\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"$ref":"#\/components\/schemas\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"$ref":"#\/components\/schemas\/function"},"x-example":""}},"required":["total","functions"]},"installationList":{"description":"Installations List","type":"object","properties":{"total":{"type":"integer","description":"Total number of installations documents that matched your query.","x-example":5,"format":"int32"},"installations":{"type":"array","description":"List of installations.","items":{"$ref":"#\/components\/schemas\/installation"},"x-example":""}},"required":["total","installations"]},"providerRepositoryList":{"description":"Provider Repositories List","type":"object","properties":{"total":{"type":"integer","description":"Total number of providerRepositories documents that matched your query.","x-example":5,"format":"int32"},"providerRepositories":{"type":"array","description":"List of providerRepositories.","items":{"$ref":"#\/components\/schemas\/providerRepository"},"x-example":""}},"required":["total","providerRepositories"]},"branchList":{"description":"Branches List","type":"object","properties":{"total":{"type":"integer","description":"Total number of branches documents that matched your query.","x-example":5,"format":"int32"},"branches":{"type":"array","description":"List of branches.","items":{"$ref":"#\/components\/schemas\/branch"},"x-example":""}},"required":["total","branches"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"$ref":"#\/components\/schemas\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"$ref":"#\/components\/schemas\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"projectList":{"description":"Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"$ref":"#\/components\/schemas\/project"},"x-example":""}},"required":["total","projects"]},"webhookList":{"description":"Webhooks List","type":"object","properties":{"total":{"type":"integer","description":"Total number of webhooks documents that matched your query.","x-example":5,"format":"int32"},"webhooks":{"type":"array","description":"List of webhooks.","items":{"$ref":"#\/components\/schemas\/webhook"},"x-example":""}},"required":["total","webhooks"]},"keyList":{"description":"API Keys List","type":"object","properties":{"total":{"type":"integer","description":"Total number of keys documents that matched your query.","x-example":5,"format":"int32"},"keys":{"type":"array","description":"List of keys.","items":{"$ref":"#\/components\/schemas\/key"},"x-example":""}},"required":["total","keys"]},"platformList":{"description":"Platforms List","type":"object","properties":{"total":{"type":"integer","description":"Total number of platforms documents that matched your query.","x-example":5,"format":"int32"},"platforms":{"type":"array","description":"List of platforms.","items":{"$ref":"#\/components\/schemas\/platform"},"x-example":""}},"required":["total","platforms"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":""}},"required":["total","variables"]},"proxyRuleList":{"description":"Rule List","type":"object","properties":{"total":{"type":"integer","description":"Total number of rules documents that matched your query.","x-example":5,"format":"int32"},"rules":{"type":"array","description":"List of rules.","items":{"$ref":"#\/components\/schemas\/proxyRule"},"x-example":""}},"required":["total","rules"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"migrationList":{"description":"Migrations List","type":"object","properties":{"total":{"type":"integer","description":"Total number of migrations documents that matched your query.","x-example":5,"format":"int32"},"migrations":{"type":"array","description":"List of migrations.","items":{"$ref":"#\/components\/schemas\/migration"},"x-example":""}},"required":["total","migrations"]},"firebaseProjectList":{"description":"Migrations Firebase Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"$ref":"#\/components\/schemas\/firebaseProject"},"x-example":""}},"required":["total","projects"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"If database is enabled. Can be 'enabled' or 'disabled'. When disabled, the database is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled. Can be 'enabled' or 'disabled'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"live":{"type":"boolean","description":"Is the function deployed with the latest configuration? This is set to false if you've changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":300,"format":"int32"},"entrypoint":{"type":"string","description":"The entrypoint file used to execute the deployment.","x-example":"index.js"},"commands":{"type":"string","description":"The build command used to build the deployment.","x-example":"npm install"},"version":{"type":"string","description":"Version of Open Runtimes used for the function.","x-example":"v2"},"installationId":{"type":"string","description":"Function VCS (Version Control System) installation id.","x-example":"6m40at4ejk5h2u9s1hboo"},"providerRepositoryId":{"type":"string","description":"VCS (Version Control System) Repository ID","x-example":"appwrite"},"providerBranch":{"type":"string","description":"VCS (Version Control System) branch name","x-example":"main"},"providerRootDirectory":{"type":"string","description":"Path to function in VCS (Version Control System) repository","x-example":"functions\/helloWorld"},"providerSilentMode":{"type":"boolean","description":"Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests","x-example":false}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","live","logging","runtime","deployment","vars","events","schedule","timeout","entrypoint","commands","version","installationId","providerRepositoryId","providerBranch","providerRootDirectory","providerSilentMode"]},"installation":{"description":"Installation","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"VCS (Version Control System) provider name.","x-example":"github"},"organization":{"type":"string","description":"VCS (Version Control System) organization name.","x-example":"appwrite"},"providerInstallationId":{"type":"string","description":"VCS (Version Control System) installation ID.","x-example":"5322"}},"required":["$id","$createdAt","$updatedAt","provider","organization","providerInstallationId"]},"providerRepository":{"description":"ProviderRepository","type":"object","properties":{"id":{"type":"string","description":"VCS (Version Control System) repository ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"VCS (Version Control System) repository name.","x-example":"appwrite"},"organization":{"type":"string","description":"VCS (Version Control System) organization name","x-example":"appwrite"},"provider":{"type":"string","description":"VCS (Version Control System) provider name.","x-example":"github"},"private":{"type":"boolean","description":"Is VCS (Version Control System) repository private?","x-example":true},"runtime":{"type":"string","description":"Auto-detected runtime suggestion. Empty if getting response of getRuntime().","x-example":"node"},"pushedAt":{"type":"string","description":"Last commit date in ISO 8601 format.","x-example":"datetime"}},"required":["id","name","organization","provider","private","runtime","pushedAt"]},"detection":{"description":"Detection","type":"object","properties":{"runtime":{"type":"string","description":"Runtime","x-example":"node"}},"required":["runtime"]},"branch":{"description":"Branch","type":"object","properties":{"name":{"type":"string","description":"Branch Name.","x-example":"main"}},"required":["name"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"type":{"type":"string","description":"Type of deployment.","x-example":"vcs"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"index.js"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"waiting\", \"ready\", and \"failed\".","x-example":"ready"},"buildLogs":{"type":"string","description":"The build logs.","x-example":"Compiling source files..."},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"},"providerRepositoryName":{"type":"string","description":"The name of the vcs provider repository","x-example":"database"},"providerRepositoryOwner":{"type":"string","description":"The name of the vcs provider repository owner","x-example":"utopia"},"providerRepositoryUrl":{"type":"string","description":"The url of the vcs provider repository","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function"},"providerBranch":{"type":"string","description":"The branch of the vcs repository","x-example":"0.7.x"},"providerCommitHash":{"type":"string","description":"The commit hash of the vcs commit","x-example":"7c3f25d"},"providerCommitAuthorUrl":{"type":"string","description":"The url of vcs commit author","x-example":"https:\/\/github.com\/vermakhushboo"},"providerCommitAuthor":{"type":"string","description":"The name of vcs commit author","x-example":"Khushboo Verma"},"providerCommitMessage":{"type":"string","description":"The commit message","x-example":"Update index.js"},"providerCommitUrl":{"type":"string","description":"The url of the vcs commit","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function\/commit\/60c0416257a9cbcdd96b2d370c38d8f8d150ccfb"},"providerBranchUrl":{"type":"string","description":"The branch of the vcs repository","x-example":"https:\/\/github.com\/vermakhushboo\/appwrite\/tree\/0.7.x"}},"required":["$id","$createdAt","$updatedAt","type","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildLogs","buildTime","providerRepositoryName","providerRepositoryOwner","providerRepositoryUrl","providerBranch","providerCommitHash","providerCommitAuthorUrl","providerCommitAuthor","providerCommitMessage","providerCommitUrl","providerBranchUrl"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"project":{"description":"Project","type":"object","properties":{"$id":{"type":"string","description":"Project ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Project creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Project update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Project name.","x-example":"New Project"},"description":{"type":"string","description":"Project description.","x-example":"This is a new project."},"teamId":{"type":"string","description":"Project team ID.","x-example":"1592981250"},"logo":{"type":"string","description":"Project logo file ID.","x-example":"5f5c451b403cb"},"url":{"type":"string","description":"Project website URL.","x-example":"5f5c451b403cb"},"legalName":{"type":"string","description":"Company legal name.","x-example":"Company LTD."},"legalCountry":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format.","x-example":"US"},"legalState":{"type":"string","description":"State name.","x-example":"New York"},"legalCity":{"type":"string","description":"City name.","x-example":"New York City."},"legalAddress":{"type":"string","description":"Company Address.","x-example":"620 Eighth Avenue, New York, NY 10018"},"legalTaxId":{"type":"string","description":"Company Tax ID.","x-example":"131102020"},"authDuration":{"type":"integer","description":"Session duration in seconds.","x-example":60,"format":"int32"},"authLimit":{"type":"integer","description":"Max users allowed. 0 is unlimited.","x-example":100,"format":"int32"},"authSessionsLimit":{"type":"integer","description":"Max sessions allowed per user. 100 maximum.","x-example":10,"format":"int32"},"authPasswordHistory":{"type":"integer","description":"Max allowed passwords in the history list per user. Max passwords limit allowed in history is 20. Use 0 for disabling password history.","x-example":5,"format":"int32"},"authPasswordDictionary":{"type":"boolean","description":"Whether or not to check user's password against most commonly used passwords.","x-example":true},"authPersonalDataCheck":{"type":"boolean","description":"Whether or not to check the user password for similarity with their personal data.","x-example":true},"providers":{"type":"array","description":"List of Providers.","items":{"$ref":"#\/components\/schemas\/provider"},"x-example":[{}]},"platforms":{"type":"array","description":"List of Platforms.","items":{"$ref":"#\/components\/schemas\/platform"},"x-example":{}},"webhooks":{"type":"array","description":"List of Webhooks.","items":{"$ref":"#\/components\/schemas\/webhook"},"x-example":{}},"keys":{"type":"array","description":"List of API Keys.","items":{"$ref":"#\/components\/schemas\/key"},"x-example":{}},"smtpEnabled":{"type":"boolean","description":"Status for custom SMTP","x-example":false},"smtpSenderName":{"type":"string","description":"SMTP sender name","x-example":"John Appwrite"},"smtpSenderEmail":{"type":"string","description":"SMTP sender email","x-example":"john@appwrite.io"},"smtpReplyTo":{"type":"string","description":"SMTP reply to email","x-example":"support@appwrite.io"},"smtpHost":{"type":"string","description":"SMTP server host name","x-example":"mail.appwrite.io"},"smtpPort":{"type":"integer","description":"SMTP server port","x-example":25,"format":"int32"},"smtpUsername":{"type":"string","description":"SMTP server username","x-example":"emailuser"},"smtpPassword":{"type":"string","description":"SMTP server password","x-example":"securepassword"},"smtpSecure":{"type":"string","description":"SMTP server secure protocol","x-example":"tls"},"authEmailPassword":{"type":"boolean","description":"Email\/Password auth method status","x-example":true},"authUsersAuthMagicURL":{"type":"boolean","description":"Magic URL auth method status","x-example":true},"authAnonymous":{"type":"boolean","description":"Anonymous auth method status","x-example":true},"authInvites":{"type":"boolean","description":"Invites auth method status","x-example":true},"authJWT":{"type":"boolean","description":"JWT auth method status","x-example":true},"authPhone":{"type":"boolean","description":"Phone auth method status","x-example":true},"serviceStatusForAccount":{"type":"boolean","description":"Account service status","x-example":true},"serviceStatusForAvatars":{"type":"boolean","description":"Avatars service status","x-example":true},"serviceStatusForDatabases":{"type":"boolean","description":"Databases service status","x-example":true},"serviceStatusForLocale":{"type":"boolean","description":"Locale service status","x-example":true},"serviceStatusForHealth":{"type":"boolean","description":"Health service status","x-example":true},"serviceStatusForStorage":{"type":"boolean","description":"Storage service status","x-example":true},"serviceStatusForTeams":{"type":"boolean","description":"Teams service status","x-example":true},"serviceStatusForUsers":{"type":"boolean","description":"Users service status","x-example":true},"serviceStatusForVcs":{"type":"boolean","description":"VCS service status","x-example":true},"serviceStatusForFunctions":{"type":"boolean","description":"Functions service status","x-example":true},"serviceStatusForProxy":{"type":"boolean","description":"Proxy service status","x-example":true},"serviceStatusForGraphql":{"type":"boolean","description":"GraphQL service status","x-example":true},"serviceStatusForMigrations":{"type":"boolean","description":"Migrations service status","x-example":true}},"required":["$id","$createdAt","$updatedAt","name","description","teamId","logo","url","legalName","legalCountry","legalState","legalCity","legalAddress","legalTaxId","authDuration","authLimit","authSessionsLimit","authPasswordHistory","authPasswordDictionary","authPersonalDataCheck","providers","platforms","webhooks","keys","smtpEnabled","smtpSenderName","smtpSenderEmail","smtpReplyTo","smtpHost","smtpPort","smtpUsername","smtpPassword","smtpSecure","authEmailPassword","authUsersAuthMagicURL","authAnonymous","authInvites","authJWT","authPhone","serviceStatusForAccount","serviceStatusForAvatars","serviceStatusForDatabases","serviceStatusForLocale","serviceStatusForHealth","serviceStatusForStorage","serviceStatusForTeams","serviceStatusForUsers","serviceStatusForVcs","serviceStatusForFunctions","serviceStatusForProxy","serviceStatusForGraphql","serviceStatusForMigrations"]},"webhook":{"description":"Webhook","type":"object","properties":{"$id":{"type":"string","description":"Webhook ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Webhook creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Webhook update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Webhook name.","x-example":"My Webhook"},"url":{"type":"string","description":"Webhook URL endpoint.","x-example":"https:\/\/example.com\/webhook"},"events":{"type":"array","description":"Webhook trigger events.","items":{"type":"string"},"x-example":"database.collections.update"},"security":{"type":"boolean","description":"Indicated if SSL \/ TLS Certificate verification is enabled.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"},"signatureKey":{"type":"string","description":"Signature key which can be used to validated incoming","x-example":"ad3d581ca230e2b7059c545e5a"}},"required":["$id","$createdAt","$updatedAt","name","url","events","security","httpUser","httpPass","signatureKey"]},"key":{"description":"Key","type":"object","properties":{"$id":{"type":"string","description":"Key ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Key creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Key update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Key name.","x-example":"My API Key"},"expire":{"type":"string","description":"Key expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"scopes":{"type":"array","description":"Allowed permission scopes.","items":{"type":"string"},"x-example":"users.read"},"secret":{"type":"string","description":"Secret key.","x-example":"919c2d18fb5d4...a2ae413da83346ad2"},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"},"sdks":{"type":"array","description":"List of SDK user agents that used this key.","items":{"type":"string"},"x-example":"appwrite:flutter"}},"required":["$id","$createdAt","$updatedAt","name","expire","scopes","secret","accessedAt","sdks"]},"provider":{"description":"Provider","type":"object","properties":{"key":{"type":"string","description":"Provider.","x-example":"github"},"name":{"type":"string","description":"Provider name.","x-example":"GitHub"},"appId":{"type":"string","description":"OAuth 2.0 application ID.","x-example":"259125845563242502"},"secret":{"type":"string","description":"OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.","x-example":"Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ"},"enabled":{"type":"boolean","description":"Provider is active and can be used to create session.","x-example":""}},"required":["key","name","appId","secret","enabled"]},"platform":{"description":"Platform","type":"object","properties":{"$id":{"type":"string","description":"Platform ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Platform creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Platform update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Platform name.","x-example":"My Web App"},"type":{"type":"string","description":"Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, and unity.","x-example":"web"},"key":{"type":"string","description":"Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.","x-example":"com.company.appname"},"store":{"type":"string","description":"App store or Google Play store ID.","x-example":""},"hostname":{"type":"string","description":"Web app hostname. Empty string for other platforms.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"}},"required":["$id","$createdAt","$updatedAt","name","type","key","store","hostname","httpUser","httpPass"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"resourceType":{"type":"string","description":"Service to which the variable belongs. Possible values are \"project\", \"function\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource to which the variable belongs. If resourceType is \"project\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"}},"required":["$id","$createdAt","$updatedAt","key","value","resourceType","resourceId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"metric":{"description":"Metric","type":"object","properties":{"value":{"type":"integer","description":"The value of this metric at the timestamp.","x-example":1,"format":"int32"},"date":{"type":"string","description":"The date at which this metric was aggregated in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["value","date"]},"usageDatabases":{"description":"UsageDatabases","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"databasesCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsCount":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesDelete":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsCreate":{"type":"array","description":"Aggregated stats for collections created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsRead":{"type":"array","description":"Aggregated stats for collections read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsUpdate":{"type":"array","description":"Aggregated stats for collections updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsDelete":{"type":"array","description":"Aggregated stats for collections delete.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","databasesCount","documentsCount","collectionsCount","databasesCreate","databasesRead","databasesUpdate","databasesDelete","documentsCreate","documentsRead","documentsUpdate","documentsDelete","collectionsCreate","collectionsRead","collectionsUpdate","collectionsDelete"]},"usageDatabase":{"description":"UsageDatabase","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsCount":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsCreate":{"type":"array","description":"Aggregated stats for collections created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsRead":{"type":"array","description":"Aggregated stats for collections read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsUpdate":{"type":"array","description":"Aggregated stats for collections updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsDelete":{"type":"array","description":"Aggregated stats for collections delete.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","documentsCount","collectionsCount","documentsCreate","documentsRead","documentsUpdate","documentsDelete","collectionsCreate","collectionsRead","collectionsUpdate","collectionsDelete"]},"usageCollection":{"description":"UsageCollection","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","documentsCount","documentsCreate","documentsRead","documentsUpdate","documentsDelete"]},"usageUsers":{"description":"UsageUsers","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"usersCount":{"type":"array","description":"Aggregated stats for total number of users.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersCreate":{"type":"array","description":"Aggregated stats for users created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersRead":{"type":"array","description":"Aggregated stats for users read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersUpdate":{"type":"array","description":"Aggregated stats for users updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersDelete":{"type":"array","description":"Aggregated stats for users deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"sessionsCreate":{"type":"array","description":"Aggregated stats for sessions created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"sessionsProviderCreate":{"type":"array","description":"Aggregated stats for sessions created for a provider ( email, anonymous or oauth2 ).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"sessionsDelete":{"type":"array","description":"Aggregated stats for sessions deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","usersCount","usersCreate","usersRead","usersUpdate","usersDelete","sessionsCreate","sessionsProviderCreate","sessionsDelete"]},"usageStorage":{"description":"StorageUsage","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"storage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesCount":{"type":"array","description":"Aggregated stats for total number of files.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsCount":{"type":"array","description":"Aggregated stats for total number of buckets.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsCreate":{"type":"array","description":"Aggregated stats for buckets created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsRead":{"type":"array","description":"Aggregated stats for buckets read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsUpdate":{"type":"array","description":"Aggregated stats for buckets updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsDelete":{"type":"array","description":"Aggregated stats for buckets deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesCreate":{"type":"array","description":"Aggregated stats for files created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesRead":{"type":"array","description":"Aggregated stats for files read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesUpdate":{"type":"array","description":"Aggregated stats for files updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesDelete":{"type":"array","description":"Aggregated stats for files deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","storage","filesCount","bucketsCount","bucketsCreate","bucketsRead","bucketsUpdate","bucketsDelete","filesCreate","filesRead","filesUpdate","filesDelete"]},"usageBuckets":{"description":"UsageBuckets","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"filesCount":{"type":"array","description":"Aggregated stats for total number of files in this bucket.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for total storage of files in this bucket.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesCreate":{"type":"array","description":"Aggregated stats for files created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesRead":{"type":"array","description":"Aggregated stats for files read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesUpdate":{"type":"array","description":"Aggregated stats for files updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesDelete":{"type":"array","description":"Aggregated stats for files deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","filesCount","filesStorage","filesCreate","filesRead","filesUpdate","filesDelete"]},"usageFunctions":{"description":"UsageFunctions","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"executionsTotal":{"type":"array","description":"Aggregated stats for number of function executions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsFailure":{"type":"array","description":"Aggregated stats for function execution failures.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsSuccess":{"type":"array","description":"Aggregated stats for function execution successes.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsTime":{"type":"array","description":"Aggregated stats for function execution duration.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsTotal":{"type":"array","description":"Aggregated stats for number of function builds.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsFailure":{"type":"array","description":"Aggregated stats for function build failures.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsSuccess":{"type":"array","description":"Aggregated stats for function build successes.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsTime":{"type":"array","description":"Aggregated stats for function build duration.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","executionsTotal","executionsFailure","executionsSuccess","executionsTime","buildsTotal","buildsFailure","buildsSuccess","buildsTime"]},"usageProject":{"description":"UsageProject","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"requests":{"type":"array","description":"Aggregated stats for number of requests.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"network":{"type":"array","description":"Aggregated stats for consumed bandwidth.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executions":{"type":"array","description":"Aggregated stats for function executions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documents":{"type":"array","description":"Aggregated stats for number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databases":{"type":"array","description":"Aggregated stats for number of databases.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"users":{"type":"array","description":"Aggregated stats for number of users.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"storage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buckets":{"type":"array","description":"Aggregated stats for number of buckets.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","requests","network","executions","documents","databases","users","storage","buckets"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]},"proxyRule":{"description":"Rule","type":"object","properties":{"$id":{"type":"string","description":"Rule ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Rule creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Rule update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"domain":{"type":"string","description":"Domain name.","x-example":"appwrite.company.com"},"resourceType":{"type":"string","description":"Action definition for the rule. Possible values are \"api\", \"function\", or \"redirect\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource for the action type. If resourceType is \"api\" or \"url\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"},"status":{"type":"string","description":"Domain verification status. Possible values are \"created\", \"verifying\", \"verified\" and \"unverified\"","x-example":"verified"},"logs":{"type":"string","description":"Certificate generation logs. This will return an empty string if generation did not run, or succeeded.","x-example":"HTTP challegne failed."},"renewAt":{"type":"string","description":"Certificate auto-renewal date in ISO 8601 format.","x-example":"datetime"}},"required":["$id","$createdAt","$updatedAt","domain","resourceType","resourceId","status","logs","renewAt"]},"smsTemplate":{"description":"SmsTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."}},"required":["type","locale","message"]},"emailTemplate":{"description":"EmailTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."},"senderName":{"type":"string","description":"Name of the sender","x-example":"My User"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"mail@appwrite.io"},"replyTo":{"type":"string","description":"Reply to email address","x-example":"emails@appwrite.io"},"subject":{"type":"string","description":"Email subject","x-example":"Please verify your email address"}},"required":["type","locale","message","senderName","senderEmail","replyTo","subject"]},"consoleVariables":{"description":"Console Variables","type":"object","properties":{"_APP_DOMAIN_TARGET":{"type":"string","description":"CNAME target for your Appwrite custom domains.","x-example":"appwrite.io"},"_APP_STORAGE_LIMIT":{"type":"integer","description":"Maximum file size allowed for file upload in bytes.","x-example":"30000000","format":"int32"},"_APP_FUNCTIONS_SIZE_LIMIT":{"type":"integer","description":"Maximum file size allowed for deployment in bytes.","x-example":"30000000","format":"int32"},"_APP_USAGE_STATS":{"type":"string","description":"Defines if usage stats are enabled. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'.","x-example":"enabled"},"_APP_VCS_ENABLED":{"type":"boolean","description":"Defines if VCS (Version Control System) is enabled.","x-example":true},"_APP_DOMAIN_ENABLED":{"type":"boolean","description":"Defines if main domain is configured. If so, custom domains can be created.","x-example":true},"_APP_ASSISTANT_ENABLED":{"type":"boolean","description":"Defines if AI assistant is enabled.","x-example":true}},"required":["_APP_DOMAIN_TARGET","_APP_STORAGE_LIMIT","_APP_FUNCTIONS_SIZE_LIMIT","_APP_USAGE_STATS","_APP_VCS_ENABLED","_APP_DOMAIN_ENABLED","_APP_ASSISTANT_ENABLED"]},"migration":{"description":"Migration","type":"object","properties":{"$id":{"type":"string","description":"Migration ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"string","description":"Migration status ( pending, processing, failed, completed ) ","x-example":"pending"},"stage":{"type":"string","description":"Migration stage ( init, processing, source-check, destination-check, migrating, finished )","x-example":"init"},"source":{"type":"string","description":"A string containing the type of source of the migration.","x-example":"Appwrite"},"resources":{"type":"array","description":"Resources to migration.","items":{"type":"string"},"x-example":["user"]},"statusCounters":{"type":"object","description":"A group of counters that represent the total progress of the migration.","x-example":"{\"Database\": {\"PENDING\": 0, \"SUCCESS\": 1, \"ERROR\": 0, \"SKIP\": 0, \"PROCESSING\": 0, \"WARNING\": 0}}"},"resourceData":{"type":"object","description":"An array of objects containing the report data of the resources that were migrated.","x-example":"[{\"resource\":\"Database\",\"id\":\"public\",\"status\":\"SUCCESS\",\"message\":\"\"}]"},"errors":{"type":"string","description":"All errors that occurred during the migration process.","x-example":[]}},"required":["$id","$createdAt","$updatedAt","status","stage","source","resources","statusCounters","resourceData","errors"]},"migrationReport":{"description":"Migration Report","type":"object","properties":{"user":{"type":"integer","description":"Number of users to be migrated.","x-example":20,"format":"int32"},"team":{"type":"integer","description":"Number of teams to be migrated.","x-example":20,"format":"int32"},"database":{"type":"integer","description":"Number of databases to be migrated.","x-example":20,"format":"int32"},"document":{"type":"integer","description":"Number of documents to be migrated.","x-example":20,"format":"int32"},"file":{"type":"integer","description":"Number of files to be migrated.","x-example":20,"format":"int32"},"bucket":{"type":"integer","description":"Number of buckets to be migrated.","x-example":20,"format":"int32"},"function":{"type":"integer","description":"Number of functions to be migrated.","x-example":20,"format":"int32"},"size":{"type":"integer","description":"Size of files to be migrated in mb.","x-example":30000,"format":"int32"},"version":{"type":"string","description":"Version of the Appwrite instance to be migrated.","x-example":"1.4.0"}},"required":["user","team","database","document","file","bucket","function","size","version"]},"firebaseProject":{"description":"MigrationFirebaseProject","type":"object","properties":{"projectId":{"type":"string","description":"Project ID.","x-example":"my-project"},"displayName":{"type":"string","description":"Project display name.","x-example":"My Project"}},"required":["projectId","displayName"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}},"Mode":{"type":"apiKey","name":"X-Appwrite-Mode","description":"","in":"header","x-appwrite":{"demo":""}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/open-api3-1.4.x-server.json b/app/config/specs/open-api3-1.4.x-server.json index f4d0b3f98e..87d38a2ed2 100644 --- a/app/config/specs/open-api3-1.4.x-server.json +++ b/app/config/specs/open-api3-1.4.x-server.json @@ -1 +1 @@ -{"openapi":"3.0.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa"},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex"},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af"},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/databaseList"}}}}},"x-appwrite":{"method":"list","weight":50,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"create","weight":49,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","x-example":false}},"required":["databaseId","name"]}}}}}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"get","weight":51,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"update","weight":53,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Database","operationId":"databasesDelete","tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":54,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collectionList"}}}}},"x-appwrite":{"method":"listCollections","weight":56,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"createCollection","weight":55,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","x-example":false}},"required":["collectionId","name"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"getCollection","weight":57,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"updateCollection","weight":59,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":60,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeList"}}}}},"x-appwrite":{"method":"listAttributes","weight":71,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"createBooleanAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"createEmailAttribute","weight":62,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"updateEmailAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"createEnumAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","elements","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"updateEnumAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"createFloatAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"updateFloatAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"createIntegerAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"createIpAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"updateIpAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","x-example":"oneToOne"},"twoWay":{"type":"boolean","description":"Is Two Way?","x-example":false},"key":{"type":"string","description":"Attribute Key.","x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","x-example":null},"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade"}},"required":["relatedCollectionId","type"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"createStringAttribute","weight":61,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","x-example":1},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","size","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"updateStringAttribute","weight":73,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"createUrlAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"updateUrlAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","content":{"application\/json":{"schema":{"oneOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]}}}}},"x-appwrite":{"method":"getAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade"}}}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/indexList"}}}}},"x-appwrite":{"method":"listIndexes","weight":85,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","tags":["databases"],"description":"","responses":{"202":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"createIndex","weight":84,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":null},"type":{"type":"string","description":"Index type.","x-example":"key"},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","tags":["databases"],"description":"","responses":{"200":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"getIndex","weight":86,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":87,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/functionList"}}}}},"x-appwrite":{"method":"list","weight":222,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"create","weight":221,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","x-example":false}},"required":["functionId","name","runtime"]}}}}}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/runtimeList"}}}}},"x-appwrite":{"method":"listRuntimes","weight":223,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"get","weight":224,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"update","weight":227,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Function","operationId":"functionsDelete","tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":229,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deploymentList"}}}}},"x-appwrite":{"method":"listDeployments","weight":231,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: entrypoint, size, buildId, activate","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","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](\/docs\/functions).\n\nUse the \"command\" param to set the entry point used to execute your code.","responses":{"202":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"createDeployment","weight":230,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"entrypoint":{"type":"string","description":"Entrypoint File.","x-example":"[ENTRYPOINT]"},"code":{"type":"string","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","x-example":null},"activate":{"type":"boolean","description":"Automatically activate the deployment when it is finished building.","x-example":false}},"required":["entrypoint","code","activate"]}}}}}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"getDeployment","weight":232,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"updateDeployment","weight":228,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":233,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","tags":["functions"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":234,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"schema":{"type":"string","x-example":"[BUILD_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","weight":239,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","tags":["functions"],"description":"Create a new function variable. These variables can be accessed within function in the `env` object under the request variable.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","weight":238,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","weight":240,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","weight":241,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":242,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"get","weight":105,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthAntivirus"}}}}},"x-appwrite":{"method":"getAntivirus","weight":117,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getCache","weight":108,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getDB","weight":107,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getPubSub","weight":110,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getQueue","weight":109,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueCertificates","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueFunctions","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueLogs","weight":113,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueWebhooks","weight":112,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getStorageLocal","weight":116,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthTime"}}}}},"x-appwrite":{"method":"getTime","weight":111,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucketList"}}}}},"x-appwrite":{"method":"listBuckets","weight":165,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"createBucket","weight":164,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none"},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["bucketId","name"]}}}}}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"getBucket","weight":166,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"updateBucket","weight":167,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none"},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":168,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","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](\/docs\/permissions).","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/userList"}}}}},"x-appwrite":{"method":"list","weight":201,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":193,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId"]}}}}}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createArgon2User","weight":196,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createBcryptUser","weight":194,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createMD5User","weight":195,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createPHPassUser","weight":198,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptUser","weight":199,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}}}}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":200,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}}}}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createSHAUser","weight":197,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","x-example":"sha1"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":202,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":219,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":213,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"}},"required":["email"]}}}}}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateLabels","weight":208,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","x-example":null,"items":{"type":"string"}}},"required":["labels"]}}}}}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":206,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":205,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":211,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":212,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null}},"required":["password"]}}}}}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":214,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","x-example":"+12065550100"}},"required":["number"]}}}}}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":203,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":216,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":204,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":218,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":217,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":207,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","x-example":false}},"required":["status"]}}}}}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmailVerification","weight":215,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","x-example":false}},"required":["emailVerification"]}}}}}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":210,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","x-example":false}},"required":["phoneVerification"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"$ref":"#\/components\/schemas\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"$ref":"#\/components\/schemas\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"$ref":"#\/components\/schemas\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"$ref":"#\/components\/schemas\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"$ref":"#\/components\/schemas\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"$ref":"#\/components\/schemas\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"$ref":"#\/components\/schemas\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"Database enabled.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":15,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","runtime","deployment","vars","events","schedule","timeout"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"enabled"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"pending\", \"ready\", and \"failed\".","x-example":"ready"},"buildStdout":{"type":"string","description":"The build stdout.","x-example":"enabled"},"buildStderr":{"type":"string","description":"The build stderr.","x-example":"enabled"},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildStdout","buildStderr","buildTime"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"}},"required":["$id","$createdAt","$updatedAt","key","value","functionId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"openapi":"3.0.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":21,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":28,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","weight":13,"cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":14,"cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":24,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":26,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":27,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":29,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":22,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":30,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":35,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":36,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":23,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":34,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":25,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":33,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":32,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":31,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":39,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":40,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":47,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":46,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/databaseList"}}}}},"x-appwrite":{"method":"list","weight":52,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"create","weight":51,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","x-example":false}},"required":["databaseId","name"]}}}}}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"get","weight":53,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"update","weight":55,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Database","operationId":"databasesDelete","tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":56,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collectionList"}}}}},"x-appwrite":{"method":"listCollections","weight":58,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"createCollection","weight":57,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","x-example":false}},"required":["collectionId","name"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"getCollection","weight":59,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"updateCollection","weight":61,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":62,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeList"}}}}},"x-appwrite":{"method":"listAttributes","weight":73,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"createBooleanAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":71,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"createEmailAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"updateEmailAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"createEnumAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","elements","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"updateEnumAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"createFloatAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"updateFloatAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"createIntegerAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"createIpAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"updateIpAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","x-example":false},"key":{"type":"string","description":"Attribute Key.","x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","x-example":null},"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"createStringAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","x-example":1},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false},"encrypt":{"type":"boolean","description":"Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.","x-example":false}},"required":["key","size","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"updateStringAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"createUrlAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"updateUrlAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","content":{"application\/json":{"schema":{"oneOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]}}}}},"x-appwrite":{"method":"getAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":85,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":84,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":91,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":90,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":92,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":94,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":95,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/indexList"}}}}},"x-appwrite":{"method":"listIndexes","weight":87,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","tags":["databases"],"description":"","responses":{"202":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"createIndex","weight":86,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":null},"type":{"type":"string","description":"Index type.","x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","tags":["databases"],"description":"","responses":{"200":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"getIndex","weight":88,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":89,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/functionList"}}}}},"x-appwrite":{"method":"list","weight":238,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"create","weight":237,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Control System) deployment.","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function.","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function.","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","x-example":"[PROVIDER_ROOT_DIRECTORY]"},"templateRepository":{"type":"string","description":"Repository name of the template.","x-example":"[TEMPLATE_REPOSITORY]"},"templateOwner":{"type":"string","description":"The name of the owner of the template.","x-example":"[TEMPLATE_OWNER]"},"templateRootDirectory":{"type":"string","description":"Path to function code in the template repo.","x-example":"[TEMPLATE_ROOT_DIRECTORY]"},"templateBranch":{"type":"string","description":"Production branch for the repo linked to the function template.","x-example":"[TEMPLATE_BRANCH]"}},"required":["functionId","name","runtime"]}}}}}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/runtimeList"}}}}},"x-appwrite":{"method":"listRuntimes","weight":239,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"get","weight":240,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"update","weight":243,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Controle System) deployment.","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","x-example":"[PROVIDER_ROOT_DIRECTORY]"}},"required":["name","runtime"]}}}}},"delete":{"summary":"Delete Function","operationId":"functionsDelete","tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":246,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deploymentList"}}}}},"x-appwrite":{"method":"listDeployments","weight":248,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: size, buildId, activate, entrypoint, commands","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","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](\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.","responses":{"202":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"createDeployment","weight":247,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"entrypoint":{"type":"string","description":"Entrypoint File.","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"code":{"type":"string","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","x-example":null},"activate":{"type":"boolean","description":"Automatically activate the deployment when it is finished building.","x-example":false}},"required":["code","activate"]}}}}}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"getDeployment","weight":249,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"updateDeployment","weight":245,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":250,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","tags":["functions"],"description":"Create a new build for an Appwrite Function deployment. This endpoint can be used to retry a failed build.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":251,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"schema":{"type":"string","x-example":"[BUILD_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/download":{"get":{"summary":"Download Deployment","operationId":"functionsDownloadDeployment","tags":["functions"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"downloadDeployment","weight":244,"cookies":false,"type":"location","demo":"functions\/download-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/download-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":253,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":252,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","x-example":"[BODY]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false},"path":{"type":"string","description":"HTTP path of execution. Path can include query params. Default value is \/","x-example":"[PATH]"},"method":{"type":"string","description":"HTTP method of execution. Default value is GET.","x-example":"GET","enum":["GET","POST","PUT","PATCH","DELETE","OPTIONS"],"x-enum-name":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","x-example":"{}"}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":254,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","weight":256,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","tags":["functions"],"description":"Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","weight":255,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","weight":257,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","weight":258,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":259,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":293,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":292,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"get","weight":107,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthAntivirus"}}}}},"x-appwrite":{"method":"getAntivirus","weight":119,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getCache","weight":110,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getDB","weight":109,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getPubSub","weight":112,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getQueue","weight":111,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueCertificates","weight":116,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueFunctions","weight":117,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueLogs","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueWebhooks","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getStorageLocal","weight":118,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthTime"}}}}},"x-appwrite":{"method":"getTime","weight":113,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":99,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":100,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":104,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":102,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":103,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":105,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":106,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucketList"}}}}},"x-appwrite":{"method":"listBuckets","weight":168,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"createBucket","weight":167,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["bucketId","name"]}}}}}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"getBucket","weight":169,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"updateBucket","weight":170,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":171,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":173,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":172,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":174,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":178,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":179,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":176,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":175,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":177,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":183,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":182,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":184,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":186,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":188,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":190,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":189,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":191,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembership","weight":192,"cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":194,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":193,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":185,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":187,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/userList"}}}}},"x-appwrite":{"method":"list","weight":204,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":196,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId"]}}}}}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createArgon2User","weight":199,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createBcryptUser","weight":197,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/identities":{"get":{"summary":"List Identities","operationId":"usersListIdentities","tags":["users"],"description":"Get identities for all users.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","weight":210,"cookies":false,"type":"","demo":"users\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]}},"\/users\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"usersDeleteIdentity","tags":["users"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":223,"cookies":false,"type":"","demo":"users\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createMD5User","weight":198,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createPHPassUser","weight":201,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptUser","weight":202,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}}}}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":203,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}}}}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createSHAUser","weight":200,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":205,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":222,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":216,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"}},"required":["email"]}}}}}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateLabels","weight":212,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","x-example":null,"items":{"type":"string"}}},"required":["labels"]}}}}}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":209,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":208,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":214,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":215,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null}},"required":["password"]}}}}}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":217,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","x-example":"+12065550100"}},"required":["number"]}}}}}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":206,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":219,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":207,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":221,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":220,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":211,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","x-example":false}},"required":["status"]}}}}}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmailVerification","weight":218,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","x-example":false}},"required":["emailVerification"]}}}}}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":213,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","x-example":false}},"required":["phoneVerification"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"$ref":"#\/components\/schemas\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"$ref":"#\/components\/schemas\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"$ref":"#\/components\/schemas\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"$ref":"#\/components\/schemas\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"$ref":"#\/components\/schemas\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"$ref":"#\/components\/schemas\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"$ref":"#\/components\/schemas\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"$ref":"#\/components\/schemas\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"If database is enabled. Can be 'enabled' or 'disabled'. When disabled, the database is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled. Can be 'enabled' or 'disabled'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"live":{"type":"boolean","description":"Is the function deployed with the latest configuration? This is set to false if you've changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":300,"format":"int32"},"entrypoint":{"type":"string","description":"The entrypoint file used to execute the deployment.","x-example":"index.js"},"commands":{"type":"string","description":"The build command used to build the deployment.","x-example":"npm install"},"version":{"type":"string","description":"Version of Open Runtimes used for the function.","x-example":"v2"},"installationId":{"type":"string","description":"Function VCS (Version Control System) installation id.","x-example":"6m40at4ejk5h2u9s1hboo"},"providerRepositoryId":{"type":"string","description":"VCS (Version Control System) Repository ID","x-example":"appwrite"},"providerBranch":{"type":"string","description":"VCS (Version Control System) branch name","x-example":"main"},"providerRootDirectory":{"type":"string","description":"Path to function in VCS (Version Control System) repository","x-example":"functions\/helloWorld"},"providerSilentMode":{"type":"boolean","description":"Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests","x-example":false}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","live","logging","runtime","deployment","vars","events","schedule","timeout","entrypoint","commands","version","installationId","providerRepositoryId","providerBranch","providerRootDirectory","providerSilentMode"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"type":{"type":"string","description":"Type of deployment.","x-example":"vcs"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"index.js"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"waiting\", \"ready\", and \"failed\".","x-example":"ready"},"buildLogs":{"type":"string","description":"The build logs.","x-example":"Compiling source files..."},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"},"providerRepositoryName":{"type":"string","description":"The name of the vcs provider repository","x-example":"database"},"providerRepositoryOwner":{"type":"string","description":"The name of the vcs provider repository owner","x-example":"utopia"},"providerRepositoryUrl":{"type":"string","description":"The url of the vcs provider repository","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function"},"providerBranch":{"type":"string","description":"The branch of the vcs repository","x-example":"0.7.x"},"providerCommitHash":{"type":"string","description":"The commit hash of the vcs commit","x-example":"7c3f25d"},"providerCommitAuthorUrl":{"type":"string","description":"The url of vcs commit author","x-example":"https:\/\/github.com\/vermakhushboo"},"providerCommitAuthor":{"type":"string","description":"The name of vcs commit author","x-example":"Khushboo Verma"},"providerCommitMessage":{"type":"string","description":"The commit message","x-example":"Update index.js"},"providerCommitUrl":{"type":"string","description":"The url of the vcs commit","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function\/commit\/60c0416257a9cbcdd96b2d370c38d8f8d150ccfb"},"providerBranchUrl":{"type":"string","description":"The branch of the vcs repository","x-example":"https:\/\/github.com\/vermakhushboo\/appwrite\/tree\/0.7.x"}},"required":["$id","$createdAt","$updatedAt","type","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildLogs","buildTime","providerRepositoryName","providerRepositoryOwner","providerRepositoryUrl","providerBranch","providerCommitHash","providerCommitAuthorUrl","providerCommitAuthor","providerCommitMessage","providerCommitUrl","providerBranchUrl"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"resourceType":{"type":"string","description":"Service to which the variable belongs. Possible values are \"project\", \"function\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource to which the variable belongs. If resourceType is \"project\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"}},"required":["$id","$createdAt","$updatedAt","key","value","resourceType","resourceId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json index 5ac56609fd..f3e8254dde 100644 --- a/app/config/specs/open-api3-latest-client.json +++ b/app/config/specs/open-api3-latest-client.json @@ -1 +1 @@ -{"openapi":"3.0.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/jwt"}}}}},"x-appwrite":{"method":"createJWT","weight":18,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createAnonymousSession","weight":17,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createMagicURLSession","weight":13,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}}}},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateMagicURLSession","weight":14,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"File"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"schema":{"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[]},"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneSession","weight":15,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"}},"required":["userId","phone"]}}}}},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updatePhoneSession","weight":16,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/console\/assistant":{"post":{"summary":"Ask Query","operationId":"assistantChat","tags":["assistant"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"chat","weight":275,"cookies":false,"type":"","demo":"assistant\/chat.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/assistant\/chat.md","rate-limit":15,"rate-time":3600,"rate-key":"userId:{userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"query":{"type":"string","description":"Query","x-example":"[QUERY]"}},"required":["query"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","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](\/docs\/permissions).","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"openapi":"3.0.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":21,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":28,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","weight":13,"cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":14,"cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/jwt"}}}}},"x-appwrite":{"method":"createJWT","weight":20,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":24,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":26,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":27,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":29,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":22,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":30,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":35,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":36,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":23,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":34,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createAnonymousSession","weight":19,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createMagicURLSession","weight":15,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}}}},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateMagicURLSession","weight":16,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"File"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"schema":{"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[]},"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneSession","weight":17,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"}},"required":["userId","phone"]}}}}},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updatePhoneSession","weight":18,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":25,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":33,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":32,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":31,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":39,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":40,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":47,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":46,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":91,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":90,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":92,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":94,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":95,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":253,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":252,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","x-example":"[BODY]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false},"path":{"type":"string","description":"HTTP path of execution. Path can include query params. Default value is \/","x-example":"[PATH]"},"method":{"type":"string","description":"HTTP method of execution. Default value is GET.","x-example":"GET","enum":["GET","POST","PUT","PATCH","DELETE","OPTIONS"],"x-enum-name":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","x-example":"{}"}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":254,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":293,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":292,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":99,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":100,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":104,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":102,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":103,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":105,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":106,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":173,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":172,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":174,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":178,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":179,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":176,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":175,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":177,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":183,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":182,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":184,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":186,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":188,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":190,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":189,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":191,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembership","weight":192,"cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":194,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":193,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":185,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":187,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"$ref":"#\/components\/schemas\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 8bb7e8de50..fd8212e58e 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -1 +1 @@ -{"openapi":"3.0.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/invite":{"post":{"summary":"Create account using an invite code","operationId":"accountCreateWithInviteCode","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"Account","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/account"}}}}},"x-appwrite":{"method":"createWithInviteCode","weight":6,"cookies":false,"type":"","demo":"account\/create-with-invite-code.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose your own unique ID or pass the string `ID.unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"},"code":{"type":"string","description":"An invite code to restrict user signups on the Appwrite console. Users with an invite code will be able to create accounts irrespective of email and IP whitelists.","x-example":"[CODE]"}},"required":["userId","email","password"]}}}}}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/jwt"}}}}},"x-appwrite":{"method":"createJWT","weight":18,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createAnonymousSession","weight":17,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createMagicURLSession","weight":13,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}}}},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateMagicURLSession","weight":14,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"File"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"schema":{"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[]},"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneSession","weight":15,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"}},"required":["userId","phone"]}}}}},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updatePhoneSession","weight":16,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/console\/assistant":{"post":{"summary":"Ask Query","operationId":"assistantChat","tags":["assistant"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"chat","weight":275,"cookies":false,"type":"","demo":"assistant\/chat.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/assistant\/chat.md","rate-limit":15,"rate-time":3600,"rate-key":"userId:{userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"query":{"type":"string","description":"Query","x-example":"[QUERY]"}},"required":["query"]}}}}}},"\/console\/variables":{"get":{"summary":"Get Variables","operationId":"consoleVariables","tags":["console"],"description":"Get all Environment Variables that are relevant for the console.","responses":{"200":{"description":"Console Variables","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/consoleVariables"}}}}},"x-appwrite":{"method":"variables","weight":274,"cookies":false,"type":"","demo":"console\/variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/console\/variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/databaseList"}}}}},"x-appwrite":{"method":"list","weight":50,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"create","weight":49,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","x-example":false}},"required":["databaseId","name"]}}}}}},"\/databases\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabases","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageDatabases"}}}}},"x-appwrite":{"method":"getUsage","weight":94,"cookies":false,"type":"","demo":"databases\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"`Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"get","weight":51,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"update","weight":53,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Database","operationId":"databasesDelete","tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":54,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collectionList"}}}}},"x-appwrite":{"method":"listCollections","weight":56,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"createCollection","weight":55,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","x-example":false}},"required":["collectionId","name"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"getCollection","weight":57,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"updateCollection","weight":59,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":60,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeList"}}}}},"x-appwrite":{"method":"listAttributes","weight":71,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"createBooleanAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"createEmailAttribute","weight":62,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"updateEmailAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"createEnumAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","elements","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"updateEnumAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"createFloatAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"updateFloatAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"createIntegerAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"createIpAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"updateIpAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","x-example":false},"key":{"type":"string","description":"Attribute Key.","x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","x-example":null},"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"createStringAttribute","weight":61,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","x-example":1},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","size","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"updateStringAttribute","weight":73,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"createUrlAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"updateUrlAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","content":{"application\/json":{"schema":{"oneOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]}}}}},"x-appwrite":{"method":"getAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/logs":{"get":{"summary":"List Document Logs","operationId":"databasesListDocumentLogs","tags":["databases"],"description":"Get the document activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listDocumentLogs","weight":91,"cookies":false,"type":"","demo":"databases\/list-document-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/indexList"}}}}},"x-appwrite":{"method":"listIndexes","weight":85,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","tags":["databases"],"description":"","responses":{"202":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"createIndex","weight":84,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":null},"type":{"type":"string","description":"Index type.","x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","tags":["databases"],"description":"","responses":{"200":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"getIndex","weight":86,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":87,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/logs":{"get":{"summary":"List Collection Logs","operationId":"databasesListCollectionLogs","tags":["databases"],"description":"Get the collection activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listCollectionLogs","weight":58,"cookies":false,"type":"","demo":"databases\/list-collection-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/usage":{"get":{"summary":"Get usage stats for a collection","operationId":"databasesGetCollectionUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageCollection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageCollection"}}}}},"x-appwrite":{"method":"getCollectionUsage","weight":96,"cookies":false,"type":"","demo":"databases\/get-collection-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/logs":{"get":{"summary":"List Database Logs","operationId":"databasesListLogs","tags":["databases"],"description":"Get the database activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":52,"cookies":false,"type":"","demo":"databases\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetDatabaseUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabase","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageDatabase"}}}}},"x-appwrite":{"method":"getDatabaseUsage","weight":95,"cookies":false,"type":"","demo":"databases\/get-database-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"range","description":"`Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/functionList"}}}}},"x-appwrite":{"method":"list","weight":222,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"create","weight":221,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","php-8.0","php-8.1","ruby-3.0","ruby-3.1","python-3.8","python-3.9","python-3.10","dart-2.15","dart-2.16","dart-2.17","dotnet-3.1","dotnet-6.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","kotlin-1.6","cpp-17.0"],"x-enum-name":null,"x-enum-keys":[]},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","x-example":false}},"required":["functionId","name","runtime"]}}}}}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/runtimeList"}}}}},"x-appwrite":{"method":"listRuntimes","weight":223,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/usage":{"get":{"summary":"Get Functions Usage","operationId":"functionsGetUsage","tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageFunctions"}}}}},"x-appwrite":{"method":"getUsage","weight":226,"cookies":false,"type":"","demo":"functions\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"get","weight":224,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"update","weight":227,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Function","operationId":"functionsDelete","tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":229,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deploymentList"}}}}},"x-appwrite":{"method":"listDeployments","weight":231,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: entrypoint, size, buildId, activate","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","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](\/docs\/functions).\n\nUse the \"command\" param to set the entry point used to execute your code.","responses":{"202":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"createDeployment","weight":230,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"entrypoint":{"type":"string","description":"Entrypoint File.","x-example":"[ENTRYPOINT]"},"code":{"type":"string","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","x-example":null},"activate":{"type":"boolean","description":"Automatically activate the deployment when it is finished building.","x-example":false}},"required":["entrypoint","code","activate"]}}}}}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"getDeployment","weight":232,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"updateDeployment","weight":228,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":233,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","tags":["functions"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":234,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"schema":{"type":"string","x-example":"[BUILD_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/usage":{"get":{"summary":"Get Function Usage","operationId":"functionsGetFunctionUsage","tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageFunctions"}}}}},"x-appwrite":{"method":"getFunctionUsage","weight":225,"cookies":false,"type":"","demo":"functions\/get-function-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","weight":239,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","tags":["functions"],"description":"Create a new function variable. These variables can be accessed within function in the `env` object under the request variable.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","weight":238,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","weight":240,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","weight":241,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":242,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"get","weight":105,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthAntivirus"}}}}},"x-appwrite":{"method":"getAntivirus","weight":117,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getCache","weight":108,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getDB","weight":107,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getPubSub","weight":110,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getQueue","weight":109,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueCertificates","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueFunctions","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueLogs","weight":113,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueWebhooks","weight":112,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getStorageLocal","weight":116,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthTime"}}}}},"x-appwrite":{"method":"getTime","weight":111,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/project\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectGetUsage","tags":["project"],"description":"","responses":{"200":{"description":"UsageProject","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageProject"}}}}},"x-appwrite":{"method":"getUsage","weight":163,"cookies":false,"type":"","demo":"project\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/projects":{"get":{"summary":"List Projects","operationId":"projectsList","tags":["projects"],"description":"","responses":{"200":{"description":"Projects List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/projectList"}}}}},"x-appwrite":{"method":"list","weight":120,"cookies":false,"type":"","demo":"projects\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Project","operationId":"projectsCreate","tags":["projects"],"description":"","responses":{"201":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"create","weight":119,"cookies":false,"type":"","demo":"projects\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.","x-example":null},"name":{"type":"string","description":"Project name. Max length: 128 chars.","x-example":"[NAME]"},"teamId":{"type":"string","description":"Team unique ID.","x-example":"[TEAM_ID]"},"region":{"type":"string","description":"Project Region.","x-example":"default","enum":["default"],"x-enum-name":null,"x-enum-keys":[]},"description":{"type":"string","description":"Project description. Max length: 256 chars.","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal Name. Max length: 256 chars.","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal Country. Max length: 256 chars.","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal State. Max length: 256 chars.","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal City. Max length: 256 chars.","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal Address. Max length: 256 chars.","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal Tax ID. Max length: 256 chars.","x-example":"[LEGAL_TAX_ID]"}},"required":["projectId","name","teamId"]}}}}}},"\/projects\/{projectId}":{"get":{"summary":"Get Project","operationId":"projectsGet","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"get","weight":121,"cookies":false,"type":"","demo":"projects\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"patch":{"summary":"Update Project","operationId":"projectsUpdate","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"update","weight":122,"cookies":false,"type":"","demo":"projects\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name. Max length: 128 chars.","x-example":"[NAME]"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal name. Max length: 256 chars.","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal country. Max length: 256 chars.","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal state. Max length: 256 chars.","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal city. Max length: 256 chars.","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal address. Max length: 256 chars.","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal tax ID. Max length: 256 chars.","x-example":"[LEGAL_TAX_ID]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Project","operationId":"projectsDelete","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":134,"cookies":false,"type":"","demo":"projects\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/auth\/duration":{"patch":{"summary":"Update Project Authentication Duration","operationId":"projectsUpdateAuthDuration","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthDuration","weight":128,"cookies":false,"type":"","demo":"projects\/update-auth-duration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"duration":{"type":"integer","description":"Project session length in seconds. Max length: 31536000 seconds.","x-example":0}},"required":["duration"]}}}}}},"\/projects\/{projectId}\/auth\/limit":{"patch":{"summary":"Update Project users limit","operationId":"projectsUpdateAuthLimit","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthLimit","weight":127,"cookies":false,"type":"","demo":"projects\/update-auth-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Use 0 for unlimited.","x-example":0}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/max-sessions":{"patch":{"summary":"Update Project user sessions limit","operationId":"projectsUpdateAuthSessionsLimit","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthSessionsLimit","weight":133,"cookies":false,"type":"","demo":"projects\/update-auth-sessions-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10","x-example":1}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/password-dictionary":{"patch":{"summary":"Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password","operationId":"projectsUpdateAuthPasswordDictionary","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthPasswordDictionary","weight":131,"cookies":false,"type":"","demo":"projects\/update-auth-password-dictionary.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to enable checking user's password against most commonly used passwords. Default is false.","x-example":false}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/auth\/password-history":{"patch":{"summary":"Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.","operationId":"projectsUpdateAuthPasswordHistory","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthPasswordHistory","weight":130,"cookies":false,"type":"","demo":"projects\/update-auth-password-history.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0","x-example":0}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/personal-data":{"patch":{"summary":"Enable or disable checking user passwords for similarity with their personal data.","operationId":"projectsUpdatePersonalDataCheck","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updatePersonalDataCheck","weight":132,"cookies":false,"type":"","demo":"projects\/update-personal-data-check.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to check a password for similarity with personal data. Default is false.","x-example":false}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/auth\/{method}":{"patch":{"summary":"Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.","operationId":"projectsUpdateAuthStatus","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthStatus","weight":129,"cookies":false,"type":"","demo":"projects\/update-auth-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"method","description":"Auth Method. Possible values: email-password,magic-url,anonymous,invites,jwt,phone","required":true,"schema":{"type":"string","x-example":"email-password","enum":["email-password","magic-url","anonymous","invites","jwt","phone"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Set the status of this auth method.","x-example":false}},"required":["status"]}}}}}},"\/projects\/{projectId}\/domains":{"get":{"summary":"List Domains","operationId":"projectsListDomains","tags":["projects"],"description":"","responses":{"200":{"description":"Domains List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/domainList"}}}}},"x-appwrite":{"method":"listDomains","weight":152,"cookies":false,"type":"","demo":"projects\/list-domains.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Domain","operationId":"projectsCreateDomain","tags":["projects"],"description":"","responses":{"201":{"description":"Domain","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/domain"}}}}},"x-appwrite":{"method":"createDomain","weight":151,"cookies":false,"type":"","demo":"projects\/create-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain name.","x-example":null}},"required":["domain"]}}}}}},"\/projects\/{projectId}\/domains\/{domainId}":{"get":{"summary":"Get Domain","operationId":"projectsGetDomain","tags":["projects"],"description":"","responses":{"200":{"description":"Domain","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/domain"}}}}},"x-appwrite":{"method":"getDomain","weight":153,"cookies":false,"type":"","demo":"projects\/get-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"schema":{"type":"string","x-example":"[DOMAIN_ID]"},"in":"path"}]},"delete":{"summary":"Delete Domain","operationId":"projectsDeleteDomain","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDomain","weight":155,"cookies":false,"type":"","demo":"projects\/delete-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"schema":{"type":"string","x-example":"[DOMAIN_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/domains\/{domainId}\/verification":{"patch":{"summary":"Update Domain Verification Status","operationId":"projectsUpdateDomainVerification","tags":["projects"],"description":"","responses":{"200":{"description":"Domain","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/domain"}}}}},"x-appwrite":{"method":"updateDomainVerification","weight":154,"cookies":false,"type":"","demo":"projects\/update-domain-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"schema":{"type":"string","x-example":"[DOMAIN_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/keys":{"get":{"summary":"List Keys","operationId":"projectsListKeys","tags":["projects"],"description":"","responses":{"200":{"description":"API Keys List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/keyList"}}}}},"x-appwrite":{"method":"listKeys","weight":142,"cookies":false,"type":"","demo":"projects\/list-keys.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Key","operationId":"projectsCreateKey","tags":["projects"],"description":"","responses":{"201":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"createKey","weight":141,"cookies":false,"type":"","demo":"projects\/create-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 scopes are allowed.","x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","x-example":null}},"required":["name","scopes"]}}}}}},"\/projects\/{projectId}\/keys\/{keyId}":{"get":{"summary":"Get Key","operationId":"projectsGetKey","tags":["projects"],"description":"","responses":{"200":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"getKey","weight":143,"cookies":false,"type":"","demo":"projects\/get-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}]},"put":{"summary":"Update Key","operationId":"projectsUpdateKey","tags":["projects"],"description":"","responses":{"200":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"updateKey","weight":144,"cookies":false,"type":"","demo":"projects\/update-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","x-example":null}},"required":["name","scopes"]}}}}},"delete":{"summary":"Delete Key","operationId":"projectsDeleteKey","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteKey","weight":145,"cookies":false,"type":"","demo":"projects\/delete-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/oauth2":{"patch":{"summary":"Update Project OAuth2","operationId":"projectsUpdateOAuth2","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateOAuth2","weight":126,"cookies":false,"type":"","demo":"projects\/update-o-auth2.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","description":"Provider Name","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":null,"x-enum-keys":[]},"appId":{"type":"string","description":"Provider app ID. Max length: 256 chars.","x-example":"[APP_ID]"},"secret":{"type":"string","description":"Provider secret key. Max length: 512 chars.","x-example":"[SECRET]"},"enabled":{"type":"boolean","description":"Provider status. Set to 'false' to disable new session creation.","x-example":false}},"required":["provider"]}}}}}},"\/projects\/{projectId}\/platforms":{"get":{"summary":"List Platforms","operationId":"projectsListPlatforms","tags":["projects"],"description":"","responses":{"200":{"description":"Platforms List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platformList"}}}}},"x-appwrite":{"method":"listPlatforms","weight":147,"cookies":false,"type":"","demo":"projects\/list-platforms.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Platform","operationId":"projectsCreatePlatform","tags":["projects"],"description":"","responses":{"201":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"createPlatform","weight":146,"cookies":false,"type":"","demo":"projects\/create-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"Platform type.","x-example":"web","enum":["web","flutter-web","flutter-ios","flutter-android","flutter-linux","flutter-macos","flutter-windows","apple-ios","apple-macos","apple-watchos","apple-tvos","android","unity"],"x-enum-name":"PlatformType","x-enum-keys":[]},"name":{"type":"string","description":"Platform name. Max length: 128 chars.","x-example":"[NAME]"},"key":{"type":"string","description":"Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client hostname. Max length: 256 chars.","x-example":null}},"required":["type","name"]}}}}}},"\/projects\/{projectId}\/platforms\/{platformId}":{"get":{"summary":"Get Platform","operationId":"projectsGetPlatform","tags":["projects"],"description":"","responses":{"200":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"getPlatform","weight":148,"cookies":false,"type":"","demo":"projects\/get-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}]},"put":{"summary":"Update Platform","operationId":"projectsUpdatePlatform","tags":["projects"],"description":"","responses":{"200":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"updatePlatform","weight":149,"cookies":false,"type":"","demo":"projects\/update-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Platform name. Max length: 128 chars.","x-example":"[NAME]"},"key":{"type":"string","description":"Package name for android or bundle ID for iOS. Max length: 256 chars.","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client URL. Max length: 256 chars.","x-example":null}},"required":["name"]}}}}},"delete":{"summary":"Delete Platform","operationId":"projectsDeletePlatform","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deletePlatform","weight":150,"cookies":false,"type":"","demo":"projects\/delete-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/service":{"patch":{"summary":"Update service status","operationId":"projectsUpdateServiceStatus","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateServiceStatus","weight":124,"cookies":false,"type":"","demo":"projects\/update-service-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"service":{"type":"string","description":"Service name.","x-example":"account","enum":["account","avatars","databases","locale","health","storage","teams","users","functions","graphql"],"x-enum-name":null,"x-enum-keys":[]},"status":{"type":"boolean","description":"Service status.","x-example":false}},"required":["service","status"]}}}}}},"\/projects\/{projectId}\/service\/all":{"patch":{"summary":"Update all service status","operationId":"projectsUpdateServiceStatusAll","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateServiceStatusAll","weight":125,"cookies":false,"type":"","demo":"projects\/update-service-status-all.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Service status.","x-example":false}},"required":["status"]}}}}}},"\/projects\/{projectId}\/smtp":{"patch":{"summary":"Update SMTP configuration","operationId":"projectsUpdateSmtpConfiguration","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateSmtpConfiguration","weight":156,"cookies":false,"type":"","demo":"projects\/update-smtp-configuration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable custom SMTP service","x-example":false},"sender":{"type":"string","description":"SMTP sender email","x-example":"email@example.com"},"host":{"type":"string","description":"SMTP server host name","x-example":null},"port":{"type":"integer","description":"SMTP server port","x-example":null},"username":{"type":"string","description":"SMTP server username","x-example":"[USERNAME]"},"password":{"type":"string","description":"SMTP server password","x-example":"[PASSWORD]"},"secure":{"type":"string","description":"Does SMTP server use secure connection","x-example":"tls","enum":["tls"],"x-enum-name":null,"x-enum-keys":[]}},"required":["enabled","sender","host","port","username","password"]}}}}}},"\/projects\/{projectId}\/team":{"patch":{"summary":"Update Project Team","operationId":"projectsUpdateTeam","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateTeam","weight":123,"cookies":false,"type":"","demo":"projects\/update-team.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID of the team to transfer project to.","x-example":"[TEAM_ID]"}},"required":["teamId"]}}}}}},"\/projects\/{projectId}\/templates\/email\/{type}\/{locale}":{"get":{"summary":"Get custom email template","operationId":"projectsGetEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/emailTemplate"}}}}},"x-appwrite":{"method":"getEmailTemplate","weight":158,"cookies":false,"type":"","demo":"projects\/get-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]},"patch":{"summary":"Update custom email templates","operationId":"projectsUpdateEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateEmailTemplate","weight":160,"cookies":false,"type":"","demo":"projects\/update-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"senderName":{"type":"string","description":"Name of the email sender","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"email@example.com"},"subject":{"type":"string","description":"Email Subject","x-example":"[SUBJECT]"},"message":{"type":"string","description":"Template message","x-example":"[MESSAGE]"},"replyTo":{"type":"string","description":"Reply to email","x-example":"email@example.com"}},"required":["senderName","senderEmail","subject","message"]}}}}},"delete":{"summary":"Reset custom email template","operationId":"projectsDeleteEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/emailTemplate"}}}}},"x-appwrite":{"method":"deleteEmailTemplate","weight":162,"cookies":false,"type":"","demo":"projects\/delete-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]}},"\/projects\/{projectId}\/templates\/sms\/{type}\/{locale}":{"get":{"summary":"Get custom SMS template","operationId":"projectsGetSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"getSmsTemplate","weight":157,"cookies":false,"type":"","demo":"projects\/get-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]},"patch":{"summary":"Update custom SMS template","operationId":"projectsUpdateSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"updateSmsTemplate","weight":159,"cookies":false,"type":"","demo":"projects\/update-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Template message","x-example":"[MESSAGE]"}},"required":["message"]}}}}},"delete":{"summary":"Reset custom SMS template","operationId":"projectsDeleteSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"deleteSmsTemplate","weight":161,"cookies":false,"type":"","demo":"projects\/delete-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]}},"\/projects\/{projectId}\/webhooks":{"get":{"summary":"List Webhooks","operationId":"projectsListWebhooks","tags":["projects"],"description":"","responses":{"200":{"description":"Webhooks List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhookList"}}}}},"x-appwrite":{"method":"listWebhooks","weight":136,"cookies":false,"type":"","demo":"projects\/list-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Webhook","operationId":"projectsCreateWebhook","tags":["projects"],"description":"","responses":{"201":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"createWebhook","weight":135,"cookies":false,"type":"","demo":"projects\/create-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}}}}},"\/projects\/{projectId}\/webhooks\/{webhookId}":{"get":{"summary":"Get Webhook","operationId":"projectsGetWebhook","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"getWebhook","weight":137,"cookies":false,"type":"","demo":"projects\/get-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]},"put":{"summary":"Update Webhook","operationId":"projectsUpdateWebhook","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"updateWebhook","weight":138,"cookies":false,"type":"","demo":"projects\/update-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}}}},"delete":{"summary":"Delete Webhook","operationId":"projectsDeleteWebhook","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteWebhook","weight":140,"cookies":false,"type":"","demo":"projects\/delete-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}\/signature":{"patch":{"summary":"Update Webhook Signature Key","operationId":"projectsUpdateWebhookSignature","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"updateWebhookSignature","weight":139,"cookies":false,"type":"","demo":"projects\/update-webhook-signature.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucketList"}}}}},"x-appwrite":{"method":"listBuckets","weight":165,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"createBucket","weight":164,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["bucketId","name"]}}}}}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"getBucket","weight":166,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"updateBucket","weight":167,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":168,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/usage":{"get":{"summary":"Get usage stats for storage","operationId":"storageGetUsage","tags":["storage"],"description":"","responses":{"200":{"description":"StorageUsage","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageStorage"}}}}},"x-appwrite":{"method":"getUsage","weight":177,"cookies":false,"type":"","demo":"storage\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/storage\/{bucketId}\/usage":{"get":{"summary":"Get usage stats for storage bucket","operationId":"storageGetBucketUsage","tags":["storage"],"description":"","responses":{"200":{"description":"UsageBuckets","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageBuckets"}}}}},"x-appwrite":{"method":"getBucketUsage","weight":178,"cookies":false,"type":"","demo":"storage\/get-bucket-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"bucketId","description":"Bucket ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/logs":{"get":{"summary":"List Team Logs","operationId":"teamsListLogs","tags":["teams"],"description":"Get the team activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":192,"cookies":false,"type":"","demo":"teams\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","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](\/docs\/permissions).","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/userList"}}}}},"x-appwrite":{"method":"list","weight":201,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":193,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId"]}}}}}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createArgon2User","weight":196,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createBcryptUser","weight":194,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createMD5User","weight":195,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createPHPassUser","weight":198,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptUser","weight":199,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}}}}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":200,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}}}}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createSHAUser","weight":197,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/usage":{"get":{"summary":"Get usage stats for the users API","operationId":"usersGetUsage","tags":["users"],"description":"","responses":{"200":{"description":"UsageUsers","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageUsers"}}}}},"x-appwrite":{"method":"getUsage","weight":220,"cookies":false,"type":"","demo":"users\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":202,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":219,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":213,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"}},"required":["email"]}}}}}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateLabels","weight":208,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","x-example":null,"items":{"type":"string"}}},"required":["labels"]}}}}}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":206,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":205,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":211,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":212,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null}},"required":["password"]}}}}}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":214,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","x-example":"+12065550100"}},"required":["number"]}}}}}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":203,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":216,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":204,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":218,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":217,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":207,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","x-example":false}},"required":["status"]}}}}}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmailVerification","weight":215,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","x-example":false}},"required":["emailVerification"]}}}}}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":210,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","x-example":false}},"required":["phoneVerification"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"$ref":"#\/components\/schemas\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"$ref":"#\/components\/schemas\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"$ref":"#\/components\/schemas\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"$ref":"#\/components\/schemas\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"$ref":"#\/components\/schemas\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"$ref":"#\/components\/schemas\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"$ref":"#\/components\/schemas\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"projectList":{"description":"Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"$ref":"#\/components\/schemas\/project"},"x-example":""}},"required":["total","projects"]},"webhookList":{"description":"Webhooks List","type":"object","properties":{"total":{"type":"integer","description":"Total number of webhooks documents that matched your query.","x-example":5,"format":"int32"},"webhooks":{"type":"array","description":"List of webhooks.","items":{"$ref":"#\/components\/schemas\/webhook"},"x-example":""}},"required":["total","webhooks"]},"keyList":{"description":"API Keys List","type":"object","properties":{"total":{"type":"integer","description":"Total number of keys documents that matched your query.","x-example":5,"format":"int32"},"keys":{"type":"array","description":"List of keys.","items":{"$ref":"#\/components\/schemas\/key"},"x-example":""}},"required":["total","keys"]},"platformList":{"description":"Platforms List","type":"object","properties":{"total":{"type":"integer","description":"Total number of platforms documents that matched your query.","x-example":5,"format":"int32"},"platforms":{"type":"array","description":"List of platforms.","items":{"$ref":"#\/components\/schemas\/platform"},"x-example":""}},"required":["total","platforms"]},"domainList":{"description":"Domains List","type":"object","properties":{"total":{"type":"integer","description":"Total number of domains documents that matched your query.","x-example":5,"format":"int32"},"domains":{"type":"array","description":"List of domains.","items":{"$ref":"#\/components\/schemas\/domain"},"x-example":""}},"required":["total","domains"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"Database enabled.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"account":{"description":"Account","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":15,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","runtime","deployment","vars","events","schedule","timeout"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"enabled"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"pending\", \"ready\", and \"failed\".","x-example":"ready"},"buildStdout":{"type":"string","description":"The build stdout.","x-example":"enabled"},"buildStderr":{"type":"string","description":"The build stderr.","x-example":"enabled"},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildStdout","buildStderr","buildTime"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"project":{"description":"Project","type":"object","properties":{"$id":{"type":"string","description":"Project ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Project creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Project update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Project name.","x-example":"New Project"},"description":{"type":"string","description":"Project description.","x-example":"This is a new project."},"teamId":{"type":"string","description":"Project team ID.","x-example":"1592981250"},"logo":{"type":"string","description":"Project logo file ID.","x-example":"5f5c451b403cb"},"url":{"type":"string","description":"Project website URL.","x-example":"5f5c451b403cb"},"legalName":{"type":"string","description":"Company legal name.","x-example":"Company LTD."},"legalCountry":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format.","x-example":"US"},"legalState":{"type":"string","description":"State name.","x-example":"New York"},"legalCity":{"type":"string","description":"City name.","x-example":"New York City."},"legalAddress":{"type":"string","description":"Company Address.","x-example":"620 Eighth Avenue, New York, NY 10018"},"legalTaxId":{"type":"string","description":"Company Tax ID.","x-example":"131102020"},"authDuration":{"type":"integer","description":"Session duration in seconds.","x-example":60,"format":"int32"},"authLimit":{"type":"integer","description":"Max users allowed. 0 is unlimited.","x-example":100,"format":"int32"},"authSessionsLimit":{"type":"integer","description":"Max sessions allowed per user. 100 maximum.","x-example":10,"format":"int32"},"authPasswordHistory":{"type":"integer","description":"Max allowed passwords in the history list per user. Max passwords limit allowed in history is 20. Use 0 for disabling password history.","x-example":5,"format":"int32"},"authPasswordDictionary":{"type":"boolean","description":"Whether or not to check user's password against most commonly used passwords.","x-example":true},"authPersonalDataCheck":{"type":"boolean","description":"Whether or not to check the user password for similarity with their personal data.","x-example":true},"providers":{"type":"array","description":"List of Providers.","items":{"$ref":"#\/components\/schemas\/provider"},"x-example":[{}]},"platforms":{"type":"array","description":"List of Platforms.","items":{"$ref":"#\/components\/schemas\/platform"},"x-example":{}},"webhooks":{"type":"array","description":"List of Webhooks.","items":{"$ref":"#\/components\/schemas\/webhook"},"x-example":{}},"keys":{"type":"array","description":"List of API Keys.","items":{"$ref":"#\/components\/schemas\/key"},"x-example":{}},"domains":{"type":"array","description":"List of Domains.","items":{"$ref":"#\/components\/schemas\/domain"},"x-example":{}},"smtpEnabled":{"type":"boolean","description":"Status for custom SMTP","x-example":false},"smtpSender":{"type":"string","description":"SMTP sender email","x-example":"john@appwrite.io"},"smtpHost":{"type":"string","description":"SMTP server host name","x-example":"mail.appwrite.io"},"smtpPort":{"type":"integer","description":"SMTP server port","x-example":25,"format":"int32"},"smtpUsername":{"type":"string","description":"SMTP server username","x-example":"emailuser"},"smtpPassword":{"type":"string","description":"SMTP server password","x-example":"securepassword"},"smtpSecure":{"type":"string","description":"SMTP server secure protocol","x-example":"tls"},"authEmailPassword":{"type":"boolean","description":"Email\/Password auth method status","x-example":true},"authUsersAuthMagicURL":{"type":"boolean","description":"Magic URL auth method status","x-example":true},"authAnonymous":{"type":"boolean","description":"Anonymous auth method status","x-example":true},"authInvites":{"type":"boolean","description":"Invites auth method status","x-example":true},"authJWT":{"type":"boolean","description":"JWT auth method status","x-example":true},"authPhone":{"type":"boolean","description":"Phone auth method status","x-example":true},"serviceStatusForAccount":{"type":"boolean","description":"Account service status","x-example":true},"serviceStatusForAvatars":{"type":"boolean","description":"Avatars service status","x-example":true},"serviceStatusForDatabases":{"type":"boolean","description":"Databases service status","x-example":true},"serviceStatusForLocale":{"type":"boolean","description":"Locale service status","x-example":true},"serviceStatusForHealth":{"type":"boolean","description":"Health service status","x-example":true},"serviceStatusForStorage":{"type":"boolean","description":"Storage service status","x-example":true},"serviceStatusForTeams":{"type":"boolean","description":"Teams service status","x-example":true},"serviceStatusForUsers":{"type":"boolean","description":"Users service status","x-example":true},"serviceStatusForFunctions":{"type":"boolean","description":"Functions service status","x-example":true},"serviceStatusForGraphql":{"type":"boolean","description":"GraphQL service status","x-example":true}},"required":["$id","$createdAt","$updatedAt","name","description","teamId","logo","url","legalName","legalCountry","legalState","legalCity","legalAddress","legalTaxId","authDuration","authLimit","authSessionsLimit","authPasswordHistory","authPasswordDictionary","authPersonalDataCheck","providers","platforms","webhooks","keys","domains","smtpEnabled","smtpSender","smtpHost","smtpPort","smtpUsername","smtpPassword","smtpSecure","authEmailPassword","authUsersAuthMagicURL","authAnonymous","authInvites","authJWT","authPhone","serviceStatusForAccount","serviceStatusForAvatars","serviceStatusForDatabases","serviceStatusForLocale","serviceStatusForHealth","serviceStatusForStorage","serviceStatusForTeams","serviceStatusForUsers","serviceStatusForFunctions","serviceStatusForGraphql"]},"webhook":{"description":"Webhook","type":"object","properties":{"$id":{"type":"string","description":"Webhook ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Webhook creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Webhook update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Webhook name.","x-example":"My Webhook"},"url":{"type":"string","description":"Webhook URL endpoint.","x-example":"https:\/\/example.com\/webhook"},"events":{"type":"array","description":"Webhook trigger events.","items":{"type":"string"},"x-example":"database.collections.update"},"security":{"type":"boolean","description":"Indicated if SSL \/ TLS Certificate verification is enabled.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"},"signatureKey":{"type":"string","description":"Signature key which can be used to validated incoming","x-example":"ad3d581ca230e2b7059c545e5a"}},"required":["$id","$createdAt","$updatedAt","name","url","events","security","httpUser","httpPass","signatureKey"]},"key":{"description":"Key","type":"object","properties":{"$id":{"type":"string","description":"Key ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Key creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Key update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Key name.","x-example":"My API Key"},"expire":{"type":"string","description":"Key expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"scopes":{"type":"array","description":"Allowed permission scopes.","items":{"type":"string"},"x-example":"users.read"},"secret":{"type":"string","description":"Secret key.","x-example":"919c2d18fb5d4...a2ae413da83346ad2"},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"},"sdks":{"type":"array","description":"List of SDK user agents that used this key.","items":{"type":"string"},"x-example":"appwrite:flutter"}},"required":["$id","$createdAt","$updatedAt","name","expire","scopes","secret","accessedAt","sdks"]},"domain":{"description":"Domain","type":"object","properties":{"$id":{"type":"string","description":"Domain ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Domain creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Domain update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"domain":{"type":"string","description":"Domain name.","x-example":"appwrite.company.com"},"registerable":{"type":"string","description":"Registerable domain name.","x-example":"company.com"},"tld":{"type":"string","description":"TLD name.","x-example":"com"},"verification":{"type":"boolean","description":"Verification process status.","x-example":true},"certificateId":{"type":"string","description":"Certificate ID.","x-example":"6ejea5c13377e"}},"required":["$id","$createdAt","$updatedAt","domain","registerable","tld","verification","certificateId"]},"provider":{"description":"Provider","type":"object","properties":{"key":{"type":"string","description":"Provider.","x-example":"github"},"name":{"type":"string","description":"Provider name.","x-example":"GitHub"},"appId":{"type":"string","description":"OAuth 2.0 application ID.","x-example":"259125845563242502"},"secret":{"type":"string","description":"OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.","x-example":"Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ"},"enabled":{"type":"boolean","description":"Provider is active and can be used to create session.","x-example":""}},"required":["key","name","appId","secret","enabled"]},"platform":{"description":"Platform","type":"object","properties":{"$id":{"type":"string","description":"Platform ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Platform creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Platform update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Platform name.","x-example":"My Web App"},"type":{"type":"string","description":"Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, and unity.","x-example":"web"},"key":{"type":"string","description":"Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.","x-example":"com.company.appname"},"store":{"type":"string","description":"App store or Google Play store ID.","x-example":""},"hostname":{"type":"string","description":"Web app hostname. Empty string for other platforms.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"}},"required":["$id","$createdAt","$updatedAt","name","type","key","store","hostname","httpUser","httpPass"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"}},"required":["$id","$createdAt","$updatedAt","key","value","functionId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"metric":{"description":"Metric","type":"object","properties":{"value":{"type":"integer","description":"The value of this metric at the timestamp.","x-example":1,"format":"int32"},"date":{"type":"string","description":"The date at which this metric was aggregated in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["value","date"]},"usageDatabases":{"description":"UsageDatabases","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"databasesTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsTotal":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","databasesTotal","collectionsTotal","documentsTotal"]},"usageDatabase":{"description":"UsageDatabase","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"collectionsTotal":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","collectionsTotal","documentsTotal"]},"usageCollection":{"description":"UsageCollection","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","documentsTotal"]},"usageUsers":{"description":"UsageUsers","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"usersTotal":{"type":"array","description":"Aggregated stats for total number of users.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"sessionsTotal":{"type":"array","description":"Aggregated stats for sessions created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","usersTotal","sessionsTotal"]},"usageStorage":{"description":"StorageUsage","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"bucketsTotal":{"type":"array","description":"Aggregated stats for total number of buckets.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesTotal":{"type":"array","description":"Aggregated stats for total number of files.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","bucketsTotal","filesTotal","filesStorage"]},"usageBuckets":{"description":"UsageBuckets","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"filesTotal":{"type":"array","description":"Aggregated stats for total number of files in this bucket.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for total storage of files in this bucket.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","filesTotal","filesStorage"]},"usageFunctions":{"description":"UsageFunctions","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"functionsTotal":{"type":"array","description":"Aggregated stats for number of functions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"deploymentsTotal":{"type":"array","description":"Aggregated stats for number of function deployments.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"deploymentsStorage":{"type":"array","description":"Aggregated stats for function deployments storage.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsTotal":{"type":"array","description":"Aggregated stats for number of function builds.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsStorage":{"type":"array","description":"Aggregated stats for builds storage.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsTime":{"type":"array","description":"Aggregated stats for function build compute.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsTotal":{"type":"array","description":"Aggregated stats for number of function executions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsTime":{"type":"array","description":"Aggregated stats for function execution compute.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","functionsTotal","deploymentsTotal","deploymentsStorage","buildsTotal","buildsStorage","buildsTime","executionsTotal","executionsTime"]},"usageProject":{"description":"UsageProject","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"requestsTotal":{"type":"array","description":"Aggregated stats for number of requests.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"network":{"type":"array","description":"Aggregated stats for consumed bandwidth.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsTotal":{"type":"array","description":"Aggregated stats for function executions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesTotal":{"type":"array","description":"Aggregated stats for number of databases.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersTotal":{"type":"array","description":"Aggregated stats for number of users.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsTotal":{"type":"array","description":"Aggregated stats for number of buckets.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","requestsTotal","network","executionsTotal","documentsTotal","databasesTotal","usersTotal","filesStorage","bucketsTotal"]},"smsTemplate":{"description":"SmsTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."}},"required":["type","locale","message"]},"emailTemplate":{"description":"EmailTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."},"senderName":{"type":"string","description":"Name of the sender","x-example":"My User"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"mail@appwrite.io"},"replyTo":{"type":"string","description":"Reply to email address","x-example":"emails@appwrite.io"},"subject":{"type":"string","description":"Email subject","x-example":"Please verify your email address"}},"required":["type","locale","message","senderName","senderEmail","replyTo","subject"]},"consoleVariables":{"description":"Console Variables","type":"object","properties":{"_APP_DOMAIN_TARGET":{"type":"string","description":"CNAME target for your Appwrite custom domains.","x-example":"appwrite.io"},"_APP_STORAGE_LIMIT":{"type":"integer","description":"Maximum file size allowed for file upload in bytes.","x-example":"30000000","format":"int32"},"_APP_FUNCTIONS_SIZE_LIMIT":{"type":"integer","description":"Maximum file size allowed for deployment in bytes.","x-example":"30000000","format":"int32"},"_APP_USAGE_STATS":{"type":"string","description":"Defines if usage stats are enabled. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'.","x-example":"enabled"}},"required":["_APP_DOMAIN_TARGET","_APP_STORAGE_LIMIT","_APP_FUNCTIONS_SIZE_LIMIT","_APP_USAGE_STATS"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}},"Mode":{"type":"apiKey","name":"X-Appwrite-Mode","description":"","in":"header","x-appwrite":{"demo":""}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"openapi":"3.0.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/jwt"}}}}},"x-appwrite":{"method":"createJWT","cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createAnonymousSession","cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"createEmailSession","cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createMagicURLSession","cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}}}},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateMagicURLSession","cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"File"}},"x-appwrite":{"method":"createOAuth2Session","cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"schema":{"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[]},"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's 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.","required":false,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com","default":""},"in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneSession","cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"}},"required":["userId","phone"]}}}}},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updatePhoneSession","cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/console\/assistant":{"post":{"summary":"Ask Query","operationId":"assistantChat","tags":["assistant"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"chat","cookies":false,"type":"","demo":"assistant\/chat.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/assistant\/chat.md","rate-limit":15,"rate-time":3600,"rate-key":"userId:{userId}","scope":"assistant.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","description":"Prompt. A string containing questions asked to the AI assistant.","x-example":"[PROMPT]"}},"required":["prompt"]}}}}}},"\/console\/variables":{"get":{"summary":"Get Variables","operationId":"consoleVariables","tags":["console"],"description":"Get all Environment Variables that are relevant for the console.","responses":{"200":{"description":"Console Variables","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/consoleVariables"}}}}},"x-appwrite":{"method":"variables","cookies":false,"type":"","demo":"console\/variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/console\/variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/databaseList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","x-example":false}},"required":["databaseId","name"]}}}}}},"\/databases\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabases","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageDatabases"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"databases\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"`Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Database","operationId":"databasesDelete","tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collectionList"}}}}},"x-appwrite":{"method":"listCollections","cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"createCollection","cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","x-example":false}},"required":["collectionId","name"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"getCollection","cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"updateCollection","cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeList"}}}}},"x-appwrite":{"method":"listAttributes","cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"createBooleanAttribute","cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"updateBooleanAttribute","cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"createDatetimeAttribute","cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"updateDatetimeAttribute","cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"createEmailAttribute","cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"updateEmailAttribute","cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"createEnumAttribute","cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","elements","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"updateEnumAttribute","cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"createFloatAttribute","cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"updateFloatAttribute","cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"createIntegerAttribute","cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"updateIntegerAttribute","cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"createIpAttribute","cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"updateIpAttribute","cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"createRelationshipAttribute","cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","x-example":false},"key":{"type":"string","description":"Attribute Key.","x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","x-example":null},"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"createStringAttribute","cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","x-example":1},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false},"encrypt":{"type":"boolean","description":"Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.","x-example":false}},"required":["key","size","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"updateStringAttribute","cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"createUrlAttribute","cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"updateUrlAttribute","cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","content":{"application\/json":{"schema":{"oneOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]}}}}},"x-appwrite":{"method":"getAttribute","cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"updateRelationshipAttribute","cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/logs":{"get":{"summary":"List Document Logs","operationId":"databasesListDocumentLogs","tags":["databases"],"description":"Get the document activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listDocumentLogs","cookies":false,"type":"","demo":"databases\/list-document-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/indexList"}}}}},"x-appwrite":{"method":"listIndexes","cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","tags":["databases"],"description":"","responses":{"202":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"createIndex","cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":null},"type":{"type":"string","description":"Index type.","x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","tags":["databases"],"description":"","responses":{"200":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"getIndex","cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/logs":{"get":{"summary":"List Collection Logs","operationId":"databasesListCollectionLogs","tags":["databases"],"description":"Get the collection activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listCollectionLogs","cookies":false,"type":"","demo":"databases\/list-collection-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/usage":{"get":{"summary":"Get usage stats for a collection","operationId":"databasesGetCollectionUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageCollection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageCollection"}}}}},"x-appwrite":{"method":"getCollectionUsage","cookies":false,"type":"","demo":"databases\/get-collection-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/logs":{"get":{"summary":"List Database Logs","operationId":"databasesListLogs","tags":["databases"],"description":"Get the database activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"databases\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetDatabaseUsage","tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabase","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageDatabase"}}}}},"x-appwrite":{"method":"getDatabaseUsage","cookies":false,"type":"","demo":"databases\/get-database-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"range","description":"`Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/functionList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Control System) deployment.","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function.","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function.","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","x-example":"[PROVIDER_ROOT_DIRECTORY]"},"templateRepository":{"type":"string","description":"Repository name of the template.","x-example":"[TEMPLATE_REPOSITORY]"},"templateOwner":{"type":"string","description":"The name of the owner of the template.","x-example":"[TEMPLATE_OWNER]"},"templateRootDirectory":{"type":"string","description":"Path to function code in the template repo.","x-example":"[TEMPLATE_ROOT_DIRECTORY]"},"templateBranch":{"type":"string","description":"Production branch for the repo linked to the function template.","x-example":"[TEMPLATE_BRANCH]"}},"required":["functionId","name","runtime"]}}}}}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/runtimeList"}}}}},"x-appwrite":{"method":"listRuntimes","cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/usage":{"get":{"summary":"Get Functions Usage","operationId":"functionsGetUsage","tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageFunctions"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"functions\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Controle System) deployment.","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","x-example":"[PROVIDER_ROOT_DIRECTORY]"}},"required":["name","runtime"]}}}}},"delete":{"summary":"Delete Function","operationId":"functionsDelete","tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deploymentList"}}}}},"x-appwrite":{"method":"listDeployments","cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: size, buildId, activate, entrypoint, commands","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","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](\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.","responses":{"202":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"createDeployment","cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"entrypoint":{"type":"string","description":"Entrypoint File.","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"code":{"type":"string","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","x-example":null},"activate":{"type":"boolean","description":"Automatically activate the deployment when it is finished building.","x-example":false}},"required":["code","activate"]}}}}}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"getDeployment","cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"updateDeployment","cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","tags":["functions"],"description":"Create a new build for an Appwrite Function deployment. This endpoint can be used to retry a failed build.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"schema":{"type":"string","x-example":"[BUILD_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/download":{"get":{"summary":"Download Deployment","operationId":"functionsDownloadDeployment","tags":["functions"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"downloadDeployment","cookies":false,"type":"location","demo":"functions\/download-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/download-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","x-example":"[BODY]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false},"path":{"type":"string","description":"HTTP path of execution. Path can include query params. Default value is \/","x-example":"[PATH]"},"method":{"type":"string","description":"HTTP method of execution. Default value is GET.","x-example":"GET","enum":["GET","POST","PUT","PATCH","DELETE","OPTIONS"],"x-enum-name":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","x-example":"{}"}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/usage":{"get":{"summary":"Get Function Usage","operationId":"functionsGetFunctionUsage","tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageFunctions"}}}}},"x-appwrite":{"method":"getFunctionUsage","cookies":false,"type":"","demo":"functions\/get-function-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","tags":["functions"],"description":"Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthAntivirus"}}}}},"x-appwrite":{"method":"getAntivirus","cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getCache","cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getDB","cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getPubSub","cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getQueue","cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueCertificates","cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueFunctions","cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueLogs","cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueWebhooks","cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getStorageLocal","cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthTime"}}}}},"x-appwrite":{"method":"getTime","cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/migrations":{"get":{"summary":"List Migrations","operationId":"migrationsList","tags":["migrations"],"description":"","responses":{"200":{"description":"Migrations List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"migrations\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/list-migrations.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: status, stage, source, resources, statusCounters, resourceData, errors","required":false,"schema":{"type":"string","default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]}},"\/migrations\/appwrite":{"post":{"summary":"Migrate Appwrite Data","operationId":"migrationsCreateAppwriteMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createAppwriteMigration","cookies":false,"type":"","demo":"migrations\/create-appwrite-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-appwrite.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"endpoint":{"type":"string","description":"Source's Appwrite Endpoint","x-example":"https:\/\/example.com"},"projectId":{"type":"string","description":"Source's Project ID","x-example":"[PROJECT_ID]"},"apiKey":{"type":"string","description":"Source's API Key","x-example":"[API_KEY]"}},"required":["resources","endpoint","projectId","apiKey"]}}}}}},"\/migrations\/appwrite\/report":{"get":{"summary":"Generate a report on Appwrite Data","operationId":"migrationsGetAppwriteReport","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getAppwriteReport","cookies":false,"type":"","demo":"migrations\/get-appwrite-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-appwrite-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"endpoint","description":"Source's Appwrite Endpoint","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"projectID","description":"Source's Project ID","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"query"},{"name":"key","description":"Source's API Key","required":true,"schema":{"type":"string","x-example":"[KEY]"},"in":"query"}]}},"\/migrations\/firebase":{"post":{"summary":"Migrate Firebase Data (Service Account)","operationId":"migrationsCreateFirebaseMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createFirebaseMigration","cookies":false,"type":"","demo":"migrations\/create-firebase-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"serviceAccount":{"type":"string","description":"JSON of the Firebase service account credentials","x-example":"[SERVICE_ACCOUNT]"}},"required":["resources","serviceAccount"]}}}}}},"\/migrations\/firebase\/deauthorize":{"get":{"summary":"Revoke Appwrite's authorization to access Firebase Projects","operationId":"migrationsDeleteFirebaseAuth","tags":["migrations"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"deleteFirebaseAuth","cookies":false,"type":"","demo":"migrations\/delete-firebase-auth.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/migrations\/firebase\/oauth":{"post":{"summary":"Migrate Firebase Data (OAuth)","operationId":"migrationsCreateFirebaseOAuthMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createFirebaseOAuthMigration","cookies":false,"type":"","demo":"migrations\/create-firebase-o-auth-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"projectId":{"type":"string","description":"Project ID of the Firebase Project","x-example":"[PROJECT_ID]"}},"required":["resources","projectId"]}}}}}},"\/migrations\/firebase\/projects":{"get":{"summary":"List Firebase Projects","operationId":"migrationsListFirebaseProjects","tags":["migrations"],"description":"","responses":{"200":{"description":"Migrations Firebase Projects List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/firebaseProjectList"}}}}},"x-appwrite":{"method":"listFirebaseProjects","cookies":false,"type":"","demo":"migrations\/list-firebase-projects.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/migrations\/firebase\/report":{"get":{"summary":"Generate a report on Firebase Data","operationId":"migrationsGetFirebaseReport","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getFirebaseReport","cookies":false,"type":"","demo":"migrations\/get-firebase-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"serviceAccount","description":"JSON of the Firebase service account credentials","required":true,"schema":{"type":"string","x-example":"[SERVICE_ACCOUNT]"},"in":"query"}]}},"\/migrations\/firebase\/report\/oauth":{"get":{"summary":"Generate a report on Firebase Data using OAuth","operationId":"migrationsGetFirebaseReportOAuth","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getFirebaseReportOAuth","cookies":false,"type":"","demo":"migrations\/get-firebase-report-o-auth.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"projectId","description":"Project ID","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"query"}]}},"\/migrations\/nhost":{"post":{"summary":"Migrate NHost Data","operationId":"migrationsCreateNHostMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createNHostMigration","cookies":false,"type":"","demo":"migrations\/create-n-host-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-nhost.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"subdomain":{"type":"string","description":"Source's Subdomain","x-example":"[SUBDOMAIN]"},"region":{"type":"string","description":"Source's Region","x-example":"[REGION]"},"adminSecret":{"type":"string","description":"Source's Admin Secret","x-example":"[ADMIN_SECRET]"},"database":{"type":"string","description":"Source's Database Name","x-example":"[DATABASE]"},"username":{"type":"string","description":"Source's Database Username","x-example":"[USERNAME]"},"password":{"type":"string","description":"Source's Database Password","x-example":"[PASSWORD]"},"port":{"type":"integer","description":"Source's Database Port","x-example":null}},"required":["resources","subdomain","region","adminSecret","database","username","password"]}}}}}},"\/migrations\/nhost\/report":{"get":{"summary":"Generate a report on NHost Data","operationId":"migrationsGetNHostReport","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getNHostReport","cookies":false,"type":"","demo":"migrations\/get-n-host-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-nhost-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate.","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"subdomain","description":"Source's Subdomain.","required":true,"schema":{"type":"string","x-example":"[SUBDOMAIN]"},"in":"query"},{"name":"region","description":"Source's Region.","required":true,"schema":{"type":"string","x-example":"[REGION]"},"in":"query"},{"name":"adminSecret","description":"Source's Admin Secret.","required":true,"schema":{"type":"string","x-example":"[ADMIN_SECRET]"},"in":"query"},{"name":"database","description":"Source's Database Name.","required":true,"schema":{"type":"string","x-example":"[DATABASE]"},"in":"query"},{"name":"username","description":"Source's Database Username.","required":true,"schema":{"type":"string","x-example":"[USERNAME]"},"in":"query"},{"name":"password","description":"Source's Database Password.","required":true,"schema":{"type":"string","x-example":"[PASSWORD]"},"in":"query"},{"name":"port","description":"Source's Database Port.","required":false,"schema":{"type":"integer","format":"int32","default":5432},"in":"query"}]}},"\/migrations\/supabase":{"post":{"summary":"Migrate Supabase Data","operationId":"migrationsCreateSupabaseMigration","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"createSupabaseMigration","cookies":false,"type":"","demo":"migrations\/create-supabase-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-supabase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","x-example":null,"items":{"type":"string"}},"endpoint":{"type":"string","description":"Source's Supabase Endpoint","x-example":"https:\/\/example.com"},"apiKey":{"type":"string","description":"Source's API Key","x-example":"[API_KEY]"},"databaseHost":{"type":"string","description":"Source's Database Host","x-example":"[DATABASE_HOST]"},"username":{"type":"string","description":"Source's Database Username","x-example":"[USERNAME]"},"password":{"type":"string","description":"Source's Database Password","x-example":"[PASSWORD]"},"port":{"type":"integer","description":"Source's Database Port","x-example":null}},"required":["resources","endpoint","apiKey","databaseHost","username","password"]}}}}}},"\/migrations\/supabase\/report":{"get":{"summary":"Generate a report on Supabase Data","operationId":"migrationsGetSupabaseReport","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migrationReport"}}}}},"x-appwrite":{"method":"getSupabaseReport","cookies":false,"type":"","demo":"migrations\/get-supabase-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-supabase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"schema":{"type":"array","items":{"type":"string"}},"in":"query"},{"name":"endpoint","description":"Source's Supabase Endpoint.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"apiKey","description":"Source's API Key.","required":true,"schema":{"type":"string","x-example":"[API_KEY]"},"in":"query"},{"name":"databaseHost","description":"Source's Database Host.","required":true,"schema":{"type":"string","x-example":"[DATABASE_HOST]"},"in":"query"},{"name":"username","description":"Source's Database Username.","required":true,"schema":{"type":"string","x-example":"[USERNAME]"},"in":"query"},{"name":"password","description":"Source's Database Password.","required":true,"schema":{"type":"string","x-example":"[PASSWORD]"},"in":"query"},{"name":"port","description":"Source's Database Port.","required":false,"schema":{"type":"integer","format":"int32","default":5432},"in":"query"}]}},"\/migrations\/{migrationId}":{"get":{"summary":"Get Migration","operationId":"migrationsGet","tags":["migrations"],"description":"","responses":{"200":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"migrations\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/get-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration unique ID.","required":true,"schema":{"type":"string","x-example":"[MIGRATION_ID]"},"in":"path"}]},"patch":{"summary":"Retry Migration","operationId":"migrationsRetry","tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/migration"}}}}},"x-appwrite":{"method":"retry","cookies":false,"type":"","demo":"migrations\/retry.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/retry-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration unique ID.","required":true,"schema":{"type":"string","x-example":"[MIGRATION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Migration","operationId":"migrationsDelete","tags":["migrations"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"migrations\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration ID.","required":true,"schema":{"type":"string","x-example":"[MIGRATION_ID]"},"in":"path"}]}},"\/project\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectGetUsage","tags":["project"],"description":"","responses":{"200":{"description":"UsageProject","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageProject"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"project\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/project\/variables":{"get":{"summary":"List Variables","operationId":"projectListVariables","tags":["project"],"description":"Get a list of all project variables. These variables will be accessible in all Appwrite Functions at runtime.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","cookies":false,"type":"","demo":"project\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]},"post":{"summary":"Create Variable","operationId":"projectCreateVariable","tags":["project"],"description":"Create a new project variable. This variable will be accessible in all Appwrite Functions at runtime.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","cookies":false,"type":"","demo":"project\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/project\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"projectGetVariable","tags":["project"],"description":"Get a project variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","cookies":false,"type":"","demo":"project\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"projectUpdateVariable","tags":["project"],"description":"Update project variable by its unique ID. This variable will be accessible in all Appwrite Functions at runtime.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","cookies":false,"type":"","demo":"project\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"projectDeleteVariable","tags":["project"],"description":"Delete a project variable by its unique ID. ","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","cookies":false,"type":"","demo":"project\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/projects":{"get":{"summary":"List Projects","operationId":"projectsList","tags":["projects"],"description":"","responses":{"200":{"description":"Projects List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/projectList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"projects\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Project","operationId":"projectsCreate","tags":["projects"],"description":"","responses":{"201":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"projects\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.","x-example":null},"name":{"type":"string","description":"Project name. Max length: 128 chars.","x-example":"[NAME]"},"teamId":{"type":"string","description":"Team unique ID.","x-example":"[TEAM_ID]"},"region":{"type":"string","description":"Project Region.","x-example":"default","enum":["default"],"x-enum-name":null,"x-enum-keys":[]},"description":{"type":"string","description":"Project description. Max length: 256 chars.","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal Name. Max length: 256 chars.","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal Country. Max length: 256 chars.","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal State. Max length: 256 chars.","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal City. Max length: 256 chars.","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal Address. Max length: 256 chars.","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal Tax ID. Max length: 256 chars.","x-example":"[LEGAL_TAX_ID]"}},"required":["projectId","name","teamId"]}}}}}},"\/projects\/{projectId}":{"get":{"summary":"Get Project","operationId":"projectsGet","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"projects\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"patch":{"summary":"Update Project","operationId":"projectsUpdate","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"projects\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name. Max length: 128 chars.","x-example":"[NAME]"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal name. Max length: 256 chars.","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal country. Max length: 256 chars.","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal state. Max length: 256 chars.","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal city. Max length: 256 chars.","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal address. Max length: 256 chars.","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal tax ID. Max length: 256 chars.","x-example":"[LEGAL_TAX_ID]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Project","operationId":"projectsDelete","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"projects\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/auth\/duration":{"patch":{"summary":"Update Project Authentication Duration","operationId":"projectsUpdateAuthDuration","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthDuration","cookies":false,"type":"","demo":"projects\/update-auth-duration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"duration":{"type":"integer","description":"Project session length in seconds. Max length: 31536000 seconds.","x-example":0}},"required":["duration"]}}}}}},"\/projects\/{projectId}\/auth\/limit":{"patch":{"summary":"Update Project users limit","operationId":"projectsUpdateAuthLimit","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthLimit","cookies":false,"type":"","demo":"projects\/update-auth-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Use 0 for unlimited.","x-example":0}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/max-sessions":{"patch":{"summary":"Update Project user sessions limit","operationId":"projectsUpdateAuthSessionsLimit","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthSessionsLimit","cookies":false,"type":"","demo":"projects\/update-auth-sessions-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10","x-example":1}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/password-dictionary":{"patch":{"summary":"Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password","operationId":"projectsUpdateAuthPasswordDictionary","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthPasswordDictionary","cookies":false,"type":"","demo":"projects\/update-auth-password-dictionary.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to enable checking user's password against most commonly used passwords. Default is false.","x-example":false}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/auth\/password-history":{"patch":{"summary":"Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.","operationId":"projectsUpdateAuthPasswordHistory","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthPasswordHistory","cookies":false,"type":"","demo":"projects\/update-auth-password-history.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0","x-example":0}},"required":["limit"]}}}}}},"\/projects\/{projectId}\/auth\/personal-data":{"patch":{"summary":"Enable or disable checking user passwords for similarity with their personal data.","operationId":"projectsUpdatePersonalDataCheck","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updatePersonalDataCheck","cookies":false,"type":"","demo":"projects\/update-personal-data-check.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to check a password for similarity with personal data. Default is false.","x-example":false}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/auth\/{method}":{"patch":{"summary":"Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.","operationId":"projectsUpdateAuthStatus","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateAuthStatus","cookies":false,"type":"","demo":"projects\/update-auth-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"method","description":"Auth Method. Possible values: email-password,magic-url,anonymous,invites,jwt,phone","required":true,"schema":{"type":"string","x-example":"email-password","enum":["email-password","magic-url","anonymous","invites","jwt","phone"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Set the status of this auth method.","x-example":false}},"required":["status"]}}}}}},"\/projects\/{projectId}\/keys":{"get":{"summary":"List Keys","operationId":"projectsListKeys","tags":["projects"],"description":"","responses":{"200":{"description":"API Keys List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/keyList"}}}}},"x-appwrite":{"method":"listKeys","cookies":false,"type":"","demo":"projects\/list-keys.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Key","operationId":"projectsCreateKey","tags":["projects"],"description":"","responses":{"201":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"createKey","cookies":false,"type":"","demo":"projects\/create-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 scopes are allowed.","x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","x-example":null}},"required":["name","scopes"]}}}}}},"\/projects\/{projectId}\/keys\/{keyId}":{"get":{"summary":"Get Key","operationId":"projectsGetKey","tags":["projects"],"description":"","responses":{"200":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"getKey","cookies":false,"type":"","demo":"projects\/get-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}]},"put":{"summary":"Update Key","operationId":"projectsUpdateKey","tags":["projects"],"description":"","responses":{"200":{"description":"Key","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/key"}}}}},"x-appwrite":{"method":"updateKey","cookies":false,"type":"","demo":"projects\/update-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","x-example":null}},"required":["name","scopes"]}}}}},"delete":{"summary":"Delete Key","operationId":"projectsDeleteKey","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteKey","cookies":false,"type":"","demo":"projects\/delete-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"schema":{"type":"string","x-example":"[KEY_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/oauth2":{"patch":{"summary":"Update Project OAuth2","operationId":"projectsUpdateOAuth2","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateOAuth2","cookies":false,"type":"","demo":"projects\/update-o-auth2.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","description":"Provider Name","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":null,"x-enum-keys":[]},"appId":{"type":"string","description":"Provider app ID. Max length: 256 chars.","x-example":"[APP_ID]"},"secret":{"type":"string","description":"Provider secret key. Max length: 512 chars.","x-example":"[SECRET]"},"enabled":{"type":"boolean","description":"Provider status. Set to 'false' to disable new session creation.","x-example":false}},"required":["provider"]}}}}}},"\/projects\/{projectId}\/platforms":{"get":{"summary":"List Platforms","operationId":"projectsListPlatforms","tags":["projects"],"description":"","responses":{"200":{"description":"Platforms List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platformList"}}}}},"x-appwrite":{"method":"listPlatforms","cookies":false,"type":"","demo":"projects\/list-platforms.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Platform","operationId":"projectsCreatePlatform","tags":["projects"],"description":"","responses":{"201":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"createPlatform","cookies":false,"type":"","demo":"projects\/create-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"Platform type.","x-example":"web","enum":["web","flutter-web","flutter-ios","flutter-android","flutter-linux","flutter-macos","flutter-windows","apple-ios","apple-macos","apple-watchos","apple-tvos","android","unity"],"x-enum-name":"PlatformType","x-enum-keys":[]},"name":{"type":"string","description":"Platform name. Max length: 128 chars.","x-example":"[NAME]"},"key":{"type":"string","description":"Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client hostname. Max length: 256 chars.","x-example":null}},"required":["type","name"]}}}}}},"\/projects\/{projectId}\/platforms\/{platformId}":{"get":{"summary":"Get Platform","operationId":"projectsGetPlatform","tags":["projects"],"description":"","responses":{"200":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"getPlatform","cookies":false,"type":"","demo":"projects\/get-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}]},"put":{"summary":"Update Platform","operationId":"projectsUpdatePlatform","tags":["projects"],"description":"","responses":{"200":{"description":"Platform","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/platform"}}}}},"x-appwrite":{"method":"updatePlatform","cookies":false,"type":"","demo":"projects\/update-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Platform name. Max length: 128 chars.","x-example":"[NAME]"},"key":{"type":"string","description":"Package name for android or bundle ID for iOS. Max length: 256 chars.","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client URL. Max length: 256 chars.","x-example":null}},"required":["name"]}}}}},"delete":{"summary":"Delete Platform","operationId":"projectsDeletePlatform","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deletePlatform","cookies":false,"type":"","demo":"projects\/delete-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"schema":{"type":"string","x-example":"[PLATFORM_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/service":{"patch":{"summary":"Update service status","operationId":"projectsUpdateServiceStatus","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateServiceStatus","cookies":false,"type":"","demo":"projects\/update-service-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"service":{"type":"string","description":"Service name.","x-example":"account","enum":["account","avatars","databases","locale","health","storage","teams","users","vcs","functions","proxy","graphql","migrations"],"x-enum-name":null,"x-enum-keys":[]},"status":{"type":"boolean","description":"Service status.","x-example":false}},"required":["service","status"]}}}}}},"\/projects\/{projectId}\/service\/all":{"patch":{"summary":"Update all service status","operationId":"projectsUpdateServiceStatusAll","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateServiceStatusAll","cookies":false,"type":"","demo":"projects\/update-service-status-all.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Service status.","x-example":false}},"required":["status"]}}}}}},"\/projects\/{projectId}\/smtp":{"patch":{"summary":"Update SMTP configuration","operationId":"projectsUpdateSmtpConfiguration","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateSmtpConfiguration","cookies":false,"type":"","demo":"projects\/update-smtp-configuration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable custom SMTP service","x-example":false},"senderName":{"type":"string","description":"Name of the email sender","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"email@example.com"},"replyTo":{"type":"string","description":"Reply to email","x-example":"email@example.com"},"host":{"type":"string","description":"SMTP server host name","x-example":null},"port":{"type":"integer","description":"SMTP server port","x-example":null},"username":{"type":"string","description":"SMTP server username","x-example":"[USERNAME]"},"password":{"type":"string","description":"SMTP server password","x-example":"[PASSWORD]"},"secure":{"type":"string","description":"Does SMTP server use secure connection","x-example":"tls","enum":["tls"],"x-enum-name":null,"x-enum-keys":[]}},"required":["enabled"]}}}}}},"\/projects\/{projectId}\/team":{"patch":{"summary":"Update Project Team","operationId":"projectsUpdateTeam","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateTeam","cookies":false,"type":"","demo":"projects\/update-team.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID of the team to transfer project to.","x-example":"[TEAM_ID]"}},"required":["teamId"]}}}}}},"\/projects\/{projectId}\/templates\/email\/{type}\/{locale}":{"get":{"summary":"Get custom email template","operationId":"projectsGetEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/emailTemplate"}}}}},"x-appwrite":{"method":"getEmailTemplate","cookies":false,"type":"","demo":"projects\/get-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]},"patch":{"summary":"Update custom email templates","operationId":"projectsUpdateEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"Project","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/project"}}}}},"x-appwrite":{"method":"updateEmailTemplate","cookies":false,"type":"","demo":"projects\/update-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"subject":{"type":"string","description":"Email Subject","x-example":"[SUBJECT]"},"message":{"type":"string","description":"Template message","x-example":"[MESSAGE]"},"senderName":{"type":"string","description":"Name of the email sender","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"email@example.com"},"replyTo":{"type":"string","description":"Reply to email","x-example":"email@example.com"}},"required":["subject","message"]}}}}},"delete":{"summary":"Reset custom email template","operationId":"projectsDeleteEmailTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/emailTemplate"}}}}},"x-appwrite":{"method":"deleteEmailTemplate","cookies":false,"type":"","demo":"projects\/delete-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]}},"\/projects\/{projectId}\/templates\/sms\/{type}\/{locale}":{"get":{"summary":"Get custom SMS template","operationId":"projectsGetSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"getSmsTemplate","cookies":false,"type":"","demo":"projects\/get-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]},"patch":{"summary":"Update custom SMS template","operationId":"projectsUpdateSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"updateSmsTemplate","cookies":false,"type":"","demo":"projects\/update-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Template message","x-example":"[MESSAGE]"}},"required":["message"]}}}}},"delete":{"summary":"Reset custom SMS template","operationId":"projectsDeleteSmsTemplate","tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/smsTemplate"}}}}},"x-appwrite":{"method":"deleteSmsTemplate","cookies":false,"type":"","demo":"projects\/delete-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"type","description":"Template type","required":true,"schema":{"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"},{"name":"locale","description":"Template locale","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[]},"in":"path"}]}},"\/projects\/{projectId}\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectsGetUsage","tags":["projects"],"description":"","responses":{"200":{"description":"UsageProject","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageProject"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"projects\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d"},"in":"query"}]}},"\/projects\/{projectId}\/webhooks":{"get":{"summary":"List Webhooks","operationId":"projectsListWebhooks","tags":["projects"],"description":"","responses":{"200":{"description":"Webhooks List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhookList"}}}}},"x-appwrite":{"method":"listWebhooks","cookies":false,"type":"","demo":"projects\/list-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}]},"post":{"summary":"Create Webhook","operationId":"projectsCreateWebhook","tags":["projects"],"description":"","responses":{"201":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"createWebhook","cookies":false,"type":"","demo":"projects\/create-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}}}}},"\/projects\/{projectId}\/webhooks\/{webhookId}":{"get":{"summary":"Get Webhook","operationId":"projectsGetWebhook","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"getWebhook","cookies":false,"type":"","demo":"projects\/get-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]},"put":{"summary":"Update Webhook","operationId":"projectsUpdateWebhook","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"updateWebhook","cookies":false,"type":"","demo":"projects\/update-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}}}},"delete":{"summary":"Delete Webhook","operationId":"projectsDeleteWebhook","tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteWebhook","cookies":false,"type":"","demo":"projects\/delete-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}\/signature":{"patch":{"summary":"Update Webhook Signature Key","operationId":"projectsUpdateWebhookSignature","tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/webhook"}}}}},"x-appwrite":{"method":"updateWebhookSignature","cookies":false,"type":"","demo":"projects\/update-webhook-signature.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"schema":{"type":"string","x-example":"[PROJECT_ID]"},"in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"schema":{"type":"string","x-example":"[WEBHOOK_ID]"},"in":"path"}]}},"\/proxy\/rules":{"get":{"summary":"List Rules","operationId":"proxyListRules","tags":["proxy"],"description":"Get a list of all the proxy rules. You can use the query params to filter your results.","responses":{"200":{"description":"Rule List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/proxyRuleList"}}}}},"x-appwrite":{"method":"listRules","cookies":false,"type":"","demo":"proxy\/list-rules.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/list-rules.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: domain, resourceType, resourceId, url","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Rule","operationId":"proxyCreateRule","tags":["proxy"],"description":"Create a new proxy rule.","responses":{"201":{"description":"Rule","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/proxyRule"}}}}},"x-appwrite":{"method":"createRule","cookies":false,"type":"","demo":"proxy\/create-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/create-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain name.","x-example":null},"resourceType":{"type":"string","description":"Action definition for the rule. Possible values are \"api\", \"function\"","x-example":"api","enum":["api","function"],"x-enum-name":null,"x-enum-keys":[]},"resourceId":{"type":"string","description":"ID of resource for the action type. If resourceType is \"api\", leave empty. If resourceType is \"function\", provide ID of the function.","x-example":"[RESOURCE_ID]"}},"required":["domain","resourceType"]}}}}}},"\/proxy\/rules\/{ruleId}":{"get":{"summary":"Get Rule","operationId":"proxyGetRule","tags":["proxy"],"description":"Get a proxy rule by its unique ID.","responses":{"200":{"description":"Rule","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/proxyRule"}}}}},"x-appwrite":{"method":"getRule","cookies":false,"type":"","demo":"proxy\/get-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/get-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"schema":{"type":"string","x-example":"[RULE_ID]"},"in":"path"}]},"delete":{"summary":"Delete Rule","operationId":"proxyDeleteRule","tags":["proxy"],"description":"Delete a proxy rule by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteRule","cookies":false,"type":"","demo":"proxy\/delete-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/delete-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"schema":{"type":"string","x-example":"[RULE_ID]"},"in":"path"}]}},"\/proxy\/rules\/{ruleId}\/verification":{"patch":{"summary":"Update Rule Verification Status","operationId":"proxyUpdateRuleVerification","tags":["proxy"],"description":"","responses":{"200":{"description":"Rule","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/proxyRule"}}}}},"x-appwrite":{"method":"updateRuleVerification","cookies":false,"type":"","demo":"proxy\/update-rule-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"schema":{"type":"string","x-example":"[RULE_ID]"},"in":"path"}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucketList"}}}}},"x-appwrite":{"method":"listBuckets","cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"createBucket","cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["bucketId","name"]}}}}}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"getBucket","cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"updateBucket","cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/usage":{"get":{"summary":"Get usage stats for storage","operationId":"storageGetUsage","tags":["storage"],"description":"","responses":{"200":{"description":"StorageUsage","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageStorage"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"storage\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/storage\/{bucketId}\/usage":{"get":{"summary":"Get usage stats for a storage bucket","operationId":"storageGetBucketUsage","tags":["storage"],"description":"","responses":{"200":{"description":"UsageBuckets","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageBuckets"}}}}},"x-appwrite":{"method":"getBucketUsage","cookies":false,"type":"","demo":"storage\/get-bucket-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"bucketId","description":"Bucket ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/logs":{"get":{"summary":"List Team Logs","operationId":"teamsListLogs","tags":["teams"],"description":"Get the team activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"teams\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembership","cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/userList"}}}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId"]}}}}}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createArgon2User","cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createBcryptUser","cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/identities":{"get":{"summary":"List Identities","operationId":"usersListIdentities","tags":["users"],"description":"Get identities for all users.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","cookies":false,"type":"","demo":"users\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]}},"\/users\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"usersDeleteIdentity","tags":["users"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","cookies":false,"type":"","demo":"users\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createMD5User","cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createPHPassUser","cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptUser","cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}}}}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptModifiedUser","cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}}}}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createSHAUser","cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/usage":{"get":{"summary":"Get usage stats for the users API","operationId":"usersGetUsage","tags":["users"],"description":"","responses":{"200":{"description":"UsageUsers","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/usageUsers"}}}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"users\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"schema":{"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d"},"in":"query"},{"name":"provider","description":"Provider Name.","required":false,"schema":{"type":"string","x-example":"email","default":""},"in":"query"}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"}},"required":["email"]}}}}}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateLabels","cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","x-example":null,"items":{"type":"string"}}},"required":["labels"]}}}}}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null}},"required":["password"]}}}}}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","x-example":"+12065550100"}},"required":["number"]}}}}}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","x-example":false}},"required":["status"]}}}}}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmailVerification","cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","x-example":false}},"required":["emailVerification"]}}}}}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhoneVerification","cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","x-example":false}},"required":["phoneVerification"]}}}}}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories":{"get":{"summary":"List Repositories","operationId":"vcsListRepositories","tags":["vcs"],"description":"","responses":{"200":{"description":"Provider Repositories List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/providerRepositoryList"}}}}},"x-appwrite":{"method":"listRepositories","cookies":false,"type":"","demo":"vcs\/list-repositories.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create repository","operationId":"vcsCreateRepository","tags":["vcs"],"description":"","responses":{"200":{"description":"ProviderRepository","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/providerRepository"}}}}},"x-appwrite":{"method":"createRepository","cookies":false,"type":"","demo":"vcs\/create-repository.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Repository name (slug)","x-example":"[NAME]"},"private":{"type":"boolean","description":"Mark repository public or private","x-example":false}},"required":["name","private"]}}}}}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}":{"get":{"summary":"Get repository","operationId":"vcsGetRepository","tags":["vcs"],"description":"","responses":{"200":{"description":"ProviderRepository","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/providerRepository"}}}}},"x-appwrite":{"method":"getRepository","cookies":false,"type":"","demo":"vcs\/get-repository.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"schema":{"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]"},"in":"path"}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/branches":{"get":{"summary":"List Repository Branches","operationId":"vcsListRepositoryBranches","tags":["vcs"],"description":"","responses":{"200":{"description":"Branches List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/branchList"}}}}},"x-appwrite":{"method":"listRepositoryBranches","cookies":false,"type":"","demo":"vcs\/list-repository-branches.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"schema":{"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]"},"in":"path"}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/detection":{"post":{"summary":"Detect runtime settings from source code","operationId":"vcsCreateRepositoryDetection","tags":["vcs"],"description":"","responses":{"200":{"description":"Detection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/detection"}}}}},"x-appwrite":{"method":"createRepositoryDetection","cookies":false,"type":"","demo":"vcs\/create-repository-detection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"schema":{"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"providerRootDirectory":{"type":"string","description":"Path to Root Directory","x-example":"[PROVIDER_ROOT_DIRECTORY]"}}}}}}}},"\/vcs\/github\/installations\/{installationId}\/repositories\/{repositoryId}":{"patch":{"summary":"Authorize external deployment","operationId":"vcsUpdateExternalDeployments","tags":["vcs"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"updateExternalDeployments","cookies":false,"type":"","demo":"vcs\/update-external-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"},{"name":"repositoryId","description":"VCS Repository Id","required":true,"schema":{"type":"string","x-example":"[REPOSITORY_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"providerPullRequestId":{"type":"string","description":"GitHub Pull Request Id","x-example":"[PROVIDER_PULL_REQUEST_ID]"}},"required":["providerPullRequestId"]}}}}}},"\/vcs\/installations":{"get":{"summary":"List installations","operationId":"vcsListInstallations","tags":["vcs"],"description":"","responses":{"200":{"description":"Installations List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/installationList"}}}}},"x-appwrite":{"method":"listInstallations","cookies":false,"type":"","demo":"vcs\/list-installations.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/list-installations.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: provider, organization","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]}},"\/vcs\/installations\/{installationId}":{"get":{"summary":"Get installation","operationId":"vcsGetInstallation","tags":["vcs"],"description":"","responses":{"200":{"description":"Installation","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/installation"}}}}},"x-appwrite":{"method":"getInstallation","cookies":false,"type":"","demo":"vcs\/get-installation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/get-installation.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Installation","operationId":"vcsDeleteInstallation","tags":["vcs"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteInstallation","cookies":false,"type":"","demo":"vcs\/delete-installation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/delete-installation.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"schema":{"type":"string","x-example":"[INSTALLATION_ID]"},"in":"path"}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"$ref":"#\/components\/schemas\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"$ref":"#\/components\/schemas\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"$ref":"#\/components\/schemas\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"$ref":"#\/components\/schemas\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"$ref":"#\/components\/schemas\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"$ref":"#\/components\/schemas\/function"},"x-example":""}},"required":["total","functions"]},"installationList":{"description":"Installations List","type":"object","properties":{"total":{"type":"integer","description":"Total number of installations documents that matched your query.","x-example":5,"format":"int32"},"installations":{"type":"array","description":"List of installations.","items":{"$ref":"#\/components\/schemas\/installation"},"x-example":""}},"required":["total","installations"]},"providerRepositoryList":{"description":"Provider Repositories List","type":"object","properties":{"total":{"type":"integer","description":"Total number of providerRepositories documents that matched your query.","x-example":5,"format":"int32"},"providerRepositories":{"type":"array","description":"List of providerRepositories.","items":{"$ref":"#\/components\/schemas\/providerRepository"},"x-example":""}},"required":["total","providerRepositories"]},"branchList":{"description":"Branches List","type":"object","properties":{"total":{"type":"integer","description":"Total number of branches documents that matched your query.","x-example":5,"format":"int32"},"branches":{"type":"array","description":"List of branches.","items":{"$ref":"#\/components\/schemas\/branch"},"x-example":""}},"required":["total","branches"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"$ref":"#\/components\/schemas\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"$ref":"#\/components\/schemas\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"projectList":{"description":"Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"$ref":"#\/components\/schemas\/project"},"x-example":""}},"required":["total","projects"]},"webhookList":{"description":"Webhooks List","type":"object","properties":{"total":{"type":"integer","description":"Total number of webhooks documents that matched your query.","x-example":5,"format":"int32"},"webhooks":{"type":"array","description":"List of webhooks.","items":{"$ref":"#\/components\/schemas\/webhook"},"x-example":""}},"required":["total","webhooks"]},"keyList":{"description":"API Keys List","type":"object","properties":{"total":{"type":"integer","description":"Total number of keys documents that matched your query.","x-example":5,"format":"int32"},"keys":{"type":"array","description":"List of keys.","items":{"$ref":"#\/components\/schemas\/key"},"x-example":""}},"required":["total","keys"]},"platformList":{"description":"Platforms List","type":"object","properties":{"total":{"type":"integer","description":"Total number of platforms documents that matched your query.","x-example":5,"format":"int32"},"platforms":{"type":"array","description":"List of platforms.","items":{"$ref":"#\/components\/schemas\/platform"},"x-example":""}},"required":["total","platforms"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":""}},"required":["total","variables"]},"proxyRuleList":{"description":"Rule List","type":"object","properties":{"total":{"type":"integer","description":"Total number of rules documents that matched your query.","x-example":5,"format":"int32"},"rules":{"type":"array","description":"List of rules.","items":{"$ref":"#\/components\/schemas\/proxyRule"},"x-example":""}},"required":["total","rules"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"migrationList":{"description":"Migrations List","type":"object","properties":{"total":{"type":"integer","description":"Total number of migrations documents that matched your query.","x-example":5,"format":"int32"},"migrations":{"type":"array","description":"List of migrations.","items":{"$ref":"#\/components\/schemas\/migration"},"x-example":""}},"required":["total","migrations"]},"firebaseProjectList":{"description":"Migrations Firebase Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"$ref":"#\/components\/schemas\/firebaseProject"},"x-example":""}},"required":["total","projects"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"If database is enabled. Can be 'enabled' or 'disabled'. When disabled, the database is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled. Can be 'enabled' or 'disabled'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"live":{"type":"boolean","description":"Is the function deployed with the latest configuration? This is set to false if you've changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":300,"format":"int32"},"entrypoint":{"type":"string","description":"The entrypoint file used to execute the deployment.","x-example":"index.js"},"commands":{"type":"string","description":"The build command used to build the deployment.","x-example":"npm install"},"version":{"type":"string","description":"Version of Open Runtimes used for the function.","x-example":"v2"},"installationId":{"type":"string","description":"Function VCS (Version Control System) installation id.","x-example":"6m40at4ejk5h2u9s1hboo"},"providerRepositoryId":{"type":"string","description":"VCS (Version Control System) Repository ID","x-example":"appwrite"},"providerBranch":{"type":"string","description":"VCS (Version Control System) branch name","x-example":"main"},"providerRootDirectory":{"type":"string","description":"Path to function in VCS (Version Control System) repository","x-example":"functions\/helloWorld"},"providerSilentMode":{"type":"boolean","description":"Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests","x-example":false}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","live","logging","runtime","deployment","vars","events","schedule","timeout","entrypoint","commands","version","installationId","providerRepositoryId","providerBranch","providerRootDirectory","providerSilentMode"]},"installation":{"description":"Installation","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"VCS (Version Control System) provider name.","x-example":"github"},"organization":{"type":"string","description":"VCS (Version Control System) organization name.","x-example":"appwrite"},"providerInstallationId":{"type":"string","description":"VCS (Version Control System) installation ID.","x-example":"5322"}},"required":["$id","$createdAt","$updatedAt","provider","organization","providerInstallationId"]},"providerRepository":{"description":"ProviderRepository","type":"object","properties":{"id":{"type":"string","description":"VCS (Version Control System) repository ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"VCS (Version Control System) repository name.","x-example":"appwrite"},"organization":{"type":"string","description":"VCS (Version Control System) organization name","x-example":"appwrite"},"provider":{"type":"string","description":"VCS (Version Control System) provider name.","x-example":"github"},"private":{"type":"boolean","description":"Is VCS (Version Control System) repository private?","x-example":true},"runtime":{"type":"string","description":"Auto-detected runtime suggestion. Empty if getting response of getRuntime().","x-example":"node"},"pushedAt":{"type":"string","description":"Last commit date in ISO 8601 format.","x-example":"datetime"}},"required":["id","name","organization","provider","private","runtime","pushedAt"]},"detection":{"description":"Detection","type":"object","properties":{"runtime":{"type":"string","description":"Runtime","x-example":"node"}},"required":["runtime"]},"branch":{"description":"Branch","type":"object","properties":{"name":{"type":"string","description":"Branch Name.","x-example":"main"}},"required":["name"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"type":{"type":"string","description":"Type of deployment.","x-example":"vcs"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"index.js"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"waiting\", \"ready\", and \"failed\".","x-example":"ready"},"buildLogs":{"type":"string","description":"The build logs.","x-example":"Compiling source files..."},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"},"providerRepositoryName":{"type":"string","description":"The name of the vcs provider repository","x-example":"database"},"providerRepositoryOwner":{"type":"string","description":"The name of the vcs provider repository owner","x-example":"utopia"},"providerRepositoryUrl":{"type":"string","description":"The url of the vcs provider repository","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function"},"providerBranch":{"type":"string","description":"The branch of the vcs repository","x-example":"0.7.x"},"providerCommitHash":{"type":"string","description":"The commit hash of the vcs commit","x-example":"7c3f25d"},"providerCommitAuthorUrl":{"type":"string","description":"The url of vcs commit author","x-example":"https:\/\/github.com\/vermakhushboo"},"providerCommitAuthor":{"type":"string","description":"The name of vcs commit author","x-example":"Khushboo Verma"},"providerCommitMessage":{"type":"string","description":"The commit message","x-example":"Update index.js"},"providerCommitUrl":{"type":"string","description":"The url of the vcs commit","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function\/commit\/60c0416257a9cbcdd96b2d370c38d8f8d150ccfb"},"providerBranchUrl":{"type":"string","description":"The branch of the vcs repository","x-example":"https:\/\/github.com\/vermakhushboo\/appwrite\/tree\/0.7.x"}},"required":["$id","$createdAt","$updatedAt","type","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildLogs","buildTime","providerRepositoryName","providerRepositoryOwner","providerRepositoryUrl","providerBranch","providerCommitHash","providerCommitAuthorUrl","providerCommitAuthor","providerCommitMessage","providerCommitUrl","providerBranchUrl"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"project":{"description":"Project","type":"object","properties":{"$id":{"type":"string","description":"Project ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Project creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Project update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Project name.","x-example":"New Project"},"description":{"type":"string","description":"Project description.","x-example":"This is a new project."},"teamId":{"type":"string","description":"Project team ID.","x-example":"1592981250"},"logo":{"type":"string","description":"Project logo file ID.","x-example":"5f5c451b403cb"},"url":{"type":"string","description":"Project website URL.","x-example":"5f5c451b403cb"},"legalName":{"type":"string","description":"Company legal name.","x-example":"Company LTD."},"legalCountry":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format.","x-example":"US"},"legalState":{"type":"string","description":"State name.","x-example":"New York"},"legalCity":{"type":"string","description":"City name.","x-example":"New York City."},"legalAddress":{"type":"string","description":"Company Address.","x-example":"620 Eighth Avenue, New York, NY 10018"},"legalTaxId":{"type":"string","description":"Company Tax ID.","x-example":"131102020"},"authDuration":{"type":"integer","description":"Session duration in seconds.","x-example":60,"format":"int32"},"authLimit":{"type":"integer","description":"Max users allowed. 0 is unlimited.","x-example":100,"format":"int32"},"authSessionsLimit":{"type":"integer","description":"Max sessions allowed per user. 100 maximum.","x-example":10,"format":"int32"},"authPasswordHistory":{"type":"integer","description":"Max allowed passwords in the history list per user. Max passwords limit allowed in history is 20. Use 0 for disabling password history.","x-example":5,"format":"int32"},"authPasswordDictionary":{"type":"boolean","description":"Whether or not to check user's password against most commonly used passwords.","x-example":true},"authPersonalDataCheck":{"type":"boolean","description":"Whether or not to check the user password for similarity with their personal data.","x-example":true},"providers":{"type":"array","description":"List of Providers.","items":{"$ref":"#\/components\/schemas\/provider"},"x-example":[{}]},"platforms":{"type":"array","description":"List of Platforms.","items":{"$ref":"#\/components\/schemas\/platform"},"x-example":{}},"webhooks":{"type":"array","description":"List of Webhooks.","items":{"$ref":"#\/components\/schemas\/webhook"},"x-example":{}},"keys":{"type":"array","description":"List of API Keys.","items":{"$ref":"#\/components\/schemas\/key"},"x-example":{}},"smtpEnabled":{"type":"boolean","description":"Status for custom SMTP","x-example":false},"smtpSenderName":{"type":"string","description":"SMTP sender name","x-example":"John Appwrite"},"smtpSenderEmail":{"type":"string","description":"SMTP sender email","x-example":"john@appwrite.io"},"smtpReplyTo":{"type":"string","description":"SMTP reply to email","x-example":"support@appwrite.io"},"smtpHost":{"type":"string","description":"SMTP server host name","x-example":"mail.appwrite.io"},"smtpPort":{"type":"integer","description":"SMTP server port","x-example":25,"format":"int32"},"smtpUsername":{"type":"string","description":"SMTP server username","x-example":"emailuser"},"smtpPassword":{"type":"string","description":"SMTP server password","x-example":"securepassword"},"smtpSecure":{"type":"string","description":"SMTP server secure protocol","x-example":"tls"},"authEmailPassword":{"type":"boolean","description":"Email\/Password auth method status","x-example":true},"authUsersAuthMagicURL":{"type":"boolean","description":"Magic URL auth method status","x-example":true},"authAnonymous":{"type":"boolean","description":"Anonymous auth method status","x-example":true},"authInvites":{"type":"boolean","description":"Invites auth method status","x-example":true},"authJWT":{"type":"boolean","description":"JWT auth method status","x-example":true},"authPhone":{"type":"boolean","description":"Phone auth method status","x-example":true},"serviceStatusForAccount":{"type":"boolean","description":"Account service status","x-example":true},"serviceStatusForAvatars":{"type":"boolean","description":"Avatars service status","x-example":true},"serviceStatusForDatabases":{"type":"boolean","description":"Databases service status","x-example":true},"serviceStatusForLocale":{"type":"boolean","description":"Locale service status","x-example":true},"serviceStatusForHealth":{"type":"boolean","description":"Health service status","x-example":true},"serviceStatusForStorage":{"type":"boolean","description":"Storage service status","x-example":true},"serviceStatusForTeams":{"type":"boolean","description":"Teams service status","x-example":true},"serviceStatusForUsers":{"type":"boolean","description":"Users service status","x-example":true},"serviceStatusForVcs":{"type":"boolean","description":"VCS service status","x-example":true},"serviceStatusForFunctions":{"type":"boolean","description":"Functions service status","x-example":true},"serviceStatusForProxy":{"type":"boolean","description":"Proxy service status","x-example":true},"serviceStatusForGraphql":{"type":"boolean","description":"GraphQL service status","x-example":true},"serviceStatusForMigrations":{"type":"boolean","description":"Migrations service status","x-example":true}},"required":["$id","$createdAt","$updatedAt","name","description","teamId","logo","url","legalName","legalCountry","legalState","legalCity","legalAddress","legalTaxId","authDuration","authLimit","authSessionsLimit","authPasswordHistory","authPasswordDictionary","authPersonalDataCheck","providers","platforms","webhooks","keys","smtpEnabled","smtpSenderName","smtpSenderEmail","smtpReplyTo","smtpHost","smtpPort","smtpUsername","smtpPassword","smtpSecure","authEmailPassword","authUsersAuthMagicURL","authAnonymous","authInvites","authJWT","authPhone","serviceStatusForAccount","serviceStatusForAvatars","serviceStatusForDatabases","serviceStatusForLocale","serviceStatusForHealth","serviceStatusForStorage","serviceStatusForTeams","serviceStatusForUsers","serviceStatusForVcs","serviceStatusForFunctions","serviceStatusForProxy","serviceStatusForGraphql","serviceStatusForMigrations"]},"webhook":{"description":"Webhook","type":"object","properties":{"$id":{"type":"string","description":"Webhook ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Webhook creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Webhook update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Webhook name.","x-example":"My Webhook"},"url":{"type":"string","description":"Webhook URL endpoint.","x-example":"https:\/\/example.com\/webhook"},"events":{"type":"array","description":"Webhook trigger events.","items":{"type":"string"},"x-example":"database.collections.update"},"security":{"type":"boolean","description":"Indicated if SSL \/ TLS Certificate verification is enabled.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"},"signatureKey":{"type":"string","description":"Signature key which can be used to validated incoming","x-example":"ad3d581ca230e2b7059c545e5a"}},"required":["$id","$createdAt","$updatedAt","name","url","events","security","httpUser","httpPass","signatureKey"]},"key":{"description":"Key","type":"object","properties":{"$id":{"type":"string","description":"Key ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Key creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Key update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Key name.","x-example":"My API Key"},"expire":{"type":"string","description":"Key expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"scopes":{"type":"array","description":"Allowed permission scopes.","items":{"type":"string"},"x-example":"users.read"},"secret":{"type":"string","description":"Secret key.","x-example":"919c2d18fb5d4...a2ae413da83346ad2"},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"},"sdks":{"type":"array","description":"List of SDK user agents that used this key.","items":{"type":"string"},"x-example":"appwrite:flutter"}},"required":["$id","$createdAt","$updatedAt","name","expire","scopes","secret","accessedAt","sdks"]},"provider":{"description":"Provider","type":"object","properties":{"key":{"type":"string","description":"Provider.","x-example":"github"},"name":{"type":"string","description":"Provider name.","x-example":"GitHub"},"appId":{"type":"string","description":"OAuth 2.0 application ID.","x-example":"259125845563242502"},"secret":{"type":"string","description":"OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.","x-example":"Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ"},"enabled":{"type":"boolean","description":"Provider is active and can be used to create session.","x-example":""}},"required":["key","name","appId","secret","enabled"]},"platform":{"description":"Platform","type":"object","properties":{"$id":{"type":"string","description":"Platform ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Platform creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Platform update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Platform name.","x-example":"My Web App"},"type":{"type":"string","description":"Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, and unity.","x-example":"web"},"key":{"type":"string","description":"Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.","x-example":"com.company.appname"},"store":{"type":"string","description":"App store or Google Play store ID.","x-example":""},"hostname":{"type":"string","description":"Web app hostname. Empty string for other platforms.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"}},"required":["$id","$createdAt","$updatedAt","name","type","key","store","hostname","httpUser","httpPass"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"resourceType":{"type":"string","description":"Service to which the variable belongs. Possible values are \"project\", \"function\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource to which the variable belongs. If resourceType is \"project\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"}},"required":["$id","$createdAt","$updatedAt","key","value","resourceType","resourceId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"metric":{"description":"Metric","type":"object","properties":{"value":{"type":"integer","description":"The value of this metric at the timestamp.","x-example":1,"format":"int32"},"date":{"type":"string","description":"The date at which this metric was aggregated in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["value","date"]},"usageDatabases":{"description":"UsageDatabases","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"databasesCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsCount":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databasesDelete":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsCreate":{"type":"array","description":"Aggregated stats for collections created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsRead":{"type":"array","description":"Aggregated stats for collections read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsUpdate":{"type":"array","description":"Aggregated stats for collections updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsDelete":{"type":"array","description":"Aggregated stats for collections delete.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","databasesCount","documentsCount","collectionsCount","databasesCreate","databasesRead","databasesUpdate","databasesDelete","documentsCreate","documentsRead","documentsUpdate","documentsDelete","collectionsCreate","collectionsRead","collectionsUpdate","collectionsDelete"]},"usageDatabase":{"description":"UsageDatabase","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsCount":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsCreate":{"type":"array","description":"Aggregated stats for collections created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsRead":{"type":"array","description":"Aggregated stats for collections read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsUpdate":{"type":"array","description":"Aggregated stats for collections updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"collectionsDelete":{"type":"array","description":"Aggregated stats for collections delete.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","documentsCount","collectionsCount","documentsCreate","documentsRead","documentsUpdate","documentsDelete","collectionsCreate","collectionsRead","collectionsUpdate","collectionsDelete"]},"usageCollection":{"description":"UsageCollection","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","documentsCount","documentsCreate","documentsRead","documentsUpdate","documentsDelete"]},"usageUsers":{"description":"UsageUsers","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"usersCount":{"type":"array","description":"Aggregated stats for total number of users.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersCreate":{"type":"array","description":"Aggregated stats for users created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersRead":{"type":"array","description":"Aggregated stats for users read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersUpdate":{"type":"array","description":"Aggregated stats for users updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"usersDelete":{"type":"array","description":"Aggregated stats for users deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"sessionsCreate":{"type":"array","description":"Aggregated stats for sessions created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"sessionsProviderCreate":{"type":"array","description":"Aggregated stats for sessions created for a provider ( email, anonymous or oauth2 ).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"sessionsDelete":{"type":"array","description":"Aggregated stats for sessions deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","usersCount","usersCreate","usersRead","usersUpdate","usersDelete","sessionsCreate","sessionsProviderCreate","sessionsDelete"]},"usageStorage":{"description":"StorageUsage","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"storage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesCount":{"type":"array","description":"Aggregated stats for total number of files.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsCount":{"type":"array","description":"Aggregated stats for total number of buckets.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsCreate":{"type":"array","description":"Aggregated stats for buckets created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsRead":{"type":"array","description":"Aggregated stats for buckets read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsUpdate":{"type":"array","description":"Aggregated stats for buckets updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"bucketsDelete":{"type":"array","description":"Aggregated stats for buckets deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesCreate":{"type":"array","description":"Aggregated stats for files created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesRead":{"type":"array","description":"Aggregated stats for files read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesUpdate":{"type":"array","description":"Aggregated stats for files updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesDelete":{"type":"array","description":"Aggregated stats for files deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","storage","filesCount","bucketsCount","bucketsCreate","bucketsRead","bucketsUpdate","bucketsDelete","filesCreate","filesRead","filesUpdate","filesDelete"]},"usageBuckets":{"description":"UsageBuckets","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"filesCount":{"type":"array","description":"Aggregated stats for total number of files in this bucket.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for total storage of files in this bucket.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesCreate":{"type":"array","description":"Aggregated stats for files created.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesRead":{"type":"array","description":"Aggregated stats for files read.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesUpdate":{"type":"array","description":"Aggregated stats for files updated.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"filesDelete":{"type":"array","description":"Aggregated stats for files deleted.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","filesCount","filesStorage","filesCreate","filesRead","filesUpdate","filesDelete"]},"usageFunctions":{"description":"UsageFunctions","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"executionsTotal":{"type":"array","description":"Aggregated stats for number of function executions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsFailure":{"type":"array","description":"Aggregated stats for function execution failures.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsSuccess":{"type":"array","description":"Aggregated stats for function execution successes.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executionsTime":{"type":"array","description":"Aggregated stats for function execution duration.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsTotal":{"type":"array","description":"Aggregated stats for number of function builds.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsFailure":{"type":"array","description":"Aggregated stats for function build failures.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsSuccess":{"type":"array","description":"Aggregated stats for function build successes.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buildsTime":{"type":"array","description":"Aggregated stats for function build duration.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","executionsTotal","executionsFailure","executionsSuccess","executionsTime","buildsTotal","buildsFailure","buildsSuccess","buildsTime"]},"usageProject":{"description":"UsageProject","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"requests":{"type":"array","description":"Aggregated stats for number of requests.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"network":{"type":"array","description":"Aggregated stats for consumed bandwidth.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"executions":{"type":"array","description":"Aggregated stats for function executions.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"documents":{"type":"array","description":"Aggregated stats for number of documents.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"databases":{"type":"array","description":"Aggregated stats for number of databases.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"users":{"type":"array","description":"Aggregated stats for number of users.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"storage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]},"buckets":{"type":"array","description":"Aggregated stats for number of buckets.","items":{"$ref":"#\/components\/schemas\/metric"},"x-example":[]}},"required":["range","requests","network","executions","documents","databases","users","storage","buckets"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]},"proxyRule":{"description":"Rule","type":"object","properties":{"$id":{"type":"string","description":"Rule ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Rule creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Rule update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"domain":{"type":"string","description":"Domain name.","x-example":"appwrite.company.com"},"resourceType":{"type":"string","description":"Action definition for the rule. Possible values are \"api\", \"function\", or \"redirect\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource for the action type. If resourceType is \"api\" or \"url\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"},"status":{"type":"string","description":"Domain verification status. Possible values are \"created\", \"verifying\", \"verified\" and \"unverified\"","x-example":"verified"},"logs":{"type":"string","description":"Certificate generation logs. This will return an empty string if generation did not run, or succeeded.","x-example":"HTTP challegne failed."},"renewAt":{"type":"string","description":"Certificate auto-renewal date in ISO 8601 format.","x-example":"datetime"}},"required":["$id","$createdAt","$updatedAt","domain","resourceType","resourceId","status","logs","renewAt"]},"smsTemplate":{"description":"SmsTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."}},"required":["type","locale","message"]},"emailTemplate":{"description":"EmailTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."},"senderName":{"type":"string","description":"Name of the sender","x-example":"My User"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"mail@appwrite.io"},"replyTo":{"type":"string","description":"Reply to email address","x-example":"emails@appwrite.io"},"subject":{"type":"string","description":"Email subject","x-example":"Please verify your email address"}},"required":["type","locale","message","senderName","senderEmail","replyTo","subject"]},"consoleVariables":{"description":"Console Variables","type":"object","properties":{"_APP_DOMAIN_TARGET":{"type":"string","description":"CNAME target for your Appwrite custom domains.","x-example":"appwrite.io"},"_APP_STORAGE_LIMIT":{"type":"integer","description":"Maximum file size allowed for file upload in bytes.","x-example":"30000000","format":"int32"},"_APP_FUNCTIONS_SIZE_LIMIT":{"type":"integer","description":"Maximum file size allowed for deployment in bytes.","x-example":"30000000","format":"int32"},"_APP_USAGE_STATS":{"type":"string","description":"Defines if usage stats are enabled. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'.","x-example":"enabled"},"_APP_VCS_ENABLED":{"type":"boolean","description":"Defines if VCS (Version Control System) is enabled.","x-example":true},"_APP_DOMAIN_ENABLED":{"type":"boolean","description":"Defines if main domain is configured. If so, custom domains can be created.","x-example":true},"_APP_ASSISTANT_ENABLED":{"type":"boolean","description":"Defines if AI assistant is enabled.","x-example":true}},"required":["_APP_DOMAIN_TARGET","_APP_STORAGE_LIMIT","_APP_FUNCTIONS_SIZE_LIMIT","_APP_USAGE_STATS","_APP_VCS_ENABLED","_APP_DOMAIN_ENABLED","_APP_ASSISTANT_ENABLED"]},"migration":{"description":"Migration","type":"object","properties":{"$id":{"type":"string","description":"Migration ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"string","description":"Migration status ( pending, processing, failed, completed ) ","x-example":"pending"},"stage":{"type":"string","description":"Migration stage ( init, processing, source-check, destination-check, migrating, finished )","x-example":"init"},"source":{"type":"string","description":"A string containing the type of source of the migration.","x-example":"Appwrite"},"resources":{"type":"array","description":"Resources to migration.","items":{"type":"string"},"x-example":["user"]},"statusCounters":{"type":"object","description":"A group of counters that represent the total progress of the migration.","x-example":"{\"Database\": {\"PENDING\": 0, \"SUCCESS\": 1, \"ERROR\": 0, \"SKIP\": 0, \"PROCESSING\": 0, \"WARNING\": 0}}"},"resourceData":{"type":"object","description":"An array of objects containing the report data of the resources that were migrated.","x-example":"[{\"resource\":\"Database\",\"id\":\"public\",\"status\":\"SUCCESS\",\"message\":\"\"}]"},"errors":{"type":"string","description":"All errors that occurred during the migration process.","x-example":[]}},"required":["$id","$createdAt","$updatedAt","status","stage","source","resources","statusCounters","resourceData","errors"]},"migrationReport":{"description":"Migration Report","type":"object","properties":{"user":{"type":"integer","description":"Number of users to be migrated.","x-example":20,"format":"int32"},"team":{"type":"integer","description":"Number of teams to be migrated.","x-example":20,"format":"int32"},"database":{"type":"integer","description":"Number of databases to be migrated.","x-example":20,"format":"int32"},"document":{"type":"integer","description":"Number of documents to be migrated.","x-example":20,"format":"int32"},"file":{"type":"integer","description":"Number of files to be migrated.","x-example":20,"format":"int32"},"bucket":{"type":"integer","description":"Number of buckets to be migrated.","x-example":20,"format":"int32"},"function":{"type":"integer","description":"Number of functions to be migrated.","x-example":20,"format":"int32"},"size":{"type":"integer","description":"Size of files to be migrated in mb.","x-example":30000,"format":"int32"},"version":{"type":"string","description":"Version of the Appwrite instance to be migrated.","x-example":"1.4.0"}},"required":["user","team","database","document","file","bucket","function","size","version"]},"firebaseProject":{"description":"MigrationFirebaseProject","type":"object","properties":{"projectId":{"type":"string","description":"Project ID.","x-example":"my-project"},"displayName":{"type":"string","description":"Project display name.","x-example":"My Project"}},"required":["projectId","displayName"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}},"Mode":{"type":"apiKey","name":"X-Appwrite-Mode","description":"","in":"header","x-appwrite":{"demo":""}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 70e72f510b..87d38a2ed2 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -1 +1 @@ -{"openapi":"3.0.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/databaseList"}}}}},"x-appwrite":{"method":"list","weight":50,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"create","weight":49,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","x-example":false}},"required":["databaseId","name"]}}}}}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"get","weight":51,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"update","weight":53,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Database","operationId":"databasesDelete","tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":54,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collectionList"}}}}},"x-appwrite":{"method":"listCollections","weight":56,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"createCollection","weight":55,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","x-example":false}},"required":["collectionId","name"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"getCollection","weight":57,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"updateCollection","weight":59,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":60,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeList"}}}}},"x-appwrite":{"method":"listAttributes","weight":71,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"createBooleanAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"createEmailAttribute","weight":62,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"updateEmailAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"createEnumAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","elements","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"updateEnumAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"createFloatAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"updateFloatAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"createIntegerAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"createIpAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"updateIpAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","x-example":false},"key":{"type":"string","description":"Attribute Key.","x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","x-example":null},"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"createStringAttribute","weight":61,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","x-example":1},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","size","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"updateStringAttribute","weight":73,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"createUrlAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"updateUrlAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","content":{"application\/json":{"schema":{"oneOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]}}}}},"x-appwrite":{"method":"getAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/indexList"}}}}},"x-appwrite":{"method":"listIndexes","weight":85,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","tags":["databases"],"description":"","responses":{"202":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"createIndex","weight":84,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":null},"type":{"type":"string","description":"Index type.","x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","tags":["databases"],"description":"","responses":{"200":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"getIndex","weight":86,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":87,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/functionList"}}}}},"x-appwrite":{"method":"list","weight":222,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"create","weight":221,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","php-8.0","php-8.1","ruby-3.0","ruby-3.1","python-3.8","python-3.9","python-3.10","dart-2.15","dart-2.16","dart-2.17","dotnet-3.1","dotnet-6.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","kotlin-1.6","cpp-17.0"],"x-enum-name":null,"x-enum-keys":[]},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","x-example":false}},"required":["functionId","name","runtime"]}}}}}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/runtimeList"}}}}},"x-appwrite":{"method":"listRuntimes","weight":223,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"get","weight":224,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"update","weight":227,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Function","operationId":"functionsDelete","tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":229,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deploymentList"}}}}},"x-appwrite":{"method":"listDeployments","weight":231,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: entrypoint, size, buildId, activate","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","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](\/docs\/functions).\n\nUse the \"command\" param to set the entry point used to execute your code.","responses":{"202":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"createDeployment","weight":230,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"entrypoint":{"type":"string","description":"Entrypoint File.","x-example":"[ENTRYPOINT]"},"code":{"type":"string","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","x-example":null},"activate":{"type":"boolean","description":"Automatically activate the deployment when it is finished building.","x-example":false}},"required":["entrypoint","code","activate"]}}}}}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"getDeployment","weight":232,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"updateDeployment","weight":228,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":233,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","tags":["functions"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":234,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"schema":{"type":"string","x-example":"[BUILD_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","weight":239,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","tags":["functions"],"description":"Create a new function variable. These variables can be accessed within function in the `env` object under the request variable.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","weight":238,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","weight":240,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","weight":241,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":242,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"get","weight":105,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthAntivirus"}}}}},"x-appwrite":{"method":"getAntivirus","weight":117,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getCache","weight":108,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getDB","weight":107,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getPubSub","weight":110,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getQueue","weight":109,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueCertificates","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueFunctions","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueLogs","weight":113,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueWebhooks","weight":112,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getStorageLocal","weight":116,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthTime"}}}}},"x-appwrite":{"method":"getTime","weight":111,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucketList"}}}}},"x-appwrite":{"method":"listBuckets","weight":165,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"createBucket","weight":164,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["bucketId","name"]}}}}}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"getBucket","weight":166,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"updateBucket","weight":167,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":168,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","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](\/docs\/permissions).","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/userList"}}}}},"x-appwrite":{"method":"list","weight":201,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":193,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId"]}}}}}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createArgon2User","weight":196,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createBcryptUser","weight":194,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createMD5User","weight":195,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createPHPassUser","weight":198,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptUser","weight":199,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}}}}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":200,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}}}}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createSHAUser","weight":197,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":202,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":219,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":213,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"}},"required":["email"]}}}}}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateLabels","weight":208,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","x-example":null,"items":{"type":"string"}}},"required":["labels"]}}}}}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":206,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":205,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":211,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":212,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null}},"required":["password"]}}}}}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":214,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","x-example":"+12065550100"}},"required":["number"]}}}}}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":203,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":216,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":204,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":218,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":217,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":207,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","x-example":false}},"required":["status"]}}}}}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmailVerification","weight":215,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","x-example":false}},"required":["emailVerification"]}}}}}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":210,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","x-example":false}},"required":["phoneVerification"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"$ref":"#\/components\/schemas\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"$ref":"#\/components\/schemas\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"$ref":"#\/components\/schemas\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"$ref":"#\/components\/schemas\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"$ref":"#\/components\/schemas\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"$ref":"#\/components\/schemas\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"$ref":"#\/components\/schemas\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"Database enabled.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":15,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","runtime","deployment","vars","events","schedule","timeout"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"enabled"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"pending\", \"ready\", and \"failed\".","x-example":"ready"},"buildStdout":{"type":"string","description":"The build stdout.","x-example":"enabled"},"buildStderr":{"type":"string","description":"The build stderr.","x-example":"enabled"},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildStdout","buildStderr","buildTime"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"}},"required":["$id","$createdAt","$updatedAt","key","value","functionId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"openapi":"3.0.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"servers":[{"url":"https:\/\/HOSTNAME\/v1"}],"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":21,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","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","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":28,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["email","password"]}}}}}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","weight":13,"cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":14,"cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":24,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":26,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":27,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","x-example":"password"}},"required":["password"]}}}}}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":29,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","x-example":"password"}},"required":["phone","password"]}}}}}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":22,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePrefs","weight":30,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createRecovery","weight":35,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["email","url"]}}}}},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateRecovery","weight":36,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}}}}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":23,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":34,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"getSession","weight":25,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/session"}}}}},"x-appwrite":{"method":"updateSession","weight":33,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":32,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":31,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"}},"required":["url"]}}}}},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updateVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"createPhoneVerification","weight":39,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/token"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":40,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getBrowser","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"schema":{"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getCreditCard","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"schema":{"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFavicon","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","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](http:\/\/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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFlag","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"schema":{"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"]},"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getImage","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"schema":{"type":"string","format":"url","x-example":"https:\/\/example.com"},"in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":400},"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getInitials","weight":47,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"schema":{"type":"string","x-example":"[NAME]","default":""},"in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":500},"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"schema":{"type":"string","default":""},"in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","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","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getQR","weight":46,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"schema":{"type":"string","x-example":"[TEXT]"},"in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"schema":{"type":"integer","format":"int32","x-example":1,"default":400},"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":1},"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"schema":{"type":"boolean","x-example":false,"default":false},"in":"query"}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/databaseList"}}}}},"x-appwrite":{"method":"list","weight":52,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"create","weight":51,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","x-example":false}},"required":["databaseId","name"]}}}}}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"get","weight":53,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/database"}}}}},"x-appwrite":{"method":"update","weight":55,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Database","operationId":"databasesDelete","tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":56,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collectionList"}}}}},"x-appwrite":{"method":"listCollections","weight":58,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"createCollection","weight":57,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","x-example":false}},"required":["collectionId","name"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"getCollection","weight":59,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/collection"}}}}},"x-appwrite":{"method":"updateCollection","weight":61,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":62,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeList"}}}}},"x-appwrite":{"method":"listAttributes","weight":73,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"createBooleanAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeBoolean"}}}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":71,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeDatetime"}}}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"createEmailAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEmail"}}}}},"x-appwrite":{"method":"updateEmailAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"createEnumAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","elements","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeEnum"}}}}},"x-appwrite":{"method":"updateEnumAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"createFloatAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeFloat"}}}}},"x-appwrite":{"method":"updateFloatAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"createIntegerAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeInteger"}}}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"createIpAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeIp"}}}}},"x-appwrite":{"method":"updateIpAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":null,"x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","x-example":false},"key":{"type":"string","description":"Attribute Key.","x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","x-example":null},"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"createStringAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","x-example":1},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false},"encrypt":{"type":"boolean","description":"Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.","x-example":false}},"required":["key","size","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeString"}}}}},"x-appwrite":{"method":"updateStringAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"createUrlAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":null},"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false}},"required":["key","required"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeUrl"}}}}},"x-appwrite":{"method":"updateUrlAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","content":{"application\/json":{"schema":{"oneOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]}}}}},"x-appwrite":{"method":"getAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":85,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","content":{"":{"schema":{"$ref":"#\/components\/schemas\/attributeRelationship"}}}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":84,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Attribute Key.","required":true,"schema":{"type":"string"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/documentList"}}}}},"x-appwrite":{"method":"listDocuments","weight":91,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"createDocument","weight":90,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"getDocument","weight":92,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/document"}}}}},"x-appwrite":{"method":"updateDocument","weight":94,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":95,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"documentId","description":"Document ID.","required":true,"schema":{"type":"string","x-example":"[DOCUMENT_ID]"},"in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/indexList"}}}}},"x-appwrite":{"method":"listIndexes","weight":87,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","tags":["databases"],"description":"","responses":{"202":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"createIndex","weight":86,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":null},"type":{"type":"string","description":"Index type.","x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}}}}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","tags":["databases"],"description":"","responses":{"200":{"description":"Index","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/index"}}}}},"x-appwrite":{"method":"getIndex","weight":88,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":89,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"schema":{"type":"string","x-example":"[DATABASE_ID]"},"in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"schema":{"type":"string","x-example":"[COLLECTION_ID]"},"in":"path"},{"name":"key","description":"Index Key.","required":true,"schema":{"type":"string"},"in":"path"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/functionList"}}}}},"x-appwrite":{"method":"list","weight":238,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"create","weight":237,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Control System) deployment.","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function.","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function.","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","x-example":"[PROVIDER_ROOT_DIRECTORY]"},"templateRepository":{"type":"string","description":"Repository name of the template.","x-example":"[TEMPLATE_REPOSITORY]"},"templateOwner":{"type":"string","description":"The name of the owner of the template.","x-example":"[TEMPLATE_OWNER]"},"templateRootDirectory":{"type":"string","description":"Path to function code in the template repo.","x-example":"[TEMPLATE_ROOT_DIRECTORY]"},"templateBranch":{"type":"string","description":"Production branch for the repo linked to the function template.","x-example":"[TEMPLATE_BRANCH]"}},"required":["functionId","name","runtime"]}}}}}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/runtimeList"}}}}},"x-appwrite":{"method":"listRuntimes","weight":239,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"get","weight":240,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"update","weight":243,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Controle System) deployment.","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","x-example":"[PROVIDER_ROOT_DIRECTORY]"}},"required":["name","runtime"]}}}}},"delete":{"summary":"Delete Function","operationId":"functionsDelete","tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":246,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deploymentList"}}}}},"x-appwrite":{"method":"listDeployments","weight":248,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: size, buildId, activate, entrypoint, commands","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","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](\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.","responses":{"202":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"createDeployment","weight":247,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"entrypoint":{"type":"string","description":"Entrypoint File.","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","x-example":"[COMMANDS]"},"code":{"type":"string","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","x-example":null},"activate":{"type":"boolean","description":"Automatically activate the deployment when it is finished building.","x-example":false}},"required":["code","activate"]}}}}}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/deployment"}}}}},"x-appwrite":{"method":"getDeployment","weight":249,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/function"}}}}},"x-appwrite":{"method":"updateDeployment","weight":245,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":250,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","tags":["functions"],"description":"Create a new build for an Appwrite Function deployment. This endpoint can be used to retry a failed build.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":251,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"schema":{"type":"string","x-example":"[BUILD_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/download":{"get":{"summary":"Download Deployment","operationId":"functionsDownloadDeployment","tags":["functions"],"description":"","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"downloadDeployment","weight":244,"cookies":false,"type":"location","demo":"functions\/download-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/download-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"schema":{"type":"string","x-example":"[DEPLOYMENT_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/executionList"}}}}},"x-appwrite":{"method":"listExecutions","weight":253,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"createExecution","weight":252,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","x-example":"[BODY]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","x-example":false},"path":{"type":"string","description":"HTTP path of execution. Path can include query params. Default value is \/","x-example":"[PATH]"},"method":{"type":"string","description":"HTTP method of execution. Default value is GET.","x-example":"GET","enum":["GET","POST","PUT","PATCH","DELETE","OPTIONS"],"x-enum-name":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","x-example":"{}"}}}}}}}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/execution"}}}}},"x-appwrite":{"method":"getExecution","weight":254,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"schema":{"type":"string","x-example":"[EXECUTION_ID]"},"in":"path"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variableList"}}}}},"x-appwrite":{"method":"listVariables","weight":256,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","tags":["functions"],"description":"Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.","responses":{"201":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"createVariable","weight":255,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key","value"]}}}}}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"getVariable","weight":257,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/variable"}}}}},"x-appwrite":{"method":"updateVariable","weight":258,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","x-example":"[VALUE]"}},"required":["key"]}}}}},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":259,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"schema":{"type":"string","x-example":"[FUNCTION_ID]"},"in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"schema":{"type":"string","x-example":"[VARIABLE_ID]"},"in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"query","weight":293,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/any"}}}}},"x-appwrite":{"method":"mutation","weight":292,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"get","weight":107,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthAntivirus"}}}}},"x-appwrite":{"method":"getAntivirus","weight":119,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getCache","weight":110,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getDB","weight":109,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getPubSub","weight":112,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getQueue","weight":111,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueCertificates","weight":116,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueFunctions","weight":117,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueLogs","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthQueue"}}}}},"x-appwrite":{"method":"getQueueWebhooks","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthStatus"}}}}},"x-appwrite":{"method":"getStorageLocal","weight":118,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/healthTime"}}}}},"x-appwrite":{"method":"getTime","weight":113,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","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))","responses":{"200":{"description":"Locale","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/locale"}}}}},"x-appwrite":{"method":"get","weight":99,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/localeCodeList"}}}}},"x-appwrite":{"method":"listCodes","weight":100,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/continentList"}}}}},"x-appwrite":{"method":"listContinents","weight":104,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountries","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/countryList"}}}}},"x-appwrite":{"method":"listCountriesEU","weight":102,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/phoneList"}}}}},"x-appwrite":{"method":"listCountriesPhones","weight":103,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/currencyList"}}}}},"x-appwrite":{"method":"listCurrencies","weight":105,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/languageList"}}}}},"x-appwrite":{"method":"listLanguages","weight":106,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucketList"}}}}},"x-appwrite":{"method":"listBuckets","weight":168,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"createBucket","weight":167,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["bucketId","name"]}}}}}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"getBucket","weight":169,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/bucket"}}}}},"x-appwrite":{"method":"updateBucket","weight":170,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","x-example":false}},"required":["name"]}}}}},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":171,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/fileList"}}}}},"x-appwrite":{"method":"listFiles","weight":173,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"createFile","weight":172,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"}],"requestBody":{"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"fileId":{"type":"string","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[FILE_ID]","x-upload-id":true},"file":{"type":"string","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","x-example":null},"permissions":{"type":"array","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["fileId","file"]}}}}}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"getFile","weight":174,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/file"}}}}},"x-appwrite":{"method":"updateFile","weight":178,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}}}},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":179,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileDownload","weight":176,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image"}},"x-appwrite":{"method":"getFilePreview","weight":175,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"schema":{"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center"},"in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":100},"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"schema":{"type":"integer","format":"int32","x-example":0,"default":0},"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"schema":{"type":"number","format":"float","x-example":0,"default":1},"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"schema":{"type":"integer","format":"int32","x-example":-360,"default":0},"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"schema":{"type":"string","default":""},"in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"schema":{"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":""},"in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File"}},"x-appwrite":{"method":"getFileView","weight":177,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"schema":{"type":"string","x-example":"[BUCKET_ID]"},"in":"path"},{"name":"fileId","description":"File ID.","required":true,"schema":{"type":"string","x-example":"[FILE_ID]"},"in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/teamList"}}}}},"x-appwrite":{"method":"list","weight":183,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"create","weight":182,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}}}}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"get","weight":184,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/team"}}}}},"x-appwrite":{"method":"updateName","weight":186,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}},"delete":{"summary":"Delete Team","operationId":"teamsDelete","tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":188,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":190,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"createMembership","weight":189,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","x-example":"[NAME]"}},"required":["roles","url"]}}}}}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"getMembership","weight":191,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembership","weight":192,"cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","x-example":null,"items":{"type":"string"}}},"required":["roles"]}}}}},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":194,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","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","responses":{"200":{"description":"Membership","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membership"}}}}},"x-appwrite":{"method":"updateMembershipStatus","weight":193,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"schema":{"type":"string","x-example":"[MEMBERSHIP_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","x-example":"[SECRET]"}},"required":["userId","secret"]}}}}}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":185,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":187,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"schema":{"type":"string","x-example":"[TEAM_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/userList"}}}}},"x-appwrite":{"method":"list","weight":204,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"create","weight":196,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId"]}}}}}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createArgon2User","weight":199,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createBcryptUser","weight":197,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/identities":{"get":{"summary":"List Identities","operationId":"usersListIdentities","tags":["users"],"description":"Get identities for all users.","responses":{"200":{"description":"Identities List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/identityList"}}}}},"x-appwrite":{"method":"listIdentities","weight":210,"cookies":false,"type":"","demo":"users\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"schema":{"type":"string","default":[]},"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"schema":{"type":"string","x-example":"[SEARCH]","default":""},"in":"query"}]}},"\/users\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"usersDeleteIdentity","tags":["users"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":223,"cookies":false,"type":"","demo":"users\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"schema":{"type":"string","x-example":"[IDENTITY_ID]"},"in":"path"}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createMD5User","weight":198,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createPHPassUser","weight":201,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptUser","weight":202,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}}}}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":203,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}}}}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"createSHAUser","weight":200,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["userId","email","password"]}}}}}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"get","weight":205,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":222,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmail","weight":216,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","x-example":"email@example.com"}},"required":["email"]}}}}}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateLabels","weight":212,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","x-example":null,"items":{"type":"string"}}},"required":["labels"]}}}}}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/logList"}}}}},"x-appwrite":{"method":"listLogs","weight":209,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[]},"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/membershipList"}}}}},"x-appwrite":{"method":"listMemberships","weight":208,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateName","weight":214,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","x-example":"[NAME]"}},"required":["name"]}}}}}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePassword","weight":215,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","x-example":null}},"required":["password"]}}}}}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhone","weight":217,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","x-example":"+12065550100"}},"required":["number"]}}}}}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"getPrefs","weight":206,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/preferences"}}}}},"x-appwrite":{"method":"updatePrefs","weight":219,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","x-example":"{}"}},"required":["prefs"]}}}}}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/sessionList"}}}}},"x-appwrite":{"method":"listSessions","weight":207,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":221,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":220,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"schema":{"type":"string","x-example":"[SESSION_ID]"},"in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateStatus","weight":211,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","x-example":false}},"required":["status"]}}}}}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updateEmailVerification","weight":218,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","x-example":false}},"required":["emailVerification"]}}}}}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/user"}}}}},"x-appwrite":{"method":"updatePhoneVerification","weight":213,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"schema":{"type":"string","x-example":"[USER_ID]"},"in":"path"}],"requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","x-example":false}},"required":["phoneVerification"]}}}}}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"components":{"schemas":{"any":{"description":"Any","type":"object","additionalProperties":true},"error":{"description":"Error","type":"object","properties":{"message":{"type":"string","description":"Error message.","x-example":"Not found"},"code":{"type":"string","description":"Error code.","x-example":"404"},"type":{"type":"string","description":"Error type. You can learn more about all the error types at https:\/\/appwrite.io\/docs\/error-codes#errorTypes","x-example":"not_found"},"version":{"type":"string","description":"Server version number.","x-example":"1.0"}},"required":["message","code","type","version"]},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"$ref":"#\/components\/schemas\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"$ref":"#\/components\/schemas\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"$ref":"#\/components\/schemas\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"$ref":"#\/components\/schemas\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"$ref":"#\/components\/schemas\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"$ref":"#\/components\/schemas\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"$ref":"#\/components\/schemas\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"$ref":"#\/components\/schemas\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"$ref":"#\/components\/schemas\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"$ref":"#\/components\/schemas\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"$ref":"#\/components\/schemas\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"$ref":"#\/components\/schemas\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"$ref":"#\/components\/schemas\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"$ref":"#\/components\/schemas\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"$ref":"#\/components\/schemas\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"$ref":"#\/components\/schemas\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"$ref":"#\/components\/schemas\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"$ref":"#\/components\/schemas\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"$ref":"#\/components\/schemas\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"$ref":"#\/components\/schemas\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"$ref":"#\/components\/schemas\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"If database is enabled. Can be 'enabled' or 'disabled'. When disabled, the database is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled. Can be 'enabled' or 'disabled'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"$ref":"#\/components\/schemas\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"anyOf":[{"$ref":"#\/components\/schemas\/attributeBoolean"},{"$ref":"#\/components\/schemas\/attributeInteger"},{"$ref":"#\/components\/schemas\/attributeFloat"},{"$ref":"#\/components\/schemas\/attributeEmail"},{"$ref":"#\/components\/schemas\/attributeEnum"},{"$ref":"#\/components\/schemas\/attributeUrl"},{"$ref":"#\/components\/schemas\/attributeIp"},{"$ref":"#\/components\/schemas\/attributeDatetime"},{"$ref":"#\/components\/schemas\/attributeRelationship"},{"$ref":"#\/components\/schemas\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"oneOf":[{"$ref":"#\/components\/schemas\/algoArgon2"},{"$ref":"#\/components\/schemas\/algoScrypt"},{"$ref":"#\/components\/schemas\/algoScryptModified"},{"$ref":"#\/components\/schemas\/algoBcrypt"},{"$ref":"#\/components\/schemas\/algoPhpass"},{"$ref":"#\/components\/schemas\/algoSha"},{"$ref":"#\/components\/schemas\/algoMd5"}]},"nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"$ref":"#\/components\/schemas\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"live":{"type":"boolean","description":"Is the function deployed with the latest configuration? This is set to false if you've changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"$ref":"#\/components\/schemas\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":300,"format":"int32"},"entrypoint":{"type":"string","description":"The entrypoint file used to execute the deployment.","x-example":"index.js"},"commands":{"type":"string","description":"The build command used to build the deployment.","x-example":"npm install"},"version":{"type":"string","description":"Version of Open Runtimes used for the function.","x-example":"v2"},"installationId":{"type":"string","description":"Function VCS (Version Control System) installation id.","x-example":"6m40at4ejk5h2u9s1hboo"},"providerRepositoryId":{"type":"string","description":"VCS (Version Control System) Repository ID","x-example":"appwrite"},"providerBranch":{"type":"string","description":"VCS (Version Control System) branch name","x-example":"main"},"providerRootDirectory":{"type":"string","description":"Path to function in VCS (Version Control System) repository","x-example":"functions\/helloWorld"},"providerSilentMode":{"type":"boolean","description":"Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests","x-example":false}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","live","logging","runtime","deployment","vars","events","schedule","timeout","entrypoint","commands","version","installationId","providerRepositoryId","providerBranch","providerRootDirectory","providerSilentMode"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"type":{"type":"string","description":"Type of deployment.","x-example":"vcs"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"index.js"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"waiting\", \"ready\", and \"failed\".","x-example":"ready"},"buildLogs":{"type":"string","description":"The build logs.","x-example":"Compiling source files..."},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"},"providerRepositoryName":{"type":"string","description":"The name of the vcs provider repository","x-example":"database"},"providerRepositoryOwner":{"type":"string","description":"The name of the vcs provider repository owner","x-example":"utopia"},"providerRepositoryUrl":{"type":"string","description":"The url of the vcs provider repository","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function"},"providerBranch":{"type":"string","description":"The branch of the vcs repository","x-example":"0.7.x"},"providerCommitHash":{"type":"string","description":"The commit hash of the vcs commit","x-example":"7c3f25d"},"providerCommitAuthorUrl":{"type":"string","description":"The url of vcs commit author","x-example":"https:\/\/github.com\/vermakhushboo"},"providerCommitAuthor":{"type":"string","description":"The name of vcs commit author","x-example":"Khushboo Verma"},"providerCommitMessage":{"type":"string","description":"The commit message","x-example":"Update index.js"},"providerCommitUrl":{"type":"string","description":"The url of the vcs commit","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function\/commit\/60c0416257a9cbcdd96b2d370c38d8f8d150ccfb"},"providerBranchUrl":{"type":"string","description":"The branch of the vcs repository","x-example":"https:\/\/github.com\/vermakhushboo\/appwrite\/tree\/0.7.x"}},"required":["$id","$createdAt","$updatedAt","type","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildLogs","buildTime","providerRepositoryName","providerRepositoryOwner","providerRepositoryUrl","providerBranch","providerCommitHash","providerCommitAuthorUrl","providerCommitAuthor","providerCommitMessage","providerCommitUrl","providerBranchUrl"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"$ref":"#\/components\/schemas\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"resourceType":{"type":"string","description":"Service to which the variable belongs. Possible values are \"project\", \"function\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource to which the variable belongs. If resourceType is \"project\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"}},"required":["$id","$createdAt","$updatedAt","key","value","resourceType","resourceId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]}},"securitySchemes":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header"},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/swagger2-1.4.x-client.json b/app/config/specs/swagger2-1.4.x-client.json index 2e9b841b0b..1b291408f0 100644 --- a/app/config/specs/swagger2-1.4.x-client.json +++ b/app/config/specs/swagger2-1.4.x-client.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","schema":{"$ref":"#\/definitions\/jwt"}}},"x-appwrite":{"method":"createJWT","weight":18,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createAnonymousSession","weight":17,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createMagicURLSession","weight":13,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":"","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}]},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateMagicURLSession","weight":14,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","consumes":["application\/json"],"produces":["text\/html"],"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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"No content"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"type":"string","x-example":"amazon","in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneSession","weight":15,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"}},"required":["userId","phone"]}}]},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updatePhoneSession","weight":16,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","default":"","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","default":false,"x-example":false}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":21,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":28,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","weight":13,"cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":14,"cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","schema":{"$ref":"#\/definitions\/jwt"}}},"x-appwrite":{"method":"createJWT","weight":20,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":24,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":26,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":27,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":29,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":22,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":30,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":35,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":36,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":23,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":34,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createAnonymousSession","weight":19,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createMagicURLSession","weight":15,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":"","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}]},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateMagicURLSession","weight":16,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","consumes":["application\/json"],"produces":["text\/html"],"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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"No content"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[],"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneSession","weight":17,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"}},"required":["userId","phone"]}}]},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updatePhoneSession","weight":18,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":25,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":33,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":32,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":31,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":39,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":40,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":47,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":46,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":91,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":90,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":92,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":94,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":95,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":253,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":252,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","default":"","x-example":"[BODY]"},"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":"[PATH]"},"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":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","default":[],"x-example":"{}"}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":254,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":293,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":292,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":99,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":100,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":104,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":102,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":103,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":105,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":106,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":173,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":172,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":174,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":178,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":179,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":176,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":175,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":177,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":183,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":182,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":184,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":186,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":188,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":190,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":189,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":191,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembership","weight":192,"cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":194,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":193,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":185,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":187,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"type":"object","$ref":"#\/definitions\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/swagger2-1.4.x-console.json b/app/config/specs/swagger2-1.4.x-console.json index 61c0ca11f2..cf2b52db4b 100644 --- a/app/config/specs/swagger2-1.4.x-console.json +++ b/app/config/specs/swagger2-1.4.x-console.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}},"Mode":{"type":"apiKey","name":"X-Appwrite-Mode","description":"","in":"header","x-appwrite":{"demo":""}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/invite":{"post":{"summary":"Create account using an invite code","operationId":"accountCreateWithInviteCode","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"Account","schema":{"$ref":"#\/definitions\/account"}}},"x-appwrite":{"method":"createWithInviteCode","weight":6,"cookies":false,"type":"","demo":"account\/create-with-invite-code.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose your own unique ID or pass the string `ID.unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"},"code":{"type":"string","description":"An invite code to restrict user signups on the Appwrite console. Users with an invite code will be able to create accounts irrespective of email and IP whitelists.","default":"","x-example":"[CODE]"}},"required":["userId","email","password"]}}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","schema":{"$ref":"#\/definitions\/jwt"}}},"x-appwrite":{"method":"createJWT","weight":18,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createAnonymousSession","weight":17,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createMagicURLSession","weight":13,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":"","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}]},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateMagicURLSession","weight":14,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","consumes":["application\/json"],"produces":["text\/html"],"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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"No content"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"type":"string","x-example":"amazon","in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneSession","weight":15,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"}},"required":["userId","phone"]}}]},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updatePhoneSession","weight":16,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/console\/variables":{"get":{"summary":"Get Variables","operationId":"consoleVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["console"],"description":"Get all Environment Variables that are relevant for the console.","responses":{"200":{"description":"Console Variables","schema":{"$ref":"#\/definitions\/consoleVariables"}}},"x-appwrite":{"method":"variables","weight":274,"cookies":false,"type":"","demo":"console\/variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/console\/variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","schema":{"$ref":"#\/definitions\/databaseList"}}},"x-appwrite":{"method":"list","weight":50,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"create","weight":49,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","default":true,"x-example":false}},"required":["databaseId","name"]}}]}},"\/databases\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabases","schema":{"$ref":"#\/definitions\/usageDatabases"}}},"x-appwrite":{"method":"getUsage","weight":94,"cookies":false,"type":"","demo":"databases\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"`Date range.","required":false,"type":"string","x-example":"24h","default":"30d","in":"query"}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"get","weight":51,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"update","weight":53,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Database","operationId":"databasesDelete","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":54,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","schema":{"$ref":"#\/definitions\/collectionList"}}},"x-appwrite":{"method":"listCollections","weight":56,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"createCollection","weight":55,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","default":true,"x-example":false}},"required":["collectionId","name"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"getCollection","weight":57,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"updateCollection","weight":59,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":60,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","schema":{"$ref":"#\/definitions\/attributeList"}}},"x-appwrite":{"method":"listAttributes","weight":71,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"createBooleanAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"createEmailAttribute","weight":62,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"updateEmailAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"createEnumAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","elements","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"updateEnumAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"createFloatAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"updateFloatAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"createIntegerAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"createIpAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"updateIpAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","default":null,"x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","default":null,"x-example":"oneToOne"},"twoWay":{"type":"boolean","description":"Is Two Way?","default":false,"x-example":false},"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","default":null,"x-example":null},"onDelete":{"type":"string","description":"Constraints option","default":"restrict","x-example":"cascade"}},"required":["relatedCollectionId","type"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"createStringAttribute","weight":61,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","default":null,"x-example":1},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","size","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"updateStringAttribute","weight":73,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"createUrlAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"updateUrlAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","schema":{"x-oneOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]}}},"x-appwrite":{"method":"getAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","default":null,"x-example":"cascade"}}}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/logs":{"get":{"summary":"List Document Logs","operationId":"databasesListDocumentLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the document activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listDocumentLogs","weight":91,"cookies":false,"type":"","demo":"databases\/list-document-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","schema":{"$ref":"#\/definitions\/indexList"}}},"x-appwrite":{"method":"listIndexes","weight":85,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"createIndex","weight":84,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","default":null,"x-example":null},"type":{"type":"string","description":"Index type.","default":null,"x-example":"key"},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","default":[],"x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"getIndex","weight":86,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":87,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/logs":{"get":{"summary":"List Collection Logs","operationId":"databasesListCollectionLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the collection activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listCollectionLogs","weight":58,"cookies":false,"type":"","demo":"databases\/list-collection-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/usage":{"get":{"summary":"Get usage stats for a collection","operationId":"databasesGetCollectionUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageCollection","schema":{"$ref":"#\/definitions\/usageCollection"}}},"x-appwrite":{"method":"getCollectionUsage","weight":96,"cookies":false,"type":"","demo":"databases\/get-collection-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","default":"30d","in":"query"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/logs":{"get":{"summary":"List Database Logs","operationId":"databasesListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the database activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":52,"cookies":false,"type":"","demo":"databases\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetDatabaseUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabase","schema":{"$ref":"#\/definitions\/usageDatabase"}}},"x-appwrite":{"method":"getDatabaseUsage","weight":95,"cookies":false,"type":"","demo":"databases\/get-database-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"range","description":"`Date range.","required":false,"type":"string","x-example":"24h","default":"30d","in":"query"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","schema":{"$ref":"#\/definitions\/functionList"}}},"x-appwrite":{"method":"list","weight":222,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"create","weight":221,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","default":true,"x-example":false}},"required":["functionId","name","runtime"]}}]}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","schema":{"$ref":"#\/definitions\/runtimeList"}}},"x-appwrite":{"method":"listRuntimes","weight":223,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/usage":{"get":{"summary":"Get Functions Usage","operationId":"functionsGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","schema":{"$ref":"#\/definitions\/usageFunctions"}}},"x-appwrite":{"method":"getUsage","weight":226,"cookies":false,"type":"","demo":"functions\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","default":"30d","in":"query"}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"get","weight":224,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"update","weight":227,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Function","operationId":"functionsDelete","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":229,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","schema":{"$ref":"#\/definitions\/deploymentList"}}},"x-appwrite":{"method":"listDeployments","weight":231,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: entrypoint, size, buildId, activate","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","consumes":["multipart\/form-data"],"produces":["application\/json"],"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](\/docs\/functions).\n\nUse the \"command\" param to set the entry point used to execute your code.","responses":{"202":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"createDeployment","weight":230,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"entrypoint","description":"Entrypoint File.","required":true,"type":"string","x-example":"[ENTRYPOINT]","in":"formData"},{"name":"code","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","required":true,"type":"file","in":"formData"},{"name":"activate","description":"Automatically activate the deployment when it is finished building.","required":true,"type":"boolean","x-example":false,"in":"formData"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"getDeployment","weight":232,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"updateDeployment","weight":228,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":233,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":234,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"type":"string","x-example":"[BUILD_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","default":"","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","default":false,"x-example":false}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/usage":{"get":{"summary":"Get Function Usage","operationId":"functionsGetFunctionUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","schema":{"$ref":"#\/definitions\/usageFunctions"}}},"x-appwrite":{"method":"getFunctionUsage","weight":225,"cookies":false,"type":"","demo":"functions\/get-function-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","default":"30d","in":"query"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","weight":239,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function variable. These variables can be accessed within function in the `env` object under the request variable.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","weight":238,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","weight":240,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","weight":241,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":242,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"get","weight":105,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","schema":{"$ref":"#\/definitions\/healthAntivirus"}}},"x-appwrite":{"method":"getAntivirus","weight":117,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getCache","weight":108,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getDB","weight":107,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getPubSub","weight":110,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getQueue","weight":109,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueCertificates","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueFunctions","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueLogs","weight":113,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueWebhooks","weight":112,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getStorageLocal","weight":116,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","schema":{"$ref":"#\/definitions\/healthTime"}}},"x-appwrite":{"method":"getTime","weight":111,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/project\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"","responses":{"200":{"description":"UsageProject","schema":{"$ref":"#\/definitions\/usageProject"}}},"x-appwrite":{"method":"getUsage","weight":163,"cookies":false,"type":"","demo":"project\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","default":"30d","in":"query"}]}},"\/projects":{"get":{"summary":"List Projects","operationId":"projectsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Projects List","schema":{"$ref":"#\/definitions\/projectList"}}},"x-appwrite":{"method":"list","weight":120,"cookies":false,"type":"","demo":"projects\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Project","operationId":"projectsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"create","weight":119,"cookies":false,"type":"","demo":"projects\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"projectId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":null},"name":{"type":"string","description":"Project name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"teamId":{"type":"string","description":"Team unique ID.","default":null,"x-example":"[TEAM_ID]"},"region":{"type":"string","description":"Project Region.","default":"default","x-example":"default"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","default":"","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","default":"","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","default":"","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal Name. Max length: 256 chars.","default":"","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal Country. Max length: 256 chars.","default":"","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal State. Max length: 256 chars.","default":"","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal City. Max length: 256 chars.","default":"","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal Address. Max length: 256 chars.","default":"","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal Tax ID. Max length: 256 chars.","default":"","x-example":"[LEGAL_TAX_ID]"}},"required":["projectId","name","teamId"]}}]}},"\/projects\/{projectId}":{"get":{"summary":"Get Project","operationId":"projectsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"get","weight":121,"cookies":false,"type":"","demo":"projects\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"patch":{"summary":"Update Project","operationId":"projectsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"update","weight":122,"cookies":false,"type":"","demo":"projects\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","default":"","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","default":"","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","default":"","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal name. Max length: 256 chars.","default":"","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal country. Max length: 256 chars.","default":"","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal state. Max length: 256 chars.","default":"","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal city. Max length: 256 chars.","default":"","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal address. Max length: 256 chars.","default":"","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal tax ID. Max length: 256 chars.","default":"","x-example":"[LEGAL_TAX_ID]"}},"required":["name"]}}]},"delete":{"summary":"Delete Project","operationId":"projectsDelete","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":134,"cookies":false,"type":"","demo":"projects\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]}},"\/projects\/{projectId}\/auth\/duration":{"patch":{"summary":"Update Project Authentication Duration","operationId":"projectsUpdateAuthDuration","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthDuration","weight":128,"cookies":false,"type":"","demo":"projects\/update-auth-duration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"duration":{"type":"integer","description":"Project session length in seconds. Max length: 31536000 seconds.","default":null,"x-example":0}},"required":["duration"]}}]}},"\/projects\/{projectId}\/auth\/limit":{"patch":{"summary":"Update Project users limit","operationId":"projectsUpdateAuthLimit","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthLimit","weight":127,"cookies":false,"type":"","demo":"projects\/update-auth-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Use 0 for unlimited.","default":null,"x-example":0}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/max-sessions":{"patch":{"summary":"Update Project user sessions limit","operationId":"projectsUpdateAuthSessionsLimit","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthSessionsLimit","weight":133,"cookies":false,"type":"","demo":"projects\/update-auth-sessions-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10","default":null,"x-example":1}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/password-dictionary":{"patch":{"summary":"Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password","operationId":"projectsUpdateAuthPasswordDictionary","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthPasswordDictionary","weight":131,"cookies":false,"type":"","demo":"projects\/update-auth-password-dictionary.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to enable checking user's password against most commonly used passwords. Default is false.","default":null,"x-example":false}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/auth\/password-history":{"patch":{"summary":"Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.","operationId":"projectsUpdateAuthPasswordHistory","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthPasswordHistory","weight":130,"cookies":false,"type":"","demo":"projects\/update-auth-password-history.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0","default":null,"x-example":0}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/personal-data":{"patch":{"summary":"Enable or disable checking user passwords for similarity with their personal data.","operationId":"projectsUpdatePersonalDataCheck","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updatePersonalDataCheck","weight":132,"cookies":false,"type":"","demo":"projects\/update-personal-data-check.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to check a password for similarity with personal data. Default is false.","default":null,"x-example":false}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/auth\/{method}":{"patch":{"summary":"Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.","operationId":"projectsUpdateAuthStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthStatus","weight":129,"cookies":false,"type":"","demo":"projects\/update-auth-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"method","description":"Auth Method. Possible values: email-password,magic-url,anonymous,invites,jwt,phone","required":true,"type":"string","x-example":"email-password","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Set the status of this auth method.","default":null,"x-example":false}},"required":["status"]}}]}},"\/projects\/{projectId}\/domains":{"get":{"summary":"List Domains","operationId":"projectsListDomains","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Domains List","schema":{"$ref":"#\/definitions\/domainList"}}},"x-appwrite":{"method":"listDomains","weight":152,"cookies":false,"type":"","demo":"projects\/list-domains.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Domain","operationId":"projectsCreateDomain","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Domain","schema":{"$ref":"#\/definitions\/domain"}}},"x-appwrite":{"method":"createDomain","weight":151,"cookies":false,"type":"","demo":"projects\/create-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain name.","default":null,"x-example":null}},"required":["domain"]}}]}},"\/projects\/{projectId}\/domains\/{domainId}":{"get":{"summary":"Get Domain","operationId":"projectsGetDomain","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Domain","schema":{"$ref":"#\/definitions\/domain"}}},"x-appwrite":{"method":"getDomain","weight":153,"cookies":false,"type":"","demo":"projects\/get-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"type":"string","x-example":"[DOMAIN_ID]","in":"path"}]},"delete":{"summary":"Delete Domain","operationId":"projectsDeleteDomain","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDomain","weight":155,"cookies":false,"type":"","demo":"projects\/delete-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"type":"string","x-example":"[DOMAIN_ID]","in":"path"}]}},"\/projects\/{projectId}\/domains\/{domainId}\/verification":{"patch":{"summary":"Update Domain Verification Status","operationId":"projectsUpdateDomainVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Domain","schema":{"$ref":"#\/definitions\/domain"}}},"x-appwrite":{"method":"updateDomainVerification","weight":154,"cookies":false,"type":"","demo":"projects\/update-domain-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"type":"string","x-example":"[DOMAIN_ID]","in":"path"}]}},"\/projects\/{projectId}\/keys":{"get":{"summary":"List Keys","operationId":"projectsListKeys","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"API Keys List","schema":{"$ref":"#\/definitions\/keyList"}}},"x-appwrite":{"method":"listKeys","weight":142,"cookies":false,"type":"","demo":"projects\/list-keys.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Key","operationId":"projectsCreateKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"createKey","weight":141,"cookies":false,"type":"","demo":"projects\/create-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 scopes are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","default":null,"x-example":null}},"required":["name","scopes"]}}]}},"\/projects\/{projectId}\/keys\/{keyId}":{"get":{"summary":"Get Key","operationId":"projectsGetKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"getKey","weight":143,"cookies":false,"type":"","demo":"projects\/get-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"}]},"put":{"summary":"Update Key","operationId":"projectsUpdateKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"updateKey","weight":144,"cookies":false,"type":"","demo":"projects\/update-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","default":null,"x-example":null}},"required":["name","scopes"]}}]},"delete":{"summary":"Delete Key","operationId":"projectsDeleteKey","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteKey","weight":145,"cookies":false,"type":"","demo":"projects\/delete-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"}]}},"\/projects\/{projectId}\/oauth2":{"patch":{"summary":"Update Project OAuth2","operationId":"projectsUpdateOAuth2","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateOAuth2","weight":126,"cookies":false,"type":"","demo":"projects\/update-o-auth2.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"provider":{"type":"string","description":"Provider Name","default":null,"x-example":"amazon"},"appId":{"type":"string","description":"Provider app ID. Max length: 256 chars.","default":null,"x-example":"[APP_ID]"},"secret":{"type":"string","description":"Provider secret key. Max length: 512 chars.","default":null,"x-example":"[SECRET]"},"enabled":{"type":"boolean","description":"Provider status. Set to 'false' to disable new session creation.","default":null,"x-example":false}},"required":["provider"]}}]}},"\/projects\/{projectId}\/platforms":{"get":{"summary":"List Platforms","operationId":"projectsListPlatforms","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platforms List","schema":{"$ref":"#\/definitions\/platformList"}}},"x-appwrite":{"method":"listPlatforms","weight":147,"cookies":false,"type":"","demo":"projects\/list-platforms.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Platform","operationId":"projectsCreatePlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"createPlatform","weight":146,"cookies":false,"type":"","demo":"projects\/create-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"type":{"type":"string","description":"Platform type.","default":null,"x-example":"web"},"name":{"type":"string","description":"Platform name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"key":{"type":"string","description":"Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.","default":"","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","default":"","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client hostname. Max length: 256 chars.","default":"","x-example":null}},"required":["type","name"]}}]}},"\/projects\/{projectId}\/platforms\/{platformId}":{"get":{"summary":"Get Platform","operationId":"projectsGetPlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"getPlatform","weight":148,"cookies":false,"type":"","demo":"projects\/get-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"}]},"put":{"summary":"Update Platform","operationId":"projectsUpdatePlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"updatePlatform","weight":149,"cookies":false,"type":"","demo":"projects\/update-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Platform name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"key":{"type":"string","description":"Package name for android or bundle ID for iOS. Max length: 256 chars.","default":"","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","default":"","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client URL. Max length: 256 chars.","default":"","x-example":null}},"required":["name"]}}]},"delete":{"summary":"Delete Platform","operationId":"projectsDeletePlatform","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deletePlatform","weight":150,"cookies":false,"type":"","demo":"projects\/delete-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"}]}},"\/projects\/{projectId}\/service":{"patch":{"summary":"Update service status","operationId":"projectsUpdateServiceStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateServiceStatus","weight":124,"cookies":false,"type":"","demo":"projects\/update-service-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"service":{"type":"string","description":"Service name.","default":null,"x-example":"account"},"status":{"type":"boolean","description":"Service status.","default":null,"x-example":false}},"required":["service","status"]}}]}},"\/projects\/{projectId}\/service\/all":{"patch":{"summary":"Update all service status","operationId":"projectsUpdateServiceStatusAll","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateServiceStatusAll","weight":125,"cookies":false,"type":"","demo":"projects\/update-service-status-all.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Service status.","default":null,"x-example":false}},"required":["status"]}}]}},"\/projects\/{projectId}\/smtp":{"patch":{"summary":"Update SMTP configuration","operationId":"projectsUpdateSmtpConfiguration","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateSmtpConfiguration","weight":156,"cookies":false,"type":"","demo":"projects\/update-smtp-configuration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable custom SMTP service","default":null,"x-example":false},"sender":{"type":"string","description":"SMTP sender email","default":null,"x-example":"email@example.com"},"host":{"type":"string","description":"SMTP server host name","default":null,"x-example":null},"port":{"type":"integer","description":"SMTP server port","default":null,"x-example":null},"username":{"type":"string","description":"SMTP server username","default":null,"x-example":"[USERNAME]"},"password":{"type":"string","description":"SMTP server password","default":null,"x-example":"[PASSWORD]"},"secure":{"type":"string","description":"Does SMTP server use secure connection","default":"","x-example":"tls"}},"required":["enabled","sender","host","port","username","password"]}}]}},"\/projects\/{projectId}\/team":{"patch":{"summary":"Update Project Team","operationId":"projectsUpdateTeam","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateTeam","weight":123,"cookies":false,"type":"","demo":"projects\/update-team.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID of the team to transfer project to.","default":null,"x-example":"[TEAM_ID]"}},"required":["teamId"]}}]}},"\/projects\/{projectId}\/templates\/email\/{type}\/{locale}":{"get":{"summary":"Get custom email template","operationId":"projectsGetEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","schema":{"$ref":"#\/definitions\/emailTemplate"}}},"x-appwrite":{"method":"getEmailTemplate","weight":158,"cookies":false,"type":"","demo":"projects\/get-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","in":"path"}]},"patch":{"summary":"Update custom email templates","operationId":"projectsUpdateEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateEmailTemplate","weight":160,"cookies":false,"type":"","demo":"projects\/update-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"senderName":{"type":"string","description":"Name of the email sender","default":null,"x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","default":null,"x-example":"email@example.com"},"subject":{"type":"string","description":"Email Subject","default":null,"x-example":"[SUBJECT]"},"message":{"type":"string","description":"Template message","default":null,"x-example":"[MESSAGE]"},"replyTo":{"type":"string","description":"Reply to email","default":"","x-example":"email@example.com"}},"required":["senderName","senderEmail","subject","message"]}}]},"delete":{"summary":"Reset custom email template","operationId":"projectsDeleteEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","schema":{"$ref":"#\/definitions\/emailTemplate"}}},"x-appwrite":{"method":"deleteEmailTemplate","weight":162,"cookies":false,"type":"","demo":"projects\/delete-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","in":"path"}]}},"\/projects\/{projectId}\/templates\/sms\/{type}\/{locale}":{"get":{"summary":"Get custom SMS template","operationId":"projectsGetSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"getSmsTemplate","weight":157,"cookies":false,"type":"","demo":"projects\/get-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","in":"path"}]},"patch":{"summary":"Update custom SMS template","operationId":"projectsUpdateSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"updateSmsTemplate","weight":159,"cookies":false,"type":"","demo":"projects\/update-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"message":{"type":"string","description":"Template message","default":null,"x-example":"[MESSAGE]"}},"required":["message"]}}]},"delete":{"summary":"Reset custom SMS template","operationId":"projectsDeleteSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"deleteSmsTemplate","weight":161,"cookies":false,"type":"","demo":"projects\/delete-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","in":"path"}]}},"\/projects\/{projectId}\/webhooks":{"get":{"summary":"List Webhooks","operationId":"projectsListWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhooks List","schema":{"$ref":"#\/definitions\/webhookList"}}},"x-appwrite":{"method":"listWebhooks","weight":136,"cookies":false,"type":"","demo":"projects\/list-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Webhook","operationId":"projectsCreateWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"createWebhook","weight":135,"cookies":false,"type":"","demo":"projects\/create-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","default":null,"x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","default":null,"x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","default":"","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","default":"","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}":{"get":{"summary":"Get Webhook","operationId":"projectsGetWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"getWebhook","weight":137,"cookies":false,"type":"","demo":"projects\/get-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]},"put":{"summary":"Update Webhook","operationId":"projectsUpdateWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"updateWebhook","weight":138,"cookies":false,"type":"","demo":"projects\/update-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","default":null,"x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","default":null,"x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","default":"","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","default":"","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}]},"delete":{"summary":"Delete Webhook","operationId":"projectsDeleteWebhook","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteWebhook","weight":140,"cookies":false,"type":"","demo":"projects\/delete-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}\/signature":{"patch":{"summary":"Update Webhook Signature Key","operationId":"projectsUpdateWebhookSignature","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"updateWebhookSignature","weight":139,"cookies":false,"type":"","demo":"projects\/update-webhook-signature.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","schema":{"$ref":"#\/definitions\/bucketList"}}},"x-appwrite":{"method":"listBuckets","weight":165,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"createBucket","weight":164,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","default":30000000,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none"},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["bucketId","name"]}}]}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"getBucket","weight":166,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"updateBucket","weight":167,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","default":null,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none"},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":168,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/usage":{"get":{"summary":"Get usage stats for storage","operationId":"storageGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"","responses":{"200":{"description":"StorageUsage","schema":{"$ref":"#\/definitions\/usageStorage"}}},"x-appwrite":{"method":"getUsage","weight":177,"cookies":false,"type":"","demo":"storage\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","default":"30d","in":"query"}]}},"\/storage\/{bucketId}\/usage":{"get":{"summary":"Get usage stats for storage bucket","operationId":"storageGetBucketUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"","responses":{"200":{"description":"UsageBuckets","schema":{"$ref":"#\/definitions\/usageBuckets"}}},"x-appwrite":{"method":"getBucketUsage","weight":178,"cookies":false,"type":"","demo":"storage\/get-bucket-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"bucketId","description":"Bucket ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","default":"30d","in":"query"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/logs":{"get":{"summary":"List Team Logs","operationId":"teamsListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":192,"cookies":false,"type":"","demo":"teams\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","schema":{"$ref":"#\/definitions\/userList"}}},"x-appwrite":{"method":"list","weight":201,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":193,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","default":"","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId"]}}]}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createArgon2User","weight":196,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createBcryptUser","weight":194,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createMD5User","weight":195,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createPHPassUser","weight":198,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptUser","weight":199,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","default":null,"x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","default":null,"x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","default":null,"x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}]}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":200,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","default":null,"x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","default":null,"x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}]}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createSHAUser","weight":197,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","default":null,"x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","default":"","x-example":"sha1"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/usage":{"get":{"summary":"Get usage stats for the users API","operationId":"usersGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"","responses":{"200":{"description":"UsageUsers","schema":{"$ref":"#\/definitions\/usageUsers"}}},"x-appwrite":{"method":"getUsage","weight":220,"cookies":false,"type":"","demo":"users\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","default":"30d","in":"query"}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":202,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":219,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":213,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"}},"required":["email"]}}]}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateLabels","weight":208,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["labels"]}}]}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":206,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":205,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":211,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":212,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null}},"required":["password"]}}]}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":214,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","default":null,"x-example":"+12065550100"}},"required":["number"]}}]}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":203,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":216,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":204,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":218,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":217,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":207,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","default":null,"x-example":false}},"required":["status"]}}]}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmailVerification","weight":215,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","default":null,"x-example":false}},"required":["emailVerification"]}}]}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":210,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","default":null,"x-example":false}},"required":["phoneVerification"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"type":"object","$ref":"#\/definitions\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"type":"object","$ref":"#\/definitions\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"type":"object","$ref":"#\/definitions\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"type":"object","$ref":"#\/definitions\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"type":"object","$ref":"#\/definitions\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"type":"object","$ref":"#\/definitions\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"type":"object","$ref":"#\/definitions\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"projectList":{"description":"Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"type":"object","$ref":"#\/definitions\/project"},"x-example":""}},"required":["total","projects"]},"webhookList":{"description":"Webhooks List","type":"object","properties":{"total":{"type":"integer","description":"Total number of webhooks documents that matched your query.","x-example":5,"format":"int32"},"webhooks":{"type":"array","description":"List of webhooks.","items":{"type":"object","$ref":"#\/definitions\/webhook"},"x-example":""}},"required":["total","webhooks"]},"keyList":{"description":"API Keys List","type":"object","properties":{"total":{"type":"integer","description":"Total number of keys documents that matched your query.","x-example":5,"format":"int32"},"keys":{"type":"array","description":"List of keys.","items":{"type":"object","$ref":"#\/definitions\/key"},"x-example":""}},"required":["total","keys"]},"platformList":{"description":"Platforms List","type":"object","properties":{"total":{"type":"integer","description":"Total number of platforms documents that matched your query.","x-example":5,"format":"int32"},"platforms":{"type":"array","description":"List of platforms.","items":{"type":"object","$ref":"#\/definitions\/platform"},"x-example":""}},"required":["total","platforms"]},"domainList":{"description":"Domains List","type":"object","properties":{"total":{"type":"integer","description":"Total number of domains documents that matched your query.","x-example":5,"format":"int32"},"domains":{"type":"array","description":"List of domains.","items":{"type":"object","$ref":"#\/definitions\/domain"},"x-example":""}},"required":["total","domains"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"Database enabled.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","x-nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","x-nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","x-nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","x-nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","x-nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","x-nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"x-nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"account":{"description":"Account","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":15,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","runtime","deployment","vars","events","schedule","timeout"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"enabled"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"pending\", \"ready\", and \"failed\".","x-example":"ready"},"buildStdout":{"type":"string","description":"The build stdout.","x-example":"enabled"},"buildStderr":{"type":"string","description":"The build stderr.","x-example":"enabled"},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildStdout","buildStderr","buildTime"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"project":{"description":"Project","type":"object","properties":{"$id":{"type":"string","description":"Project ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Project creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Project update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Project name.","x-example":"New Project"},"description":{"type":"string","description":"Project description.","x-example":"This is a new project."},"teamId":{"type":"string","description":"Project team ID.","x-example":"1592981250"},"logo":{"type":"string","description":"Project logo file ID.","x-example":"5f5c451b403cb"},"url":{"type":"string","description":"Project website URL.","x-example":"5f5c451b403cb"},"legalName":{"type":"string","description":"Company legal name.","x-example":"Company LTD."},"legalCountry":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format.","x-example":"US"},"legalState":{"type":"string","description":"State name.","x-example":"New York"},"legalCity":{"type":"string","description":"City name.","x-example":"New York City."},"legalAddress":{"type":"string","description":"Company Address.","x-example":"620 Eighth Avenue, New York, NY 10018"},"legalTaxId":{"type":"string","description":"Company Tax ID.","x-example":"131102020"},"authDuration":{"type":"integer","description":"Session duration in seconds.","x-example":60,"format":"int32"},"authLimit":{"type":"integer","description":"Max users allowed. 0 is unlimited.","x-example":100,"format":"int32"},"authSessionsLimit":{"type":"integer","description":"Max sessions allowed per user. 100 maximum.","x-example":10,"format":"int32"},"authPasswordHistory":{"type":"integer","description":"Max allowed passwords in the history list per user. Max passwords limit allowed in history is 20. Use 0 for disabling password history.","x-example":5,"format":"int32"},"authPasswordDictionary":{"type":"boolean","description":"Whether or not to check user's password against most commonly used passwords.","x-example":true},"authPersonalDataCheck":{"type":"boolean","description":"Whether or not to check the user password for similarity with their personal data.","x-example":true},"providers":{"type":"array","description":"List of Providers.","items":{"type":"object","$ref":"#\/definitions\/provider"},"x-example":[{}]},"platforms":{"type":"array","description":"List of Platforms.","items":{"type":"object","$ref":"#\/definitions\/platform"},"x-example":{}},"webhooks":{"type":"array","description":"List of Webhooks.","items":{"type":"object","$ref":"#\/definitions\/webhook"},"x-example":{}},"keys":{"type":"array","description":"List of API Keys.","items":{"type":"object","$ref":"#\/definitions\/key"},"x-example":{}},"domains":{"type":"array","description":"List of Domains.","items":{"type":"object","$ref":"#\/definitions\/domain"},"x-example":{}},"smtpEnabled":{"type":"boolean","description":"Status for custom SMTP","x-example":false},"smtpSender":{"type":"string","description":"SMTP sender email","x-example":"john@appwrite.io"},"smtpHost":{"type":"string","description":"SMTP server host name","x-example":"mail.appwrite.io"},"smtpPort":{"type":"integer","description":"SMTP server port","x-example":25,"format":"int32"},"smtpUsername":{"type":"string","description":"SMTP server username","x-example":"emailuser"},"smtpPassword":{"type":"string","description":"SMTP server password","x-example":"securepassword"},"smtpSecure":{"type":"string","description":"SMTP server secure protocol","x-example":"tls"},"authEmailPassword":{"type":"boolean","description":"Email\/Password auth method status","x-example":true},"authUsersAuthMagicURL":{"type":"boolean","description":"Magic URL auth method status","x-example":true},"authAnonymous":{"type":"boolean","description":"Anonymous auth method status","x-example":true},"authInvites":{"type":"boolean","description":"Invites auth method status","x-example":true},"authJWT":{"type":"boolean","description":"JWT auth method status","x-example":true},"authPhone":{"type":"boolean","description":"Phone auth method status","x-example":true},"serviceStatusForAccount":{"type":"boolean","description":"Account service status","x-example":true},"serviceStatusForAvatars":{"type":"boolean","description":"Avatars service status","x-example":true},"serviceStatusForDatabases":{"type":"boolean","description":"Databases service status","x-example":true},"serviceStatusForLocale":{"type":"boolean","description":"Locale service status","x-example":true},"serviceStatusForHealth":{"type":"boolean","description":"Health service status","x-example":true},"serviceStatusForStorage":{"type":"boolean","description":"Storage service status","x-example":true},"serviceStatusForTeams":{"type":"boolean","description":"Teams service status","x-example":true},"serviceStatusForUsers":{"type":"boolean","description":"Users service status","x-example":true},"serviceStatusForFunctions":{"type":"boolean","description":"Functions service status","x-example":true},"serviceStatusForGraphql":{"type":"boolean","description":"GraphQL service status","x-example":true}},"required":["$id","$createdAt","$updatedAt","name","description","teamId","logo","url","legalName","legalCountry","legalState","legalCity","legalAddress","legalTaxId","authDuration","authLimit","authSessionsLimit","authPasswordHistory","authPasswordDictionary","authPersonalDataCheck","providers","platforms","webhooks","keys","domains","smtpEnabled","smtpSender","smtpHost","smtpPort","smtpUsername","smtpPassword","smtpSecure","authEmailPassword","authUsersAuthMagicURL","authAnonymous","authInvites","authJWT","authPhone","serviceStatusForAccount","serviceStatusForAvatars","serviceStatusForDatabases","serviceStatusForLocale","serviceStatusForHealth","serviceStatusForStorage","serviceStatusForTeams","serviceStatusForUsers","serviceStatusForFunctions","serviceStatusForGraphql"]},"webhook":{"description":"Webhook","type":"object","properties":{"$id":{"type":"string","description":"Webhook ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Webhook creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Webhook update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Webhook name.","x-example":"My Webhook"},"url":{"type":"string","description":"Webhook URL endpoint.","x-example":"https:\/\/example.com\/webhook"},"events":{"type":"array","description":"Webhook trigger events.","items":{"type":"string"},"x-example":"database.collections.update"},"security":{"type":"boolean","description":"Indicated if SSL \/ TLS Certificate verification is enabled.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"},"signatureKey":{"type":"string","description":"Signature key which can be used to validated incoming","x-example":"ad3d581ca230e2b7059c545e5a"}},"required":["$id","$createdAt","$updatedAt","name","url","events","security","httpUser","httpPass","signatureKey"]},"key":{"description":"Key","type":"object","properties":{"$id":{"type":"string","description":"Key ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Key creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Key update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Key name.","x-example":"My API Key"},"expire":{"type":"string","description":"Key expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"scopes":{"type":"array","description":"Allowed permission scopes.","items":{"type":"string"},"x-example":"users.read"},"secret":{"type":"string","description":"Secret key.","x-example":"919c2d18fb5d4...a2ae413da83346ad2"},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"},"sdks":{"type":"array","description":"List of SDK user agents that used this key.","items":{"type":"string"},"x-example":"appwrite:flutter"}},"required":["$id","$createdAt","$updatedAt","name","expire","scopes","secret","accessedAt","sdks"]},"domain":{"description":"Domain","type":"object","properties":{"$id":{"type":"string","description":"Domain ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Domain creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Domain update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"domain":{"type":"string","description":"Domain name.","x-example":"appwrite.company.com"},"registerable":{"type":"string","description":"Registerable domain name.","x-example":"company.com"},"tld":{"type":"string","description":"TLD name.","x-example":"com"},"verification":{"type":"boolean","description":"Verification process status.","x-example":true},"certificateId":{"type":"string","description":"Certificate ID.","x-example":"6ejea5c13377e"}},"required":["$id","$createdAt","$updatedAt","domain","registerable","tld","verification","certificateId"]},"provider":{"description":"Provider","type":"object","properties":{"key":{"type":"string","description":"Provider.","x-example":"github"},"name":{"type":"string","description":"Provider name.","x-example":"GitHub"},"appId":{"type":"string","description":"OAuth 2.0 application ID.","x-example":"259125845563242502"},"secret":{"type":"string","description":"OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.","x-example":"Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ"},"enabled":{"type":"boolean","description":"Provider is active and can be used to create session.","x-example":""}},"required":["key","name","appId","secret","enabled"]},"platform":{"description":"Platform","type":"object","properties":{"$id":{"type":"string","description":"Platform ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Platform creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Platform update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Platform name.","x-example":"My Web App"},"type":{"type":"string","description":"Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, and unity.","x-example":"web"},"key":{"type":"string","description":"Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.","x-example":"com.company.appname"},"store":{"type":"string","description":"App store or Google Play store ID.","x-example":""},"hostname":{"type":"string","description":"Web app hostname. Empty string for other platforms.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"}},"required":["$id","$createdAt","$updatedAt","name","type","key","store","hostname","httpUser","httpPass"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"}},"required":["$id","$createdAt","$updatedAt","key","value","functionId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"metric":{"description":"Metric","type":"object","properties":{"value":{"type":"integer","description":"The value of this metric at the timestamp.","x-example":1,"format":"int32"},"date":{"type":"string","description":"The date at which this metric was aggregated in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["value","date"]},"usageDatabases":{"description":"UsageDatabases","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"databasesTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsTotal":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","databasesTotal","collectionsTotal","documentsTotal"]},"usageDatabase":{"description":"UsageDatabase","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"collectionsTotal":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","collectionsTotal","documentsTotal"]},"usageCollection":{"description":"UsageCollection","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","documentsTotal"]},"usageUsers":{"description":"UsageUsers","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"usersTotal":{"type":"array","description":"Aggregated stats for total number of users.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"sessionsTotal":{"type":"array","description":"Aggregated stats for sessions created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","usersTotal","sessionsTotal"]},"usageStorage":{"description":"StorageUsage","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"bucketsTotal":{"type":"array","description":"Aggregated stats for total number of buckets.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesTotal":{"type":"array","description":"Aggregated stats for total number of files.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","bucketsTotal","filesTotal","filesStorage"]},"usageBuckets":{"description":"UsageBuckets","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"filesTotal":{"type":"array","description":"Aggregated stats for total number of files in this bucket.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for total storage of files in this bucket.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","filesTotal","filesStorage"]},"usageFunctions":{"description":"UsageFunctions","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"functionsTotal":{"type":"array","description":"Aggregated stats for number of functions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"deploymentsTotal":{"type":"array","description":"Aggregated stats for number of function deployments.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"deploymentsStorage":{"type":"array","description":"Aggregated stats for function deployments storage.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsTotal":{"type":"array","description":"Aggregated stats for number of function builds.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsStorage":{"type":"array","description":"Aggregated stats for builds storage.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsTime":{"type":"array","description":"Aggregated stats for function build compute.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsTotal":{"type":"array","description":"Aggregated stats for number of function executions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsTime":{"type":"array","description":"Aggregated stats for function execution compute.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","functionsTotal","deploymentsTotal","deploymentsStorage","buildsTotal","buildsStorage","buildsTime","executionsTotal","executionsTime"]},"usageProject":{"description":"UsageProject","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"requestsTotal":{"type":"array","description":"Aggregated stats for number of requests.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"network":{"type":"array","description":"Aggregated stats for consumed bandwidth.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsTotal":{"type":"array","description":"Aggregated stats for function executions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesTotal":{"type":"array","description":"Aggregated stats for number of databases.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersTotal":{"type":"array","description":"Aggregated stats for number of users.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsTotal":{"type":"array","description":"Aggregated stats for number of buckets.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","requestsTotal","network","executionsTotal","documentsTotal","databasesTotal","usersTotal","filesStorage","bucketsTotal"]},"smsTemplate":{"description":"SmsTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."}},"required":["type","locale","message"]},"emailTemplate":{"description":"EmailTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."},"senderName":{"type":"string","description":"Name of the sender","x-example":"My User"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"mail@appwrite.io"},"replyTo":{"type":"string","description":"Reply to email address","x-example":"emails@appwrite.io"},"subject":{"type":"string","description":"Email subject","x-example":"Please verify your email address"}},"required":["type","locale","message","senderName","senderEmail","replyTo","subject"]},"consoleVariables":{"description":"Console Variables","type":"object","properties":{"_APP_DOMAIN_TARGET":{"type":"string","description":"CNAME target for your Appwrite custom domains.","x-example":"appwrite.io"},"_APP_STORAGE_LIMIT":{"type":"integer","description":"Maximum file size allowed for file upload in bytes.","x-example":"30000000","format":"int32"},"_APP_FUNCTIONS_SIZE_LIMIT":{"type":"integer","description":"Maximum file size allowed for deployment in bytes.","x-example":"30000000","format":"int32"},"_APP_USAGE_STATS":{"type":"string","description":"Defines if usage stats are enabled. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'.","x-example":"enabled"}},"required":["_APP_DOMAIN_TARGET","_APP_STORAGE_LIMIT","_APP_FUNCTIONS_SIZE_LIMIT","_APP_USAGE_STATS"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}},"Mode":{"type":"apiKey","name":"X-Appwrite-Mode","description":"","in":"header","x-appwrite":{"demo":""}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","schema":{"$ref":"#\/definitions\/jwt"}}},"x-appwrite":{"method":"createJWT","cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createAnonymousSession","cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createEmailSession","cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createMagicURLSession","cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":"","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}]},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateMagicURLSession","cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","consumes":["application\/json"],"produces":["text\/html"],"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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"No content"}},"x-appwrite":{"method":"createOAuth2Session","cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[],"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneSession","cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"}},"required":["userId","phone"]}}]},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updatePhoneSession","cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/console\/assistant":{"post":{"summary":"Ask Query","operationId":"assistantChat","consumes":["application\/json"],"produces":["text\/plain"],"tags":["assistant"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"chat","cookies":false,"type":"","demo":"assistant\/chat.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/assistant\/chat.md","rate-limit":15,"rate-time":3600,"rate-key":"userId:{userId}","scope":"assistant.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prompt":{"type":"string","description":"Prompt. A string containing questions asked to the AI assistant.","default":null,"x-example":"[PROMPT]"}},"required":["prompt"]}}]}},"\/console\/variables":{"get":{"summary":"Get Variables","operationId":"consoleVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["console"],"description":"Get all Environment Variables that are relevant for the console.","responses":{"200":{"description":"Console Variables","schema":{"$ref":"#\/definitions\/consoleVariables"}}},"x-appwrite":{"method":"variables","cookies":false,"type":"","demo":"console\/variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/console\/variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","schema":{"$ref":"#\/definitions\/databaseList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["databaseId","name"]}}]}},"\/databases\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabases","schema":{"$ref":"#\/definitions\/usageDatabases"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"databases\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"`Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Database","operationId":"databasesDelete","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","schema":{"$ref":"#\/definitions\/collectionList"}}},"x-appwrite":{"method":"listCollections","cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"createCollection","cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["collectionId","name"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"getCollection","cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"updateCollection","cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","schema":{"$ref":"#\/definitions\/attributeList"}}},"x-appwrite":{"method":"listAttributes","cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"createBooleanAttribute","cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"updateBooleanAttribute","cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"createDatetimeAttribute","cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"updateDatetimeAttribute","cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"createEmailAttribute","cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"updateEmailAttribute","cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"createEnumAttribute","cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","elements","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"updateEnumAttribute","cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"createFloatAttribute","cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"updateFloatAttribute","cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"createIntegerAttribute","cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"updateIntegerAttribute","cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"createIpAttribute","cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"updateIpAttribute","cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"createRelationshipAttribute","cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","default":null,"x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","default":null,"x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","default":false,"x-example":false},"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","default":null,"x-example":null},"onDelete":{"type":"string","description":"Constraints option","default":"restrict","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"createStringAttribute","cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","default":null,"x-example":1},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false},"encrypt":{"type":"boolean","description":"Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.","default":false,"x-example":false}},"required":["key","size","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"updateStringAttribute","cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"createUrlAttribute","cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"updateUrlAttribute","cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","schema":{"x-oneOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]}}},"x-appwrite":{"method":"getAttribute","cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"updateRelationshipAttribute","cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","default":null,"x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/logs":{"get":{"summary":"List Document Logs","operationId":"databasesListDocumentLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the document activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listDocumentLogs","cookies":false,"type":"","demo":"databases\/list-document-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","schema":{"$ref":"#\/definitions\/indexList"}}},"x-appwrite":{"method":"listIndexes","cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"createIndex","cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","default":null,"x-example":null},"type":{"type":"string","description":"Index type.","default":null,"x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","default":[],"x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"getIndex","cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/logs":{"get":{"summary":"List Collection Logs","operationId":"databasesListCollectionLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the collection activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listCollectionLogs","cookies":false,"type":"","demo":"databases\/list-collection-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/usage":{"get":{"summary":"Get usage stats for a collection","operationId":"databasesGetCollectionUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageCollection","schema":{"$ref":"#\/definitions\/usageCollection"}}},"x-appwrite":{"method":"getCollectionUsage","cookies":false,"type":"","demo":"databases\/get-collection-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/logs":{"get":{"summary":"List Database Logs","operationId":"databasesListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the database activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"databases\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetDatabaseUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabase","schema":{"$ref":"#\/definitions\/usageDatabase"}}},"x-appwrite":{"method":"getDatabaseUsage","cookies":false,"type":"","demo":"databases\/get-database-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"range","description":"`Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","schema":{"$ref":"#\/definitions\/functionList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","default":true,"x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","default":true,"x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","default":"","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","default":"","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Control System) deployment.","default":"","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function.","default":"","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function.","default":"","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","default":false,"x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"},"templateRepository":{"type":"string","description":"Repository name of the template.","default":"","x-example":"[TEMPLATE_REPOSITORY]"},"templateOwner":{"type":"string","description":"The name of the owner of the template.","default":"","x-example":"[TEMPLATE_OWNER]"},"templateRootDirectory":{"type":"string","description":"Path to function code in the template repo.","default":"","x-example":"[TEMPLATE_ROOT_DIRECTORY]"},"templateBranch":{"type":"string","description":"Production branch for the repo linked to the function template.","default":"","x-example":"[TEMPLATE_BRANCH]"}},"required":["functionId","name","runtime"]}}]}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","schema":{"$ref":"#\/definitions\/runtimeList"}}},"x-appwrite":{"method":"listRuntimes","cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/usage":{"get":{"summary":"Get Functions Usage","operationId":"functionsGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","schema":{"$ref":"#\/definitions\/usageFunctions"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"functions\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","default":true,"x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","default":true,"x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","default":"","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","default":"","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Controle System) deployment.","default":"","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function","default":"","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function","default":"","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","default":false,"x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"}},"required":["name","runtime"]}}]},"delete":{"summary":"Delete Function","operationId":"functionsDelete","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","schema":{"$ref":"#\/definitions\/deploymentList"}}},"x-appwrite":{"method":"listDeployments","cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: size, buildId, activate, entrypoint, commands","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","consumes":["multipart\/form-data"],"produces":["application\/json"],"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](\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.","responses":{"202":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"createDeployment","cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"entrypoint","description":"Entrypoint File.","required":false,"type":"string","x-example":"[ENTRYPOINT]","in":"formData"},{"name":"commands","description":"Build Commands.","required":false,"type":"string","x-example":"[COMMANDS]","in":"formData"},{"name":"code","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","required":true,"type":"file","in":"formData"},{"name":"activate","description":"Automatically activate the deployment when it is finished building.","required":true,"type":"boolean","x-example":false,"in":"formData"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"getDeployment","cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"updateDeployment","cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Create a new build for an Appwrite Function deployment. This endpoint can be used to retry a failed build.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"type":"string","x-example":"[BUILD_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/download":{"get":{"summary":"Download Deployment","operationId":"functionsDownloadDeployment","consumes":["application\/json"],"produces":["*\/*"],"tags":["functions"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"downloadDeployment","cookies":false,"type":"location","demo":"functions\/download-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/download-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","default":"","x-example":"[BODY]"},"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":"[PATH]"},"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":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","default":[],"x-example":"{}"}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/usage":{"get":{"summary":"Get Function Usage","operationId":"functionsGetFunctionUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","schema":{"$ref":"#\/definitions\/usageFunctions"}}},"x-appwrite":{"method":"getFunctionUsage","cookies":false,"type":"","demo":"functions\/get-function-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","schema":{"$ref":"#\/definitions\/healthAntivirus"}}},"x-appwrite":{"method":"getAntivirus","cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getCache","cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getDB","cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getPubSub","cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getQueue","cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueCertificates","cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueFunctions","cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueLogs","cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueWebhooks","cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getStorageLocal","cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","schema":{"$ref":"#\/definitions\/healthTime"}}},"x-appwrite":{"method":"getTime","cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/migrations":{"get":{"summary":"List Migrations","operationId":"migrationsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migrations List","schema":{"$ref":"#\/definitions\/migrationList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"migrations\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/list-migrations.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: status, stage, source, resources, statusCounters, resourceData, errors","required":false,"type":"string","default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]}},"\/migrations\/appwrite":{"post":{"summary":"Migrate Appwrite Data","operationId":"migrationsCreateAppwriteMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createAppwriteMigration","cookies":false,"type":"","demo":"migrations\/create-appwrite-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-appwrite.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"endpoint":{"type":"string","description":"Source's Appwrite Endpoint","default":null,"x-example":"https:\/\/example.com"},"projectId":{"type":"string","description":"Source's Project ID","default":null,"x-example":"[PROJECT_ID]"},"apiKey":{"type":"string","description":"Source's API Key","default":null,"x-example":"[API_KEY]"}},"required":["resources","endpoint","projectId","apiKey"]}}]}},"\/migrations\/appwrite\/report":{"get":{"summary":"Generate a report on Appwrite Data","operationId":"migrationsGetAppwriteReport","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getAppwriteReport","cookies":false,"type":"","demo":"migrations\/get-appwrite-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-appwrite-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"endpoint","description":"Source's Appwrite Endpoint","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"projectID","description":"Source's Project ID","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"query"},{"name":"key","description":"Source's API Key","required":true,"type":"string","x-example":"[KEY]","in":"query"}]}},"\/migrations\/firebase":{"post":{"summary":"Migrate Firebase Data (Service Account)","operationId":"migrationsCreateFirebaseMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createFirebaseMigration","cookies":false,"type":"","demo":"migrations\/create-firebase-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"serviceAccount":{"type":"string","description":"JSON of the Firebase service account credentials","default":null,"x-example":"[SERVICE_ACCOUNT]"}},"required":["resources","serviceAccount"]}}]}},"\/migrations\/firebase\/deauthorize":{"get":{"summary":"Revoke Appwrite's authorization to access Firebase Projects","operationId":"migrationsDeleteFirebaseAuth","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"deleteFirebaseAuth","cookies":false,"type":"","demo":"migrations\/delete-firebase-auth.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/migrations\/firebase\/oauth":{"post":{"summary":"Migrate Firebase Data (OAuth)","operationId":"migrationsCreateFirebaseOAuthMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createFirebaseOAuthMigration","cookies":false,"type":"","demo":"migrations\/create-firebase-o-auth-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"projectId":{"type":"string","description":"Project ID of the Firebase Project","default":null,"x-example":"[PROJECT_ID]"}},"required":["resources","projectId"]}}]}},"\/migrations\/firebase\/projects":{"get":{"summary":"List Firebase Projects","operationId":"migrationsListFirebaseProjects","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migrations Firebase Projects List","schema":{"$ref":"#\/definitions\/firebaseProjectList"}}},"x-appwrite":{"method":"listFirebaseProjects","cookies":false,"type":"","demo":"migrations\/list-firebase-projects.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/migrations\/firebase\/report":{"get":{"summary":"Generate a report on Firebase Data","operationId":"migrationsGetFirebaseReport","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getFirebaseReport","cookies":false,"type":"","demo":"migrations\/get-firebase-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"serviceAccount","description":"JSON of the Firebase service account credentials","required":true,"type":"string","x-example":"[SERVICE_ACCOUNT]","in":"query"}]}},"\/migrations\/firebase\/report\/oauth":{"get":{"summary":"Generate a report on Firebase Data using OAuth","operationId":"migrationsGetFirebaseReportOAuth","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getFirebaseReportOAuth","cookies":false,"type":"","demo":"migrations\/get-firebase-report-o-auth.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"projectId","description":"Project ID","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"query"}]}},"\/migrations\/nhost":{"post":{"summary":"Migrate NHost Data","operationId":"migrationsCreateNHostMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createNHostMigration","cookies":false,"type":"","demo":"migrations\/create-n-host-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-nhost.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"subdomain":{"type":"string","description":"Source's Subdomain","default":null,"x-example":"[SUBDOMAIN]"},"region":{"type":"string","description":"Source's Region","default":null,"x-example":"[REGION]"},"adminSecret":{"type":"string","description":"Source's Admin Secret","default":null,"x-example":"[ADMIN_SECRET]"},"database":{"type":"string","description":"Source's Database Name","default":null,"x-example":"[DATABASE]"},"username":{"type":"string","description":"Source's Database Username","default":null,"x-example":"[USERNAME]"},"password":{"type":"string","description":"Source's Database Password","default":null,"x-example":"[PASSWORD]"},"port":{"type":"integer","description":"Source's Database Port","default":5432,"x-example":null}},"required":["resources","subdomain","region","adminSecret","database","username","password"]}}]}},"\/migrations\/nhost\/report":{"get":{"summary":"Generate a report on NHost Data","operationId":"migrationsGetNHostReport","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getNHostReport","cookies":false,"type":"","demo":"migrations\/get-n-host-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-nhost-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate.","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"subdomain","description":"Source's Subdomain.","required":true,"type":"string","x-example":"[SUBDOMAIN]","in":"query"},{"name":"region","description":"Source's Region.","required":true,"type":"string","x-example":"[REGION]","in":"query"},{"name":"adminSecret","description":"Source's Admin Secret.","required":true,"type":"string","x-example":"[ADMIN_SECRET]","in":"query"},{"name":"database","description":"Source's Database Name.","required":true,"type":"string","x-example":"[DATABASE]","in":"query"},{"name":"username","description":"Source's Database Username.","required":true,"type":"string","x-example":"[USERNAME]","in":"query"},{"name":"password","description":"Source's Database Password.","required":true,"type":"string","x-example":"[PASSWORD]","in":"query"},{"name":"port","description":"Source's Database Port.","required":false,"type":"integer","format":"int32","default":5432,"in":"query"}]}},"\/migrations\/supabase":{"post":{"summary":"Migrate Supabase Data","operationId":"migrationsCreateSupabaseMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createSupabaseMigration","cookies":false,"type":"","demo":"migrations\/create-supabase-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-supabase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"endpoint":{"type":"string","description":"Source's Supabase Endpoint","default":null,"x-example":"https:\/\/example.com"},"apiKey":{"type":"string","description":"Source's API Key","default":null,"x-example":"[API_KEY]"},"databaseHost":{"type":"string","description":"Source's Database Host","default":null,"x-example":"[DATABASE_HOST]"},"username":{"type":"string","description":"Source's Database Username","default":null,"x-example":"[USERNAME]"},"password":{"type":"string","description":"Source's Database Password","default":null,"x-example":"[PASSWORD]"},"port":{"type":"integer","description":"Source's Database Port","default":5432,"x-example":null}},"required":["resources","endpoint","apiKey","databaseHost","username","password"]}}]}},"\/migrations\/supabase\/report":{"get":{"summary":"Generate a report on Supabase Data","operationId":"migrationsGetSupabaseReport","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getSupabaseReport","cookies":false,"type":"","demo":"migrations\/get-supabase-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-supabase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"endpoint","description":"Source's Supabase Endpoint.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"apiKey","description":"Source's API Key.","required":true,"type":"string","x-example":"[API_KEY]","in":"query"},{"name":"databaseHost","description":"Source's Database Host.","required":true,"type":"string","x-example":"[DATABASE_HOST]","in":"query"},{"name":"username","description":"Source's Database Username.","required":true,"type":"string","x-example":"[USERNAME]","in":"query"},{"name":"password","description":"Source's Database Password.","required":true,"type":"string","x-example":"[PASSWORD]","in":"query"},{"name":"port","description":"Source's Database Port.","required":false,"type":"integer","format":"int32","default":5432,"in":"query"}]}},"\/migrations\/{migrationId}":{"get":{"summary":"Get Migration","operationId":"migrationsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"migrations\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/get-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration unique ID.","required":true,"type":"string","x-example":"[MIGRATION_ID]","in":"path"}]},"patch":{"summary":"Retry Migration","operationId":"migrationsRetry","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"retry","cookies":false,"type":"","demo":"migrations\/retry.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/retry-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration unique ID.","required":true,"type":"string","x-example":"[MIGRATION_ID]","in":"path"}]},"delete":{"summary":"Delete Migration","operationId":"migrationsDelete","consumes":["application\/json"],"produces":[],"tags":["migrations"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"migrations\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration ID.","required":true,"type":"string","x-example":"[MIGRATION_ID]","in":"path"}]}},"\/project\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"","responses":{"200":{"description":"UsageProject","schema":{"$ref":"#\/definitions\/usageProject"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"project\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/project\/variables":{"get":{"summary":"List Variables","operationId":"projectListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"Get a list of all project variables. These variables will be accessible in all Appwrite Functions at runtime.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","cookies":false,"type":"","demo":"project\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]},"post":{"summary":"Create Variable","operationId":"projectCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"Create a new project variable. This variable will be accessible in all Appwrite Functions at runtime.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","cookies":false,"type":"","demo":"project\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/project\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"projectGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"Get a project variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","cookies":false,"type":"","demo":"project\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"projectUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"Update project variable by its unique ID. This variable will be accessible in all Appwrite Functions at runtime.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","cookies":false,"type":"","demo":"project\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"projectDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["project"],"description":"Delete a project variable by its unique ID. ","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","cookies":false,"type":"","demo":"project\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/projects":{"get":{"summary":"List Projects","operationId":"projectsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Projects List","schema":{"$ref":"#\/definitions\/projectList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"projects\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Project","operationId":"projectsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"projects\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"projectId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":null},"name":{"type":"string","description":"Project name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"teamId":{"type":"string","description":"Team unique ID.","default":null,"x-example":"[TEAM_ID]"},"region":{"type":"string","description":"Project Region.","default":"default","x-example":"default","enum":["default"],"x-enum-name":null,"x-enum-keys":[]},"description":{"type":"string","description":"Project description. Max length: 256 chars.","default":"","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","default":"","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","default":"","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal Name. Max length: 256 chars.","default":"","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal Country. Max length: 256 chars.","default":"","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal State. Max length: 256 chars.","default":"","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal City. Max length: 256 chars.","default":"","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal Address. Max length: 256 chars.","default":"","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal Tax ID. Max length: 256 chars.","default":"","x-example":"[LEGAL_TAX_ID]"}},"required":["projectId","name","teamId"]}}]}},"\/projects\/{projectId}":{"get":{"summary":"Get Project","operationId":"projectsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"projects\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"patch":{"summary":"Update Project","operationId":"projectsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"projects\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","default":"","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","default":"","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","default":"","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal name. Max length: 256 chars.","default":"","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal country. Max length: 256 chars.","default":"","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal state. Max length: 256 chars.","default":"","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal city. Max length: 256 chars.","default":"","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal address. Max length: 256 chars.","default":"","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal tax ID. Max length: 256 chars.","default":"","x-example":"[LEGAL_TAX_ID]"}},"required":["name"]}}]},"delete":{"summary":"Delete Project","operationId":"projectsDelete","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"projects\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]}},"\/projects\/{projectId}\/auth\/duration":{"patch":{"summary":"Update Project Authentication Duration","operationId":"projectsUpdateAuthDuration","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthDuration","cookies":false,"type":"","demo":"projects\/update-auth-duration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"duration":{"type":"integer","description":"Project session length in seconds. Max length: 31536000 seconds.","default":null,"x-example":0}},"required":["duration"]}}]}},"\/projects\/{projectId}\/auth\/limit":{"patch":{"summary":"Update Project users limit","operationId":"projectsUpdateAuthLimit","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthLimit","cookies":false,"type":"","demo":"projects\/update-auth-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Use 0 for unlimited.","default":null,"x-example":0}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/max-sessions":{"patch":{"summary":"Update Project user sessions limit","operationId":"projectsUpdateAuthSessionsLimit","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthSessionsLimit","cookies":false,"type":"","demo":"projects\/update-auth-sessions-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10","default":null,"x-example":1}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/password-dictionary":{"patch":{"summary":"Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password","operationId":"projectsUpdateAuthPasswordDictionary","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthPasswordDictionary","cookies":false,"type":"","demo":"projects\/update-auth-password-dictionary.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to enable checking user's password against most commonly used passwords. Default is false.","default":null,"x-example":false}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/auth\/password-history":{"patch":{"summary":"Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.","operationId":"projectsUpdateAuthPasswordHistory","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthPasswordHistory","cookies":false,"type":"","demo":"projects\/update-auth-password-history.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0","default":null,"x-example":0}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/personal-data":{"patch":{"summary":"Enable or disable checking user passwords for similarity with their personal data.","operationId":"projectsUpdatePersonalDataCheck","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updatePersonalDataCheck","cookies":false,"type":"","demo":"projects\/update-personal-data-check.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to check a password for similarity with personal data. Default is false.","default":null,"x-example":false}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/auth\/{method}":{"patch":{"summary":"Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.","operationId":"projectsUpdateAuthStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthStatus","cookies":false,"type":"","demo":"projects\/update-auth-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"method","description":"Auth Method. Possible values: email-password,magic-url,anonymous,invites,jwt,phone","required":true,"type":"string","x-example":"email-password","enum":["email-password","magic-url","anonymous","invites","jwt","phone"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Set the status of this auth method.","default":null,"x-example":false}},"required":["status"]}}]}},"\/projects\/{projectId}\/keys":{"get":{"summary":"List Keys","operationId":"projectsListKeys","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"API Keys List","schema":{"$ref":"#\/definitions\/keyList"}}},"x-appwrite":{"method":"listKeys","cookies":false,"type":"","demo":"projects\/list-keys.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Key","operationId":"projectsCreateKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"createKey","cookies":false,"type":"","demo":"projects\/create-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 scopes are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","default":null,"x-example":null}},"required":["name","scopes"]}}]}},"\/projects\/{projectId}\/keys\/{keyId}":{"get":{"summary":"Get Key","operationId":"projectsGetKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"getKey","cookies":false,"type":"","demo":"projects\/get-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"}]},"put":{"summary":"Update Key","operationId":"projectsUpdateKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"updateKey","cookies":false,"type":"","demo":"projects\/update-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","default":null,"x-example":null}},"required":["name","scopes"]}}]},"delete":{"summary":"Delete Key","operationId":"projectsDeleteKey","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteKey","cookies":false,"type":"","demo":"projects\/delete-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"}]}},"\/projects\/{projectId}\/oauth2":{"patch":{"summary":"Update Project OAuth2","operationId":"projectsUpdateOAuth2","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateOAuth2","cookies":false,"type":"","demo":"projects\/update-o-auth2.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"provider":{"type":"string","description":"Provider Name","default":null,"x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":null,"x-enum-keys":[]},"appId":{"type":"string","description":"Provider app ID. Max length: 256 chars.","default":null,"x-example":"[APP_ID]"},"secret":{"type":"string","description":"Provider secret key. Max length: 512 chars.","default":null,"x-example":"[SECRET]"},"enabled":{"type":"boolean","description":"Provider status. Set to 'false' to disable new session creation.","default":null,"x-example":false}},"required":["provider"]}}]}},"\/projects\/{projectId}\/platforms":{"get":{"summary":"List Platforms","operationId":"projectsListPlatforms","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platforms List","schema":{"$ref":"#\/definitions\/platformList"}}},"x-appwrite":{"method":"listPlatforms","cookies":false,"type":"","demo":"projects\/list-platforms.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Platform","operationId":"projectsCreatePlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"createPlatform","cookies":false,"type":"","demo":"projects\/create-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"type":{"type":"string","description":"Platform type.","default":null,"x-example":"web","enum":["web","flutter-web","flutter-ios","flutter-android","flutter-linux","flutter-macos","flutter-windows","apple-ios","apple-macos","apple-watchos","apple-tvos","android","unity"],"x-enum-name":"PlatformType","x-enum-keys":[]},"name":{"type":"string","description":"Platform name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"key":{"type":"string","description":"Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.","default":"","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","default":"","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client hostname. Max length: 256 chars.","default":"","x-example":null}},"required":["type","name"]}}]}},"\/projects\/{projectId}\/platforms\/{platformId}":{"get":{"summary":"Get Platform","operationId":"projectsGetPlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"getPlatform","cookies":false,"type":"","demo":"projects\/get-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"}]},"put":{"summary":"Update Platform","operationId":"projectsUpdatePlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"updatePlatform","cookies":false,"type":"","demo":"projects\/update-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Platform name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"key":{"type":"string","description":"Package name for android or bundle ID for iOS. Max length: 256 chars.","default":"","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","default":"","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client URL. Max length: 256 chars.","default":"","x-example":null}},"required":["name"]}}]},"delete":{"summary":"Delete Platform","operationId":"projectsDeletePlatform","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deletePlatform","cookies":false,"type":"","demo":"projects\/delete-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"}]}},"\/projects\/{projectId}\/service":{"patch":{"summary":"Update service status","operationId":"projectsUpdateServiceStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateServiceStatus","cookies":false,"type":"","demo":"projects\/update-service-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"service":{"type":"string","description":"Service name.","default":null,"x-example":"account","enum":["account","avatars","databases","locale","health","storage","teams","users","vcs","functions","proxy","graphql","migrations"],"x-enum-name":null,"x-enum-keys":[]},"status":{"type":"boolean","description":"Service status.","default":null,"x-example":false}},"required":["service","status"]}}]}},"\/projects\/{projectId}\/service\/all":{"patch":{"summary":"Update all service status","operationId":"projectsUpdateServiceStatusAll","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateServiceStatusAll","cookies":false,"type":"","demo":"projects\/update-service-status-all.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Service status.","default":null,"x-example":false}},"required":["status"]}}]}},"\/projects\/{projectId}\/smtp":{"patch":{"summary":"Update SMTP configuration","operationId":"projectsUpdateSmtpConfiguration","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateSmtpConfiguration","cookies":false,"type":"","demo":"projects\/update-smtp-configuration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable custom SMTP service","default":null,"x-example":false},"senderName":{"type":"string","description":"Name of the email sender","default":"","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","default":"","x-example":"email@example.com"},"replyTo":{"type":"string","description":"Reply to email","default":"","x-example":"email@example.com"},"host":{"type":"string","description":"SMTP server host name","default":"","x-example":null},"port":{"type":"integer","description":"SMTP server port","default":587,"x-example":null},"username":{"type":"string","description":"SMTP server username","default":"","x-example":"[USERNAME]"},"password":{"type":"string","description":"SMTP server password","default":"","x-example":"[PASSWORD]"},"secure":{"type":"string","description":"Does SMTP server use secure connection","default":"","x-example":"tls","enum":["tls"],"x-enum-name":null,"x-enum-keys":[]}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/team":{"patch":{"summary":"Update Project Team","operationId":"projectsUpdateTeam","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateTeam","cookies":false,"type":"","demo":"projects\/update-team.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID of the team to transfer project to.","default":null,"x-example":"[TEAM_ID]"}},"required":["teamId"]}}]}},"\/projects\/{projectId}\/templates\/email\/{type}\/{locale}":{"get":{"summary":"Get custom email template","operationId":"projectsGetEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","schema":{"$ref":"#\/definitions\/emailTemplate"}}},"x-appwrite":{"method":"getEmailTemplate","cookies":false,"type":"","demo":"projects\/get-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]},"patch":{"summary":"Update custom email templates","operationId":"projectsUpdateEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateEmailTemplate","cookies":false,"type":"","demo":"projects\/update-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"subject":{"type":"string","description":"Email Subject","default":null,"x-example":"[SUBJECT]"},"message":{"type":"string","description":"Template message","default":null,"x-example":"[MESSAGE]"},"senderName":{"type":"string","description":"Name of the email sender","default":"","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","default":"","x-example":"email@example.com"},"replyTo":{"type":"string","description":"Reply to email","default":"","x-example":"email@example.com"}},"required":["subject","message"]}}]},"delete":{"summary":"Reset custom email template","operationId":"projectsDeleteEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","schema":{"$ref":"#\/definitions\/emailTemplate"}}},"x-appwrite":{"method":"deleteEmailTemplate","cookies":false,"type":"","demo":"projects\/delete-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]}},"\/projects\/{projectId}\/templates\/sms\/{type}\/{locale}":{"get":{"summary":"Get custom SMS template","operationId":"projectsGetSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"getSmsTemplate","cookies":false,"type":"","demo":"projects\/get-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]},"patch":{"summary":"Update custom SMS template","operationId":"projectsUpdateSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"updateSmsTemplate","cookies":false,"type":"","demo":"projects\/update-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"message":{"type":"string","description":"Template message","default":null,"x-example":"[MESSAGE]"}},"required":["message"]}}]},"delete":{"summary":"Reset custom SMS template","operationId":"projectsDeleteSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"deleteSmsTemplate","cookies":false,"type":"","demo":"projects\/delete-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]}},"\/projects\/{projectId}\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectsGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"UsageProject","schema":{"$ref":"#\/definitions\/usageProject"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"projects\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/projects\/{projectId}\/webhooks":{"get":{"summary":"List Webhooks","operationId":"projectsListWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhooks List","schema":{"$ref":"#\/definitions\/webhookList"}}},"x-appwrite":{"method":"listWebhooks","cookies":false,"type":"","demo":"projects\/list-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Webhook","operationId":"projectsCreateWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"createWebhook","cookies":false,"type":"","demo":"projects\/create-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","default":null,"x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","default":null,"x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","default":"","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","default":"","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}":{"get":{"summary":"Get Webhook","operationId":"projectsGetWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"getWebhook","cookies":false,"type":"","demo":"projects\/get-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]},"put":{"summary":"Update Webhook","operationId":"projectsUpdateWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"updateWebhook","cookies":false,"type":"","demo":"projects\/update-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","default":null,"x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","default":null,"x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","default":"","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","default":"","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}]},"delete":{"summary":"Delete Webhook","operationId":"projectsDeleteWebhook","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteWebhook","cookies":false,"type":"","demo":"projects\/delete-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}\/signature":{"patch":{"summary":"Update Webhook Signature Key","operationId":"projectsUpdateWebhookSignature","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"updateWebhookSignature","cookies":false,"type":"","demo":"projects\/update-webhook-signature.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]}},"\/proxy\/rules":{"get":{"summary":"List Rules","operationId":"proxyListRules","consumes":["application\/json"],"produces":["application\/json"],"tags":["proxy"],"description":"Get a list of all the proxy rules. You can use the query params to filter your results.","responses":{"200":{"description":"Rule List","schema":{"$ref":"#\/definitions\/proxyRuleList"}}},"x-appwrite":{"method":"listRules","cookies":false,"type":"","demo":"proxy\/list-rules.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/list-rules.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: domain, resourceType, resourceId, url","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Rule","operationId":"proxyCreateRule","consumes":["application\/json"],"produces":["application\/json"],"tags":["proxy"],"description":"Create a new proxy rule.","responses":{"201":{"description":"Rule","schema":{"$ref":"#\/definitions\/proxyRule"}}},"x-appwrite":{"method":"createRule","cookies":false,"type":"","demo":"proxy\/create-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/create-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain name.","default":null,"x-example":null},"resourceType":{"type":"string","description":"Action definition for the rule. Possible values are \"api\", \"function\"","default":null,"x-example":"api","enum":["api","function"],"x-enum-name":null,"x-enum-keys":[]},"resourceId":{"type":"string","description":"ID of resource for the action type. If resourceType is \"api\", leave empty. If resourceType is \"function\", provide ID of the function.","default":"","x-example":"[RESOURCE_ID]"}},"required":["domain","resourceType"]}}]}},"\/proxy\/rules\/{ruleId}":{"get":{"summary":"Get Rule","operationId":"proxyGetRule","consumes":["application\/json"],"produces":["application\/json"],"tags":["proxy"],"description":"Get a proxy rule by its unique ID.","responses":{"200":{"description":"Rule","schema":{"$ref":"#\/definitions\/proxyRule"}}},"x-appwrite":{"method":"getRule","cookies":false,"type":"","demo":"proxy\/get-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/get-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"type":"string","x-example":"[RULE_ID]","in":"path"}]},"delete":{"summary":"Delete Rule","operationId":"proxyDeleteRule","consumes":["application\/json"],"produces":[],"tags":["proxy"],"description":"Delete a proxy rule by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteRule","cookies":false,"type":"","demo":"proxy\/delete-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/delete-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"type":"string","x-example":"[RULE_ID]","in":"path"}]}},"\/proxy\/rules\/{ruleId}\/verification":{"patch":{"summary":"Update Rule Verification Status","operationId":"proxyUpdateRuleVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["proxy"],"description":"","responses":{"200":{"description":"Rule","schema":{"$ref":"#\/definitions\/proxyRule"}}},"x-appwrite":{"method":"updateRuleVerification","cookies":false,"type":"","demo":"proxy\/update-rule-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"type":"string","x-example":"[RULE_ID]","in":"path"}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","schema":{"$ref":"#\/definitions\/bucketList"}}},"x-appwrite":{"method":"listBuckets","cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"createBucket","cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","default":30000000,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["bucketId","name"]}}]}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"getBucket","cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"updateBucket","cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","default":null,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/usage":{"get":{"summary":"Get usage stats for storage","operationId":"storageGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"","responses":{"200":{"description":"StorageUsage","schema":{"$ref":"#\/definitions\/usageStorage"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"storage\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/storage\/{bucketId}\/usage":{"get":{"summary":"Get usage stats for a storage bucket","operationId":"storageGetBucketUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"","responses":{"200":{"description":"UsageBuckets","schema":{"$ref":"#\/definitions\/usageBuckets"}}},"x-appwrite":{"method":"getBucketUsage","cookies":false,"type":"","demo":"storage\/get-bucket-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"bucketId","description":"Bucket ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/logs":{"get":{"summary":"List Team Logs","operationId":"teamsListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"teams\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembership","cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","schema":{"$ref":"#\/definitions\/userList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","default":"","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId"]}}]}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createArgon2User","cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createBcryptUser","cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/identities":{"get":{"summary":"List Identities","operationId":"usersListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get identities for all users.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","cookies":false,"type":"","demo":"users\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]}},"\/users\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"usersDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","cookies":false,"type":"","demo":"users\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createMD5User","cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createPHPassUser","cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptUser","cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","default":null,"x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","default":null,"x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","default":null,"x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}]}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptModifiedUser","cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","default":null,"x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","default":null,"x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}]}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createSHAUser","cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","default":null,"x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","default":"","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/usage":{"get":{"summary":"Get usage stats for the users API","operationId":"usersGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"","responses":{"200":{"description":"UsageUsers","schema":{"$ref":"#\/definitions\/usageUsers"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"users\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"},{"name":"provider","description":"Provider Name.","required":false,"type":"string","x-example":"email","default":"","in":"query"}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"}},"required":["email"]}}]}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateLabels","cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["labels"]}}]}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null}},"required":["password"]}}]}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","default":null,"x-example":"+12065550100"}},"required":["number"]}}]}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","default":null,"x-example":false}},"required":["status"]}}]}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmailVerification","cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","default":null,"x-example":false}},"required":["emailVerification"]}}]}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhoneVerification","cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","default":null,"x-example":false}},"required":["phoneVerification"]}}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories":{"get":{"summary":"List Repositories","operationId":"vcsListRepositories","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Provider Repositories List","schema":{"$ref":"#\/definitions\/providerRepositoryList"}}},"x-appwrite":{"method":"listRepositories","cookies":false,"type":"","demo":"vcs\/list-repositories.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create repository","operationId":"vcsCreateRepository","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"ProviderRepository","schema":{"$ref":"#\/definitions\/providerRepository"}}},"x-appwrite":{"method":"createRepository","cookies":false,"type":"","demo":"vcs\/create-repository.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Repository name (slug)","default":null,"x-example":"[NAME]"},"private":{"type":"boolean","description":"Mark repository public or private","default":null,"x-example":false}},"required":["name","private"]}}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}":{"get":{"summary":"Get repository","operationId":"vcsGetRepository","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"ProviderRepository","schema":{"$ref":"#\/definitions\/providerRepository"}}},"x-appwrite":{"method":"getRepository","cookies":false,"type":"","demo":"vcs\/get-repository.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]","in":"path"}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/branches":{"get":{"summary":"List Repository Branches","operationId":"vcsListRepositoryBranches","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Branches List","schema":{"$ref":"#\/definitions\/branchList"}}},"x-appwrite":{"method":"listRepositoryBranches","cookies":false,"type":"","demo":"vcs\/list-repository-branches.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]","in":"path"}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/detection":{"post":{"summary":"Detect runtime settings from source code","operationId":"vcsCreateRepositoryDetection","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Detection","schema":{"$ref":"#\/definitions\/detection"}}},"x-appwrite":{"method":"createRepositoryDetection","cookies":false,"type":"","demo":"vcs\/create-repository-detection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"providerRootDirectory":{"type":"string","description":"Path to Root Directory","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"}}}}]}},"\/vcs\/github\/installations\/{installationId}\/repositories\/{repositoryId}":{"patch":{"summary":"Authorize external deployment","operationId":"vcsUpdateExternalDeployments","consumes":["application\/json"],"produces":[],"tags":["vcs"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"updateExternalDeployments","cookies":false,"type":"","demo":"vcs\/update-external-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"repositoryId","description":"VCS Repository Id","required":true,"type":"string","x-example":"[REPOSITORY_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"providerPullRequestId":{"type":"string","description":"GitHub Pull Request Id","default":null,"x-example":"[PROVIDER_PULL_REQUEST_ID]"}},"required":["providerPullRequestId"]}}]}},"\/vcs\/installations":{"get":{"summary":"List installations","operationId":"vcsListInstallations","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Installations List","schema":{"$ref":"#\/definitions\/installationList"}}},"x-appwrite":{"method":"listInstallations","cookies":false,"type":"","demo":"vcs\/list-installations.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/list-installations.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: provider, organization","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]}},"\/vcs\/installations\/{installationId}":{"get":{"summary":"Get installation","operationId":"vcsGetInstallation","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Installation","schema":{"$ref":"#\/definitions\/installation"}}},"x-appwrite":{"method":"getInstallation","cookies":false,"type":"","demo":"vcs\/get-installation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/get-installation.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"}]},"delete":{"summary":"Delete Installation","operationId":"vcsDeleteInstallation","consumes":["application\/json"],"produces":[],"tags":["vcs"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteInstallation","cookies":false,"type":"","demo":"vcs\/delete-installation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/delete-installation.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"type":"object","$ref":"#\/definitions\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"type":"object","$ref":"#\/definitions\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"type":"object","$ref":"#\/definitions\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"type":"object","$ref":"#\/definitions\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"type":"object","$ref":"#\/definitions\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"type":"object","$ref":"#\/definitions\/function"},"x-example":""}},"required":["total","functions"]},"installationList":{"description":"Installations List","type":"object","properties":{"total":{"type":"integer","description":"Total number of installations documents that matched your query.","x-example":5,"format":"int32"},"installations":{"type":"array","description":"List of installations.","items":{"type":"object","$ref":"#\/definitions\/installation"},"x-example":""}},"required":["total","installations"]},"providerRepositoryList":{"description":"Provider Repositories List","type":"object","properties":{"total":{"type":"integer","description":"Total number of providerRepositories documents that matched your query.","x-example":5,"format":"int32"},"providerRepositories":{"type":"array","description":"List of providerRepositories.","items":{"type":"object","$ref":"#\/definitions\/providerRepository"},"x-example":""}},"required":["total","providerRepositories"]},"branchList":{"description":"Branches List","type":"object","properties":{"total":{"type":"integer","description":"Total number of branches documents that matched your query.","x-example":5,"format":"int32"},"branches":{"type":"array","description":"List of branches.","items":{"type":"object","$ref":"#\/definitions\/branch"},"x-example":""}},"required":["total","branches"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"type":"object","$ref":"#\/definitions\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"type":"object","$ref":"#\/definitions\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"projectList":{"description":"Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"type":"object","$ref":"#\/definitions\/project"},"x-example":""}},"required":["total","projects"]},"webhookList":{"description":"Webhooks List","type":"object","properties":{"total":{"type":"integer","description":"Total number of webhooks documents that matched your query.","x-example":5,"format":"int32"},"webhooks":{"type":"array","description":"List of webhooks.","items":{"type":"object","$ref":"#\/definitions\/webhook"},"x-example":""}},"required":["total","webhooks"]},"keyList":{"description":"API Keys List","type":"object","properties":{"total":{"type":"integer","description":"Total number of keys documents that matched your query.","x-example":5,"format":"int32"},"keys":{"type":"array","description":"List of keys.","items":{"type":"object","$ref":"#\/definitions\/key"},"x-example":""}},"required":["total","keys"]},"platformList":{"description":"Platforms List","type":"object","properties":{"total":{"type":"integer","description":"Total number of platforms documents that matched your query.","x-example":5,"format":"int32"},"platforms":{"type":"array","description":"List of platforms.","items":{"type":"object","$ref":"#\/definitions\/platform"},"x-example":""}},"required":["total","platforms"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":""}},"required":["total","variables"]},"proxyRuleList":{"description":"Rule List","type":"object","properties":{"total":{"type":"integer","description":"Total number of rules documents that matched your query.","x-example":5,"format":"int32"},"rules":{"type":"array","description":"List of rules.","items":{"type":"object","$ref":"#\/definitions\/proxyRule"},"x-example":""}},"required":["total","rules"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"migrationList":{"description":"Migrations List","type":"object","properties":{"total":{"type":"integer","description":"Total number of migrations documents that matched your query.","x-example":5,"format":"int32"},"migrations":{"type":"array","description":"List of migrations.","items":{"type":"object","$ref":"#\/definitions\/migration"},"x-example":""}},"required":["total","migrations"]},"firebaseProjectList":{"description":"Migrations Firebase Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"type":"object","$ref":"#\/definitions\/firebaseProject"},"x-example":""}},"required":["total","projects"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"If database is enabled. Can be 'enabled' or 'disabled'. When disabled, the database is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled. Can be 'enabled' or 'disabled'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","x-nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","x-nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","x-nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","x-nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","x-nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","x-nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"x-nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"live":{"type":"boolean","description":"Is the function deployed with the latest configuration? This is set to false if you've changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":300,"format":"int32"},"entrypoint":{"type":"string","description":"The entrypoint file used to execute the deployment.","x-example":"index.js"},"commands":{"type":"string","description":"The build command used to build the deployment.","x-example":"npm install"},"version":{"type":"string","description":"Version of Open Runtimes used for the function.","x-example":"v2"},"installationId":{"type":"string","description":"Function VCS (Version Control System) installation id.","x-example":"6m40at4ejk5h2u9s1hboo"},"providerRepositoryId":{"type":"string","description":"VCS (Version Control System) Repository ID","x-example":"appwrite"},"providerBranch":{"type":"string","description":"VCS (Version Control System) branch name","x-example":"main"},"providerRootDirectory":{"type":"string","description":"Path to function in VCS (Version Control System) repository","x-example":"functions\/helloWorld"},"providerSilentMode":{"type":"boolean","description":"Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests","x-example":false}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","live","logging","runtime","deployment","vars","events","schedule","timeout","entrypoint","commands","version","installationId","providerRepositoryId","providerBranch","providerRootDirectory","providerSilentMode"]},"installation":{"description":"Installation","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"VCS (Version Control System) provider name.","x-example":"github"},"organization":{"type":"string","description":"VCS (Version Control System) organization name.","x-example":"appwrite"},"providerInstallationId":{"type":"string","description":"VCS (Version Control System) installation ID.","x-example":"5322"}},"required":["$id","$createdAt","$updatedAt","provider","organization","providerInstallationId"]},"providerRepository":{"description":"ProviderRepository","type":"object","properties":{"id":{"type":"string","description":"VCS (Version Control System) repository ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"VCS (Version Control System) repository name.","x-example":"appwrite"},"organization":{"type":"string","description":"VCS (Version Control System) organization name","x-example":"appwrite"},"provider":{"type":"string","description":"VCS (Version Control System) provider name.","x-example":"github"},"private":{"type":"boolean","description":"Is VCS (Version Control System) repository private?","x-example":true},"runtime":{"type":"string","description":"Auto-detected runtime suggestion. Empty if getting response of getRuntime().","x-example":"node"},"pushedAt":{"type":"string","description":"Last commit date in ISO 8601 format.","x-example":"datetime"}},"required":["id","name","organization","provider","private","runtime","pushedAt"]},"detection":{"description":"Detection","type":"object","properties":{"runtime":{"type":"string","description":"Runtime","x-example":"node"}},"required":["runtime"]},"branch":{"description":"Branch","type":"object","properties":{"name":{"type":"string","description":"Branch Name.","x-example":"main"}},"required":["name"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"type":{"type":"string","description":"Type of deployment.","x-example":"vcs"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"index.js"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"waiting\", \"ready\", and \"failed\".","x-example":"ready"},"buildLogs":{"type":"string","description":"The build logs.","x-example":"Compiling source files..."},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"},"providerRepositoryName":{"type":"string","description":"The name of the vcs provider repository","x-example":"database"},"providerRepositoryOwner":{"type":"string","description":"The name of the vcs provider repository owner","x-example":"utopia"},"providerRepositoryUrl":{"type":"string","description":"The url of the vcs provider repository","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function"},"providerBranch":{"type":"string","description":"The branch of the vcs repository","x-example":"0.7.x"},"providerCommitHash":{"type":"string","description":"The commit hash of the vcs commit","x-example":"7c3f25d"},"providerCommitAuthorUrl":{"type":"string","description":"The url of vcs commit author","x-example":"https:\/\/github.com\/vermakhushboo"},"providerCommitAuthor":{"type":"string","description":"The name of vcs commit author","x-example":"Khushboo Verma"},"providerCommitMessage":{"type":"string","description":"The commit message","x-example":"Update index.js"},"providerCommitUrl":{"type":"string","description":"The url of the vcs commit","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function\/commit\/60c0416257a9cbcdd96b2d370c38d8f8d150ccfb"},"providerBranchUrl":{"type":"string","description":"The branch of the vcs repository","x-example":"https:\/\/github.com\/vermakhushboo\/appwrite\/tree\/0.7.x"}},"required":["$id","$createdAt","$updatedAt","type","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildLogs","buildTime","providerRepositoryName","providerRepositoryOwner","providerRepositoryUrl","providerBranch","providerCommitHash","providerCommitAuthorUrl","providerCommitAuthor","providerCommitMessage","providerCommitUrl","providerBranchUrl"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"project":{"description":"Project","type":"object","properties":{"$id":{"type":"string","description":"Project ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Project creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Project update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Project name.","x-example":"New Project"},"description":{"type":"string","description":"Project description.","x-example":"This is a new project."},"teamId":{"type":"string","description":"Project team ID.","x-example":"1592981250"},"logo":{"type":"string","description":"Project logo file ID.","x-example":"5f5c451b403cb"},"url":{"type":"string","description":"Project website URL.","x-example":"5f5c451b403cb"},"legalName":{"type":"string","description":"Company legal name.","x-example":"Company LTD."},"legalCountry":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format.","x-example":"US"},"legalState":{"type":"string","description":"State name.","x-example":"New York"},"legalCity":{"type":"string","description":"City name.","x-example":"New York City."},"legalAddress":{"type":"string","description":"Company Address.","x-example":"620 Eighth Avenue, New York, NY 10018"},"legalTaxId":{"type":"string","description":"Company Tax ID.","x-example":"131102020"},"authDuration":{"type":"integer","description":"Session duration in seconds.","x-example":60,"format":"int32"},"authLimit":{"type":"integer","description":"Max users allowed. 0 is unlimited.","x-example":100,"format":"int32"},"authSessionsLimit":{"type":"integer","description":"Max sessions allowed per user. 100 maximum.","x-example":10,"format":"int32"},"authPasswordHistory":{"type":"integer","description":"Max allowed passwords in the history list per user. Max passwords limit allowed in history is 20. Use 0 for disabling password history.","x-example":5,"format":"int32"},"authPasswordDictionary":{"type":"boolean","description":"Whether or not to check user's password against most commonly used passwords.","x-example":true},"authPersonalDataCheck":{"type":"boolean","description":"Whether or not to check the user password for similarity with their personal data.","x-example":true},"providers":{"type":"array","description":"List of Providers.","items":{"type":"object","$ref":"#\/definitions\/provider"},"x-example":[{}]},"platforms":{"type":"array","description":"List of Platforms.","items":{"type":"object","$ref":"#\/definitions\/platform"},"x-example":{}},"webhooks":{"type":"array","description":"List of Webhooks.","items":{"type":"object","$ref":"#\/definitions\/webhook"},"x-example":{}},"keys":{"type":"array","description":"List of API Keys.","items":{"type":"object","$ref":"#\/definitions\/key"},"x-example":{}},"smtpEnabled":{"type":"boolean","description":"Status for custom SMTP","x-example":false},"smtpSenderName":{"type":"string","description":"SMTP sender name","x-example":"John Appwrite"},"smtpSenderEmail":{"type":"string","description":"SMTP sender email","x-example":"john@appwrite.io"},"smtpReplyTo":{"type":"string","description":"SMTP reply to email","x-example":"support@appwrite.io"},"smtpHost":{"type":"string","description":"SMTP server host name","x-example":"mail.appwrite.io"},"smtpPort":{"type":"integer","description":"SMTP server port","x-example":25,"format":"int32"},"smtpUsername":{"type":"string","description":"SMTP server username","x-example":"emailuser"},"smtpPassword":{"type":"string","description":"SMTP server password","x-example":"securepassword"},"smtpSecure":{"type":"string","description":"SMTP server secure protocol","x-example":"tls"},"authEmailPassword":{"type":"boolean","description":"Email\/Password auth method status","x-example":true},"authUsersAuthMagicURL":{"type":"boolean","description":"Magic URL auth method status","x-example":true},"authAnonymous":{"type":"boolean","description":"Anonymous auth method status","x-example":true},"authInvites":{"type":"boolean","description":"Invites auth method status","x-example":true},"authJWT":{"type":"boolean","description":"JWT auth method status","x-example":true},"authPhone":{"type":"boolean","description":"Phone auth method status","x-example":true},"serviceStatusForAccount":{"type":"boolean","description":"Account service status","x-example":true},"serviceStatusForAvatars":{"type":"boolean","description":"Avatars service status","x-example":true},"serviceStatusForDatabases":{"type":"boolean","description":"Databases service status","x-example":true},"serviceStatusForLocale":{"type":"boolean","description":"Locale service status","x-example":true},"serviceStatusForHealth":{"type":"boolean","description":"Health service status","x-example":true},"serviceStatusForStorage":{"type":"boolean","description":"Storage service status","x-example":true},"serviceStatusForTeams":{"type":"boolean","description":"Teams service status","x-example":true},"serviceStatusForUsers":{"type":"boolean","description":"Users service status","x-example":true},"serviceStatusForVcs":{"type":"boolean","description":"VCS service status","x-example":true},"serviceStatusForFunctions":{"type":"boolean","description":"Functions service status","x-example":true},"serviceStatusForProxy":{"type":"boolean","description":"Proxy service status","x-example":true},"serviceStatusForGraphql":{"type":"boolean","description":"GraphQL service status","x-example":true},"serviceStatusForMigrations":{"type":"boolean","description":"Migrations service status","x-example":true}},"required":["$id","$createdAt","$updatedAt","name","description","teamId","logo","url","legalName","legalCountry","legalState","legalCity","legalAddress","legalTaxId","authDuration","authLimit","authSessionsLimit","authPasswordHistory","authPasswordDictionary","authPersonalDataCheck","providers","platforms","webhooks","keys","smtpEnabled","smtpSenderName","smtpSenderEmail","smtpReplyTo","smtpHost","smtpPort","smtpUsername","smtpPassword","smtpSecure","authEmailPassword","authUsersAuthMagicURL","authAnonymous","authInvites","authJWT","authPhone","serviceStatusForAccount","serviceStatusForAvatars","serviceStatusForDatabases","serviceStatusForLocale","serviceStatusForHealth","serviceStatusForStorage","serviceStatusForTeams","serviceStatusForUsers","serviceStatusForVcs","serviceStatusForFunctions","serviceStatusForProxy","serviceStatusForGraphql","serviceStatusForMigrations"]},"webhook":{"description":"Webhook","type":"object","properties":{"$id":{"type":"string","description":"Webhook ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Webhook creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Webhook update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Webhook name.","x-example":"My Webhook"},"url":{"type":"string","description":"Webhook URL endpoint.","x-example":"https:\/\/example.com\/webhook"},"events":{"type":"array","description":"Webhook trigger events.","items":{"type":"string"},"x-example":"database.collections.update"},"security":{"type":"boolean","description":"Indicated if SSL \/ TLS Certificate verification is enabled.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"},"signatureKey":{"type":"string","description":"Signature key which can be used to validated incoming","x-example":"ad3d581ca230e2b7059c545e5a"}},"required":["$id","$createdAt","$updatedAt","name","url","events","security","httpUser","httpPass","signatureKey"]},"key":{"description":"Key","type":"object","properties":{"$id":{"type":"string","description":"Key ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Key creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Key update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Key name.","x-example":"My API Key"},"expire":{"type":"string","description":"Key expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"scopes":{"type":"array","description":"Allowed permission scopes.","items":{"type":"string"},"x-example":"users.read"},"secret":{"type":"string","description":"Secret key.","x-example":"919c2d18fb5d4...a2ae413da83346ad2"},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"},"sdks":{"type":"array","description":"List of SDK user agents that used this key.","items":{"type":"string"},"x-example":"appwrite:flutter"}},"required":["$id","$createdAt","$updatedAt","name","expire","scopes","secret","accessedAt","sdks"]},"provider":{"description":"Provider","type":"object","properties":{"key":{"type":"string","description":"Provider.","x-example":"github"},"name":{"type":"string","description":"Provider name.","x-example":"GitHub"},"appId":{"type":"string","description":"OAuth 2.0 application ID.","x-example":"259125845563242502"},"secret":{"type":"string","description":"OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.","x-example":"Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ"},"enabled":{"type":"boolean","description":"Provider is active and can be used to create session.","x-example":""}},"required":["key","name","appId","secret","enabled"]},"platform":{"description":"Platform","type":"object","properties":{"$id":{"type":"string","description":"Platform ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Platform creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Platform update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Platform name.","x-example":"My Web App"},"type":{"type":"string","description":"Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, and unity.","x-example":"web"},"key":{"type":"string","description":"Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.","x-example":"com.company.appname"},"store":{"type":"string","description":"App store or Google Play store ID.","x-example":""},"hostname":{"type":"string","description":"Web app hostname. Empty string for other platforms.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"}},"required":["$id","$createdAt","$updatedAt","name","type","key","store","hostname","httpUser","httpPass"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"resourceType":{"type":"string","description":"Service to which the variable belongs. Possible values are \"project\", \"function\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource to which the variable belongs. If resourceType is \"project\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"}},"required":["$id","$createdAt","$updatedAt","key","value","resourceType","resourceId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"metric":{"description":"Metric","type":"object","properties":{"value":{"type":"integer","description":"The value of this metric at the timestamp.","x-example":1,"format":"int32"},"date":{"type":"string","description":"The date at which this metric was aggregated in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["value","date"]},"usageDatabases":{"description":"UsageDatabases","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"databasesCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsCount":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesDelete":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsCreate":{"type":"array","description":"Aggregated stats for collections created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsRead":{"type":"array","description":"Aggregated stats for collections read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsUpdate":{"type":"array","description":"Aggregated stats for collections updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsDelete":{"type":"array","description":"Aggregated stats for collections delete.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","databasesCount","documentsCount","collectionsCount","databasesCreate","databasesRead","databasesUpdate","databasesDelete","documentsCreate","documentsRead","documentsUpdate","documentsDelete","collectionsCreate","collectionsRead","collectionsUpdate","collectionsDelete"]},"usageDatabase":{"description":"UsageDatabase","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsCount":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsCreate":{"type":"array","description":"Aggregated stats for collections created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsRead":{"type":"array","description":"Aggregated stats for collections read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsUpdate":{"type":"array","description":"Aggregated stats for collections updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsDelete":{"type":"array","description":"Aggregated stats for collections delete.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","documentsCount","collectionsCount","documentsCreate","documentsRead","documentsUpdate","documentsDelete","collectionsCreate","collectionsRead","collectionsUpdate","collectionsDelete"]},"usageCollection":{"description":"UsageCollection","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","documentsCount","documentsCreate","documentsRead","documentsUpdate","documentsDelete"]},"usageUsers":{"description":"UsageUsers","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"usersCount":{"type":"array","description":"Aggregated stats for total number of users.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersCreate":{"type":"array","description":"Aggregated stats for users created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersRead":{"type":"array","description":"Aggregated stats for users read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersUpdate":{"type":"array","description":"Aggregated stats for users updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersDelete":{"type":"array","description":"Aggregated stats for users deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"sessionsCreate":{"type":"array","description":"Aggregated stats for sessions created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"sessionsProviderCreate":{"type":"array","description":"Aggregated stats for sessions created for a provider ( email, anonymous or oauth2 ).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"sessionsDelete":{"type":"array","description":"Aggregated stats for sessions deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","usersCount","usersCreate","usersRead","usersUpdate","usersDelete","sessionsCreate","sessionsProviderCreate","sessionsDelete"]},"usageStorage":{"description":"StorageUsage","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"storage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesCount":{"type":"array","description":"Aggregated stats for total number of files.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsCount":{"type":"array","description":"Aggregated stats for total number of buckets.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsCreate":{"type":"array","description":"Aggregated stats for buckets created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsRead":{"type":"array","description":"Aggregated stats for buckets read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsUpdate":{"type":"array","description":"Aggregated stats for buckets updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsDelete":{"type":"array","description":"Aggregated stats for buckets deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesCreate":{"type":"array","description":"Aggregated stats for files created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesRead":{"type":"array","description":"Aggregated stats for files read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesUpdate":{"type":"array","description":"Aggregated stats for files updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesDelete":{"type":"array","description":"Aggregated stats for files deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","storage","filesCount","bucketsCount","bucketsCreate","bucketsRead","bucketsUpdate","bucketsDelete","filesCreate","filesRead","filesUpdate","filesDelete"]},"usageBuckets":{"description":"UsageBuckets","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"filesCount":{"type":"array","description":"Aggregated stats for total number of files in this bucket.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for total storage of files in this bucket.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesCreate":{"type":"array","description":"Aggregated stats for files created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesRead":{"type":"array","description":"Aggregated stats for files read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesUpdate":{"type":"array","description":"Aggregated stats for files updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesDelete":{"type":"array","description":"Aggregated stats for files deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","filesCount","filesStorage","filesCreate","filesRead","filesUpdate","filesDelete"]},"usageFunctions":{"description":"UsageFunctions","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"executionsTotal":{"type":"array","description":"Aggregated stats for number of function executions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsFailure":{"type":"array","description":"Aggregated stats for function execution failures.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsSuccess":{"type":"array","description":"Aggregated stats for function execution successes.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsTime":{"type":"array","description":"Aggregated stats for function execution duration.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsTotal":{"type":"array","description":"Aggregated stats for number of function builds.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsFailure":{"type":"array","description":"Aggregated stats for function build failures.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsSuccess":{"type":"array","description":"Aggregated stats for function build successes.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsTime":{"type":"array","description":"Aggregated stats for function build duration.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","executionsTotal","executionsFailure","executionsSuccess","executionsTime","buildsTotal","buildsFailure","buildsSuccess","buildsTime"]},"usageProject":{"description":"UsageProject","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"requests":{"type":"array","description":"Aggregated stats for number of requests.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"network":{"type":"array","description":"Aggregated stats for consumed bandwidth.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executions":{"type":"array","description":"Aggregated stats for function executions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documents":{"type":"array","description":"Aggregated stats for number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databases":{"type":"array","description":"Aggregated stats for number of databases.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"users":{"type":"array","description":"Aggregated stats for number of users.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"storage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buckets":{"type":"array","description":"Aggregated stats for number of buckets.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","requests","network","executions","documents","databases","users","storage","buckets"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]},"proxyRule":{"description":"Rule","type":"object","properties":{"$id":{"type":"string","description":"Rule ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Rule creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Rule update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"domain":{"type":"string","description":"Domain name.","x-example":"appwrite.company.com"},"resourceType":{"type":"string","description":"Action definition for the rule. Possible values are \"api\", \"function\", or \"redirect\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource for the action type. If resourceType is \"api\" or \"url\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"},"status":{"type":"string","description":"Domain verification status. Possible values are \"created\", \"verifying\", \"verified\" and \"unverified\"","x-example":"verified"},"logs":{"type":"string","description":"Certificate generation logs. This will return an empty string if generation did not run, or succeeded.","x-example":"HTTP challegne failed."},"renewAt":{"type":"string","description":"Certificate auto-renewal date in ISO 8601 format.","x-example":"datetime"}},"required":["$id","$createdAt","$updatedAt","domain","resourceType","resourceId","status","logs","renewAt"]},"smsTemplate":{"description":"SmsTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."}},"required":["type","locale","message"]},"emailTemplate":{"description":"EmailTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."},"senderName":{"type":"string","description":"Name of the sender","x-example":"My User"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"mail@appwrite.io"},"replyTo":{"type":"string","description":"Reply to email address","x-example":"emails@appwrite.io"},"subject":{"type":"string","description":"Email subject","x-example":"Please verify your email address"}},"required":["type","locale","message","senderName","senderEmail","replyTo","subject"]},"consoleVariables":{"description":"Console Variables","type":"object","properties":{"_APP_DOMAIN_TARGET":{"type":"string","description":"CNAME target for your Appwrite custom domains.","x-example":"appwrite.io"},"_APP_STORAGE_LIMIT":{"type":"integer","description":"Maximum file size allowed for file upload in bytes.","x-example":"30000000","format":"int32"},"_APP_FUNCTIONS_SIZE_LIMIT":{"type":"integer","description":"Maximum file size allowed for deployment in bytes.","x-example":"30000000","format":"int32"},"_APP_USAGE_STATS":{"type":"string","description":"Defines if usage stats are enabled. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'.","x-example":"enabled"},"_APP_VCS_ENABLED":{"type":"boolean","description":"Defines if VCS (Version Control System) is enabled.","x-example":true},"_APP_DOMAIN_ENABLED":{"type":"boolean","description":"Defines if main domain is configured. If so, custom domains can be created.","x-example":true},"_APP_ASSISTANT_ENABLED":{"type":"boolean","description":"Defines if AI assistant is enabled.","x-example":true}},"required":["_APP_DOMAIN_TARGET","_APP_STORAGE_LIMIT","_APP_FUNCTIONS_SIZE_LIMIT","_APP_USAGE_STATS","_APP_VCS_ENABLED","_APP_DOMAIN_ENABLED","_APP_ASSISTANT_ENABLED"]},"migration":{"description":"Migration","type":"object","properties":{"$id":{"type":"string","description":"Migration ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"string","description":"Migration status ( pending, processing, failed, completed ) ","x-example":"pending"},"stage":{"type":"string","description":"Migration stage ( init, processing, source-check, destination-check, migrating, finished )","x-example":"init"},"source":{"type":"string","description":"A string containing the type of source of the migration.","x-example":"Appwrite"},"resources":{"type":"array","description":"Resources to migration.","items":{"type":"string"},"x-example":["user"]},"statusCounters":{"type":"object","additionalProperties":true,"description":"A group of counters that represent the total progress of the migration.","x-example":"{\"Database\": {\"PENDING\": 0, \"SUCCESS\": 1, \"ERROR\": 0, \"SKIP\": 0, \"PROCESSING\": 0, \"WARNING\": 0}}"},"resourceData":{"type":"object","additionalProperties":true,"description":"An array of objects containing the report data of the resources that were migrated.","x-example":"[{\"resource\":\"Database\",\"id\":\"public\",\"status\":\"SUCCESS\",\"message\":\"\"}]"},"errors":{"type":"string","description":"All errors that occurred during the migration process.","x-example":[]}},"required":["$id","$createdAt","$updatedAt","status","stage","source","resources","statusCounters","resourceData","errors"]},"migrationReport":{"description":"Migration Report","type":"object","properties":{"user":{"type":"integer","description":"Number of users to be migrated.","x-example":20,"format":"int32"},"team":{"type":"integer","description":"Number of teams to be migrated.","x-example":20,"format":"int32"},"database":{"type":"integer","description":"Number of databases to be migrated.","x-example":20,"format":"int32"},"document":{"type":"integer","description":"Number of documents to be migrated.","x-example":20,"format":"int32"},"file":{"type":"integer","description":"Number of files to be migrated.","x-example":20,"format":"int32"},"bucket":{"type":"integer","description":"Number of buckets to be migrated.","x-example":20,"format":"int32"},"function":{"type":"integer","description":"Number of functions to be migrated.","x-example":20,"format":"int32"},"size":{"type":"integer","description":"Size of files to be migrated in mb.","x-example":30000,"format":"int32"},"version":{"type":"string","description":"Version of the Appwrite instance to be migrated.","x-example":"1.4.0"}},"required":["user","team","database","document","file","bucket","function","size","version"]},"firebaseProject":{"description":"MigrationFirebaseProject","type":"object","properties":{"projectId":{"type":"string","description":"Project ID.","x-example":"my-project"},"displayName":{"type":"string","description":"Project display name.","x-example":"My Project"}},"required":["projectId","displayName"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/swagger2-1.4.x-server.json b/app/config/specs/swagger2-1.4.x-server.json index e7b1bedfee..fc50cbbe5b 100644 --- a/app/config/specs/swagger2-1.4.x-server.json +++ b/app/config/specs/swagger2-1.4.x-server.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","schema":{"$ref":"#\/definitions\/databaseList"}}},"x-appwrite":{"method":"list","weight":50,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"create","weight":49,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","default":true,"x-example":false}},"required":["databaseId","name"]}}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"get","weight":51,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"update","weight":53,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Database","operationId":"databasesDelete","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":54,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","schema":{"$ref":"#\/definitions\/collectionList"}}},"x-appwrite":{"method":"listCollections","weight":56,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"createCollection","weight":55,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","default":true,"x-example":false}},"required":["collectionId","name"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"getCollection","weight":57,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"updateCollection","weight":59,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":60,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","schema":{"$ref":"#\/definitions\/attributeList"}}},"x-appwrite":{"method":"listAttributes","weight":71,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"createBooleanAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"createEmailAttribute","weight":62,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"updateEmailAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"createEnumAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","elements","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"updateEnumAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"createFloatAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"updateFloatAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"createIntegerAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"createIpAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"updateIpAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","default":null,"x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","default":null,"x-example":"oneToOne"},"twoWay":{"type":"boolean","description":"Is Two Way?","default":false,"x-example":false},"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","default":null,"x-example":null},"onDelete":{"type":"string","description":"Constraints option","default":"restrict","x-example":"cascade"}},"required":["relatedCollectionId","type"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"createStringAttribute","weight":61,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","default":null,"x-example":1},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","size","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"updateStringAttribute","weight":73,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"createUrlAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"updateUrlAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","schema":{"x-oneOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]}}},"x-appwrite":{"method":"getAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","default":null,"x-example":"cascade"}}}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","schema":{"$ref":"#\/definitions\/indexList"}}},"x-appwrite":{"method":"listIndexes","weight":85,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"createIndex","weight":84,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","default":null,"x-example":null},"type":{"type":"string","description":"Index type.","default":null,"x-example":"key"},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","default":[],"x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"getIndex","weight":86,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":87,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","schema":{"$ref":"#\/definitions\/functionList"}}},"x-appwrite":{"method":"list","weight":222,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"create","weight":221,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","default":true,"x-example":false}},"required":["functionId","name","runtime"]}}]}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","schema":{"$ref":"#\/definitions\/runtimeList"}}},"x-appwrite":{"method":"listRuntimes","weight":223,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"get","weight":224,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"update","weight":227,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Function","operationId":"functionsDelete","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":229,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","schema":{"$ref":"#\/definitions\/deploymentList"}}},"x-appwrite":{"method":"listDeployments","weight":231,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: entrypoint, size, buildId, activate","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","consumes":["multipart\/form-data"],"produces":["application\/json"],"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](\/docs\/functions).\n\nUse the \"command\" param to set the entry point used to execute your code.","responses":{"202":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"createDeployment","weight":230,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"entrypoint","description":"Entrypoint File.","required":true,"type":"string","x-example":"[ENTRYPOINT]","in":"formData"},{"name":"code","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","required":true,"type":"file","in":"formData"},{"name":"activate","description":"Automatically activate the deployment when it is finished building.","required":true,"type":"boolean","x-example":false,"in":"formData"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"getDeployment","weight":232,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"updateDeployment","weight":228,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":233,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":234,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"type":"string","x-example":"[BUILD_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","default":"","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","default":false,"x-example":false}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","weight":239,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function variable. These variables can be accessed within function in the `env` object under the request variable.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","weight":238,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","weight":240,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","weight":241,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":242,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"get","weight":105,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","schema":{"$ref":"#\/definitions\/healthAntivirus"}}},"x-appwrite":{"method":"getAntivirus","weight":117,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getCache","weight":108,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getDB","weight":107,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getPubSub","weight":110,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getQueue","weight":109,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueCertificates","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueFunctions","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueLogs","weight":113,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueWebhooks","weight":112,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getStorageLocal","weight":116,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","schema":{"$ref":"#\/definitions\/healthTime"}}},"x-appwrite":{"method":"getTime","weight":111,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","schema":{"$ref":"#\/definitions\/bucketList"}}},"x-appwrite":{"method":"listBuckets","weight":165,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"createBucket","weight":164,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","default":30000000,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none"},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["bucketId","name"]}}]}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"getBucket","weight":166,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"updateBucket","weight":167,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","default":null,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none"},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":168,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","schema":{"$ref":"#\/definitions\/userList"}}},"x-appwrite":{"method":"list","weight":201,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":193,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","default":"","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId"]}}]}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createArgon2User","weight":196,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createBcryptUser","weight":194,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createMD5User","weight":195,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createPHPassUser","weight":198,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptUser","weight":199,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","default":null,"x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","default":null,"x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","default":null,"x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}]}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":200,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","default":null,"x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","default":null,"x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}]}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createSHAUser","weight":197,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","default":null,"x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","default":"","x-example":"sha1"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":202,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":219,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":213,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"}},"required":["email"]}}]}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateLabels","weight":208,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["labels"]}}]}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":206,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":205,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":211,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":212,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null}},"required":["password"]}}]}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":214,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","default":null,"x-example":"+12065550100"}},"required":["number"]}}]}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":203,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":216,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":204,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":218,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":217,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":207,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","default":null,"x-example":false}},"required":["status"]}}]}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmailVerification","weight":215,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","default":null,"x-example":false}},"required":["emailVerification"]}}]}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":210,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","default":null,"x-example":false}},"required":["phoneVerification"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"type":"object","$ref":"#\/definitions\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"type":"object","$ref":"#\/definitions\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"type":"object","$ref":"#\/definitions\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"type":"object","$ref":"#\/definitions\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"type":"object","$ref":"#\/definitions\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"type":"object","$ref":"#\/definitions\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"type":"object","$ref":"#\/definitions\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"Database enabled.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","x-nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","x-nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","x-nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","x-nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","x-nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","x-nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"x-nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":15,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","runtime","deployment","vars","events","schedule","timeout"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"enabled"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"pending\", \"ready\", and \"failed\".","x-example":"ready"},"buildStdout":{"type":"string","description":"The build stdout.","x-example":"enabled"},"buildStderr":{"type":"string","description":"The build stderr.","x-example":"enabled"},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildStdout","buildStderr","buildTime"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"}},"required":["$id","$createdAt","$updatedAt","key","value","functionId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":21,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":28,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","weight":13,"cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":14,"cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":24,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":26,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":27,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":29,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":22,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":30,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":35,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":36,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":23,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":34,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":25,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":33,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":32,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":31,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":39,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":40,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":47,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":46,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","schema":{"$ref":"#\/definitions\/databaseList"}}},"x-appwrite":{"method":"list","weight":52,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"create","weight":51,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["databaseId","name"]}}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"get","weight":53,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"update","weight":55,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Database","operationId":"databasesDelete","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":56,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","schema":{"$ref":"#\/definitions\/collectionList"}}},"x-appwrite":{"method":"listCollections","weight":58,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"createCollection","weight":57,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["collectionId","name"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"getCollection","weight":59,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"updateCollection","weight":61,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":62,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","schema":{"$ref":"#\/definitions\/attributeList"}}},"x-appwrite":{"method":"listAttributes","weight":73,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"createBooleanAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":71,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"createEmailAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"updateEmailAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"createEnumAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","elements","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"updateEnumAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"createFloatAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"updateFloatAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"createIntegerAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"createIpAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"updateIpAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","default":null,"x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","default":null,"x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","default":false,"x-example":false},"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","default":null,"x-example":null},"onDelete":{"type":"string","description":"Constraints option","default":"restrict","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"createStringAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","default":null,"x-example":1},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false},"encrypt":{"type":"boolean","description":"Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.","default":false,"x-example":false}},"required":["key","size","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"updateStringAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"createUrlAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"updateUrlAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","schema":{"x-oneOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]}}},"x-appwrite":{"method":"getAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":85,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":84,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","default":null,"x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":91,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":90,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":92,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":94,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":95,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","schema":{"$ref":"#\/definitions\/indexList"}}},"x-appwrite":{"method":"listIndexes","weight":87,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"createIndex","weight":86,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","default":null,"x-example":null},"type":{"type":"string","description":"Index type.","default":null,"x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","default":[],"x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"getIndex","weight":88,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":89,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","schema":{"$ref":"#\/definitions\/functionList"}}},"x-appwrite":{"method":"list","weight":238,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"create","weight":237,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","default":true,"x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","default":true,"x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","default":"","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","default":"","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Control System) deployment.","default":"","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function.","default":"","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function.","default":"","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","default":false,"x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"},"templateRepository":{"type":"string","description":"Repository name of the template.","default":"","x-example":"[TEMPLATE_REPOSITORY]"},"templateOwner":{"type":"string","description":"The name of the owner of the template.","default":"","x-example":"[TEMPLATE_OWNER]"},"templateRootDirectory":{"type":"string","description":"Path to function code in the template repo.","default":"","x-example":"[TEMPLATE_ROOT_DIRECTORY]"},"templateBranch":{"type":"string","description":"Production branch for the repo linked to the function template.","default":"","x-example":"[TEMPLATE_BRANCH]"}},"required":["functionId","name","runtime"]}}]}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","schema":{"$ref":"#\/definitions\/runtimeList"}}},"x-appwrite":{"method":"listRuntimes","weight":239,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"get","weight":240,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"update","weight":243,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","default":true,"x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","default":true,"x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","default":"","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","default":"","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Controle System) deployment.","default":"","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function","default":"","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function","default":"","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","default":false,"x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"}},"required":["name","runtime"]}}]},"delete":{"summary":"Delete Function","operationId":"functionsDelete","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":246,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","schema":{"$ref":"#\/definitions\/deploymentList"}}},"x-appwrite":{"method":"listDeployments","weight":248,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: size, buildId, activate, entrypoint, commands","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","consumes":["multipart\/form-data"],"produces":["application\/json"],"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](\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.","responses":{"202":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"createDeployment","weight":247,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"entrypoint","description":"Entrypoint File.","required":false,"type":"string","x-example":"[ENTRYPOINT]","in":"formData"},{"name":"commands","description":"Build Commands.","required":false,"type":"string","x-example":"[COMMANDS]","in":"formData"},{"name":"code","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","required":true,"type":"file","in":"formData"},{"name":"activate","description":"Automatically activate the deployment when it is finished building.","required":true,"type":"boolean","x-example":false,"in":"formData"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"getDeployment","weight":249,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"updateDeployment","weight":245,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":250,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Create a new build for an Appwrite Function deployment. This endpoint can be used to retry a failed build.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":251,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"type":"string","x-example":"[BUILD_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/download":{"get":{"summary":"Download Deployment","operationId":"functionsDownloadDeployment","consumes":["application\/json"],"produces":["*\/*"],"tags":["functions"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"downloadDeployment","weight":244,"cookies":false,"type":"location","demo":"functions\/download-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/download-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":253,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":252,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","default":"","x-example":"[BODY]"},"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":"[PATH]"},"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":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","default":[],"x-example":"{}"}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":254,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","weight":256,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","weight":255,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","weight":257,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","weight":258,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":259,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":293,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":292,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"get","weight":107,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","schema":{"$ref":"#\/definitions\/healthAntivirus"}}},"x-appwrite":{"method":"getAntivirus","weight":119,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getCache","weight":110,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getDB","weight":109,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getPubSub","weight":112,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getQueue","weight":111,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueCertificates","weight":116,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueFunctions","weight":117,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueLogs","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueWebhooks","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getStorageLocal","weight":118,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","schema":{"$ref":"#\/definitions\/healthTime"}}},"x-appwrite":{"method":"getTime","weight":113,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":99,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":100,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":104,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":102,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":103,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":105,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":106,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","schema":{"$ref":"#\/definitions\/bucketList"}}},"x-appwrite":{"method":"listBuckets","weight":168,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"createBucket","weight":167,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","default":30000000,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["bucketId","name"]}}]}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"getBucket","weight":169,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"updateBucket","weight":170,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","default":null,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":171,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":173,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":172,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":174,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":178,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":179,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":176,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":175,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":177,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":183,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":182,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":184,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":186,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":188,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":190,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":189,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":191,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembership","weight":192,"cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":194,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":193,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":185,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":187,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","schema":{"$ref":"#\/definitions\/userList"}}},"x-appwrite":{"method":"list","weight":204,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":196,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","default":"","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId"]}}]}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createArgon2User","weight":199,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createBcryptUser","weight":197,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/identities":{"get":{"summary":"List Identities","operationId":"usersListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get identities for all users.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","weight":210,"cookies":false,"type":"","demo":"users\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]}},"\/users\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"usersDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":223,"cookies":false,"type":"","demo":"users\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createMD5User","weight":198,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createPHPassUser","weight":201,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptUser","weight":202,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","default":null,"x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","default":null,"x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","default":null,"x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}]}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":203,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","default":null,"x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","default":null,"x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}]}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createSHAUser","weight":200,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","default":null,"x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","default":"","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":205,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":222,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":216,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"}},"required":["email"]}}]}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateLabels","weight":212,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["labels"]}}]}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":209,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":208,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":214,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":215,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null}},"required":["password"]}}]}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":217,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","default":null,"x-example":"+12065550100"}},"required":["number"]}}]}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":206,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":219,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":207,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":221,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":220,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":211,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","default":null,"x-example":false}},"required":["status"]}}]}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmailVerification","weight":218,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","default":null,"x-example":false}},"required":["emailVerification"]}}]}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":213,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","default":null,"x-example":false}},"required":["phoneVerification"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"type":"object","$ref":"#\/definitions\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"type":"object","$ref":"#\/definitions\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"type":"object","$ref":"#\/definitions\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"type":"object","$ref":"#\/definitions\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"type":"object","$ref":"#\/definitions\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"type":"object","$ref":"#\/definitions\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"type":"object","$ref":"#\/definitions\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"type":"object","$ref":"#\/definitions\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"If database is enabled. Can be 'enabled' or 'disabled'. When disabled, the database is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled. Can be 'enabled' or 'disabled'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","x-nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","x-nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","x-nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","x-nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","x-nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","x-nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"x-nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"live":{"type":"boolean","description":"Is the function deployed with the latest configuration? This is set to false if you've changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":300,"format":"int32"},"entrypoint":{"type":"string","description":"The entrypoint file used to execute the deployment.","x-example":"index.js"},"commands":{"type":"string","description":"The build command used to build the deployment.","x-example":"npm install"},"version":{"type":"string","description":"Version of Open Runtimes used for the function.","x-example":"v2"},"installationId":{"type":"string","description":"Function VCS (Version Control System) installation id.","x-example":"6m40at4ejk5h2u9s1hboo"},"providerRepositoryId":{"type":"string","description":"VCS (Version Control System) Repository ID","x-example":"appwrite"},"providerBranch":{"type":"string","description":"VCS (Version Control System) branch name","x-example":"main"},"providerRootDirectory":{"type":"string","description":"Path to function in VCS (Version Control System) repository","x-example":"functions\/helloWorld"},"providerSilentMode":{"type":"boolean","description":"Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests","x-example":false}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","live","logging","runtime","deployment","vars","events","schedule","timeout","entrypoint","commands","version","installationId","providerRepositoryId","providerBranch","providerRootDirectory","providerSilentMode"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"type":{"type":"string","description":"Type of deployment.","x-example":"vcs"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"index.js"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"waiting\", \"ready\", and \"failed\".","x-example":"ready"},"buildLogs":{"type":"string","description":"The build logs.","x-example":"Compiling source files..."},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"},"providerRepositoryName":{"type":"string","description":"The name of the vcs provider repository","x-example":"database"},"providerRepositoryOwner":{"type":"string","description":"The name of the vcs provider repository owner","x-example":"utopia"},"providerRepositoryUrl":{"type":"string","description":"The url of the vcs provider repository","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function"},"providerBranch":{"type":"string","description":"The branch of the vcs repository","x-example":"0.7.x"},"providerCommitHash":{"type":"string","description":"The commit hash of the vcs commit","x-example":"7c3f25d"},"providerCommitAuthorUrl":{"type":"string","description":"The url of vcs commit author","x-example":"https:\/\/github.com\/vermakhushboo"},"providerCommitAuthor":{"type":"string","description":"The name of vcs commit author","x-example":"Khushboo Verma"},"providerCommitMessage":{"type":"string","description":"The commit message","x-example":"Update index.js"},"providerCommitUrl":{"type":"string","description":"The url of the vcs commit","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function\/commit\/60c0416257a9cbcdd96b2d370c38d8f8d150ccfb"},"providerBranchUrl":{"type":"string","description":"The branch of the vcs repository","x-example":"https:\/\/github.com\/vermakhushboo\/appwrite\/tree\/0.7.x"}},"required":["$id","$createdAt","$updatedAt","type","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildLogs","buildTime","providerRepositoryName","providerRepositoryOwner","providerRepositoryUrl","providerBranch","providerCommitHash","providerCommitAuthorUrl","providerCommitAuthor","providerCommitMessage","providerCommitUrl","providerBranchUrl"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"resourceType":{"type":"string","description":"Service to which the variable belongs. Possible values are \"project\", \"function\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource to which the variable belongs. If resourceType is \"project\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"}},"required":["$id","$createdAt","$updatedAt","key","value","resourceType","resourceId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json index 41b0693be4..1b291408f0 100644 --- a/app/config/specs/swagger2-latest-client.json +++ b/app/config/specs/swagger2-latest-client.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","schema":{"$ref":"#\/definitions\/jwt"}}},"x-appwrite":{"method":"createJWT","weight":18,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createAnonymousSession","weight":17,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createMagicURLSession","weight":13,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":"","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}]},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateMagicURLSession","weight":14,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","consumes":["application\/json"],"produces":["text\/html"],"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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"No content"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[],"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneSession","weight":15,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"}},"required":["userId","phone"]}}]},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updatePhoneSession","weight":16,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/console\/assistant":{"post":{"summary":"Ask Query","operationId":"assistantChat","consumes":["application\/json"],"produces":["text\/plain"],"tags":["assistant"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"chat","weight":275,"cookies":false,"type":"","demo":"assistant\/chat.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/assistant\/chat.md","rate-limit":15,"rate-time":3600,"rate-key":"userId:{userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"string","description":"Query","default":null,"x-example":"[QUERY]"}},"required":["query"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","default":"","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","default":false,"x-example":false}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":21,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":28,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","weight":13,"cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":14,"cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","schema":{"$ref":"#\/definitions\/jwt"}}},"x-appwrite":{"method":"createJWT","weight":20,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":24,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":26,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":27,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":29,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":22,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":30,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":35,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":36,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":23,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":34,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createAnonymousSession","weight":19,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createMagicURLSession","weight":15,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":"","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}]},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateMagicURLSession","weight":16,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","consumes":["application\/json"],"produces":["text\/html"],"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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"No content"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[],"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneSession","weight":17,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"}},"required":["userId","phone"]}}]},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updatePhoneSession","weight":18,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":25,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":33,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":32,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":31,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":39,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":40,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":47,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":46,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":91,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":90,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":92,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":94,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":95,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":253,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":252,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","default":"","x-example":"[BODY]"},"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":"[PATH]"},"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":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","default":[],"x-example":"{}"}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":254,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":293,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":292,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":99,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":100,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":104,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":102,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":103,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":105,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":106,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":173,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":172,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":174,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":178,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":179,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":176,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":175,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":177,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":183,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":182,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":184,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":186,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":188,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":190,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":189,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":191,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembership","weight":192,"cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":194,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":193,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":185,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":187,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"type":"object","$ref":"#\/definitions\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 39e075fcd1..cf2b52db4b 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}},"Mode":{"type":"apiKey","name":"X-Appwrite-Mode","description":"","in":"header","x-appwrite":{"demo":""}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":7,"cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/invite":{"post":{"summary":"Create account using an invite code","operationId":"accountCreateWithInviteCode","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"Account","schema":{"$ref":"#\/definitions\/account"}}},"x-appwrite":{"method":"createWithInviteCode","weight":6,"cookies":false,"type":"","demo":"account\/create-with-invite-code.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose your own unique ID or pass the string `ID.unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"},"code":{"type":"string","description":"An invite code to restrict user signups on the Appwrite console. Users with an invite code will be able to create accounts irrespective of email and IP whitelists.","default":"","x-example":"[CODE]"}},"required":["userId","email","password"]}}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","schema":{"$ref":"#\/definitions\/jwt"}}},"x-appwrite":{"method":"createJWT","weight":18,"cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createAnonymousSession","weight":17,"cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createEmailSession","weight":8,"cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createMagicURLSession","weight":13,"cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":"","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}]},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateMagicURLSession","weight":14,"cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","consumes":["application\/json"],"produces":["text\/html"],"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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"No content"}},"x-appwrite":{"method":"createOAuth2Session","weight":9,"cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[],"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneSession","weight":15,"cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"}},"required":["userId","phone"]}}]},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updatePhoneSession","weight":16,"cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/console\/assistant":{"post":{"summary":"Ask Query","operationId":"assistantChat","consumes":["application\/json"],"produces":["text\/plain"],"tags":["assistant"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"chat","weight":275,"cookies":false,"type":"","demo":"assistant\/chat.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/assistant\/chat.md","rate-limit":15,"rate-time":3600,"rate-key":"userId:{userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"string","description":"Query","default":null,"x-example":"[QUERY]"}},"required":["query"]}}]}},"\/console\/variables":{"get":{"summary":"Get Variables","operationId":"consoleVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["console"],"description":"Get all Environment Variables that are relevant for the console.","responses":{"200":{"description":"Console Variables","schema":{"$ref":"#\/definitions\/consoleVariables"}}},"x-appwrite":{"method":"variables","weight":274,"cookies":false,"type":"","demo":"console\/variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/console\/variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","schema":{"$ref":"#\/definitions\/databaseList"}}},"x-appwrite":{"method":"list","weight":50,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"create","weight":49,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","default":true,"x-example":false}},"required":["databaseId","name"]}}]}},"\/databases\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabases","schema":{"$ref":"#\/definitions\/usageDatabases"}}},"x-appwrite":{"method":"getUsage","weight":94,"cookies":false,"type":"","demo":"databases\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"`Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"get","weight":51,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"update","weight":53,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Database","operationId":"databasesDelete","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":54,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","schema":{"$ref":"#\/definitions\/collectionList"}}},"x-appwrite":{"method":"listCollections","weight":56,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"createCollection","weight":55,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","default":true,"x-example":false}},"required":["collectionId","name"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"getCollection","weight":57,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"updateCollection","weight":59,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":60,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","schema":{"$ref":"#\/definitions\/attributeList"}}},"x-appwrite":{"method":"listAttributes","weight":71,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"createBooleanAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"createEmailAttribute","weight":62,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"updateEmailAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"createEnumAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","elements","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"updateEnumAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"createFloatAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"updateFloatAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"createIntegerAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"createIpAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"updateIpAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","default":null,"x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","default":null,"x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","default":false,"x-example":false},"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","default":null,"x-example":null},"onDelete":{"type":"string","description":"Constraints option","default":"restrict","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"createStringAttribute","weight":61,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","default":null,"x-example":1},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","size","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"updateStringAttribute","weight":73,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"createUrlAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"updateUrlAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","schema":{"x-oneOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]}}},"x-appwrite":{"method":"getAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","default":null,"x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/logs":{"get":{"summary":"List Document Logs","operationId":"databasesListDocumentLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the document activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listDocumentLogs","weight":91,"cookies":false,"type":"","demo":"databases\/list-document-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","schema":{"$ref":"#\/definitions\/indexList"}}},"x-appwrite":{"method":"listIndexes","weight":85,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"createIndex","weight":84,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","default":null,"x-example":null},"type":{"type":"string","description":"Index type.","default":null,"x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","default":[],"x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"getIndex","weight":86,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":87,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/logs":{"get":{"summary":"List Collection Logs","operationId":"databasesListCollectionLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the collection activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listCollectionLogs","weight":58,"cookies":false,"type":"","demo":"databases\/list-collection-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/usage":{"get":{"summary":"Get usage stats for a collection","operationId":"databasesGetCollectionUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageCollection","schema":{"$ref":"#\/definitions\/usageCollection"}}},"x-appwrite":{"method":"getCollectionUsage","weight":96,"cookies":false,"type":"","demo":"databases\/get-collection-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/logs":{"get":{"summary":"List Database Logs","operationId":"databasesListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the database activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":52,"cookies":false,"type":"","demo":"databases\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetDatabaseUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabase","schema":{"$ref":"#\/definitions\/usageDatabase"}}},"x-appwrite":{"method":"getDatabaseUsage","weight":95,"cookies":false,"type":"","demo":"databases\/get-database-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"range","description":"`Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","schema":{"$ref":"#\/definitions\/functionList"}}},"x-appwrite":{"method":"list","weight":222,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"create","weight":221,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","php-8.0","php-8.1","ruby-3.0","ruby-3.1","python-3.8","python-3.9","python-3.10","dart-2.15","dart-2.16","dart-2.17","dotnet-3.1","dotnet-6.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","kotlin-1.6","cpp-17.0"],"x-enum-name":null,"x-enum-keys":[]},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","default":true,"x-example":false}},"required":["functionId","name","runtime"]}}]}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","schema":{"$ref":"#\/definitions\/runtimeList"}}},"x-appwrite":{"method":"listRuntimes","weight":223,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/usage":{"get":{"summary":"Get Functions Usage","operationId":"functionsGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","schema":{"$ref":"#\/definitions\/usageFunctions"}}},"x-appwrite":{"method":"getUsage","weight":226,"cookies":false,"type":"","demo":"functions\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"get","weight":224,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"update","weight":227,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Function","operationId":"functionsDelete","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":229,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","schema":{"$ref":"#\/definitions\/deploymentList"}}},"x-appwrite":{"method":"listDeployments","weight":231,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: entrypoint, size, buildId, activate","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","consumes":["multipart\/form-data"],"produces":["application\/json"],"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](\/docs\/functions).\n\nUse the \"command\" param to set the entry point used to execute your code.","responses":{"202":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"createDeployment","weight":230,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"entrypoint","description":"Entrypoint File.","required":true,"type":"string","x-example":"[ENTRYPOINT]","in":"formData"},{"name":"code","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","required":true,"type":"file","in":"formData"},{"name":"activate","description":"Automatically activate the deployment when it is finished building.","required":true,"type":"boolean","x-example":false,"in":"formData"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"getDeployment","weight":232,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"updateDeployment","weight":228,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":233,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":234,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"type":"string","x-example":"[BUILD_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","default":"","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","default":false,"x-example":false}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/usage":{"get":{"summary":"Get Function Usage","operationId":"functionsGetFunctionUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","schema":{"$ref":"#\/definitions\/usageFunctions"}}},"x-appwrite":{"method":"getFunctionUsage","weight":225,"cookies":false,"type":"","demo":"functions\/get-function-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","weight":239,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function variable. These variables can be accessed within function in the `env` object under the request variable.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","weight":238,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","weight":240,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","weight":241,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":242,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"get","weight":105,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","schema":{"$ref":"#\/definitions\/healthAntivirus"}}},"x-appwrite":{"method":"getAntivirus","weight":117,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getCache","weight":108,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getDB","weight":107,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getPubSub","weight":110,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getQueue","weight":109,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueCertificates","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueFunctions","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueLogs","weight":113,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueWebhooks","weight":112,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getStorageLocal","weight":116,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","schema":{"$ref":"#\/definitions\/healthTime"}}},"x-appwrite":{"method":"getTime","weight":111,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/project\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"","responses":{"200":{"description":"UsageProject","schema":{"$ref":"#\/definitions\/usageProject"}}},"x-appwrite":{"method":"getUsage","weight":163,"cookies":false,"type":"","demo":"project\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/projects":{"get":{"summary":"List Projects","operationId":"projectsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Projects List","schema":{"$ref":"#\/definitions\/projectList"}}},"x-appwrite":{"method":"list","weight":120,"cookies":false,"type":"","demo":"projects\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Project","operationId":"projectsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"create","weight":119,"cookies":false,"type":"","demo":"projects\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"projectId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":null},"name":{"type":"string","description":"Project name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"teamId":{"type":"string","description":"Team unique ID.","default":null,"x-example":"[TEAM_ID]"},"region":{"type":"string","description":"Project Region.","default":"default","x-example":"default","enum":["default"],"x-enum-name":null,"x-enum-keys":[]},"description":{"type":"string","description":"Project description. Max length: 256 chars.","default":"","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","default":"","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","default":"","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal Name. Max length: 256 chars.","default":"","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal Country. Max length: 256 chars.","default":"","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal State. Max length: 256 chars.","default":"","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal City. Max length: 256 chars.","default":"","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal Address. Max length: 256 chars.","default":"","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal Tax ID. Max length: 256 chars.","default":"","x-example":"[LEGAL_TAX_ID]"}},"required":["projectId","name","teamId"]}}]}},"\/projects\/{projectId}":{"get":{"summary":"Get Project","operationId":"projectsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"get","weight":121,"cookies":false,"type":"","demo":"projects\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"patch":{"summary":"Update Project","operationId":"projectsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"update","weight":122,"cookies":false,"type":"","demo":"projects\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","default":"","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","default":"","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","default":"","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal name. Max length: 256 chars.","default":"","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal country. Max length: 256 chars.","default":"","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal state. Max length: 256 chars.","default":"","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal city. Max length: 256 chars.","default":"","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal address. Max length: 256 chars.","default":"","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal tax ID. Max length: 256 chars.","default":"","x-example":"[LEGAL_TAX_ID]"}},"required":["name"]}}]},"delete":{"summary":"Delete Project","operationId":"projectsDelete","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":134,"cookies":false,"type":"","demo":"projects\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]}},"\/projects\/{projectId}\/auth\/duration":{"patch":{"summary":"Update Project Authentication Duration","operationId":"projectsUpdateAuthDuration","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthDuration","weight":128,"cookies":false,"type":"","demo":"projects\/update-auth-duration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"duration":{"type":"integer","description":"Project session length in seconds. Max length: 31536000 seconds.","default":null,"x-example":0}},"required":["duration"]}}]}},"\/projects\/{projectId}\/auth\/limit":{"patch":{"summary":"Update Project users limit","operationId":"projectsUpdateAuthLimit","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthLimit","weight":127,"cookies":false,"type":"","demo":"projects\/update-auth-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Use 0 for unlimited.","default":null,"x-example":0}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/max-sessions":{"patch":{"summary":"Update Project user sessions limit","operationId":"projectsUpdateAuthSessionsLimit","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthSessionsLimit","weight":133,"cookies":false,"type":"","demo":"projects\/update-auth-sessions-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10","default":null,"x-example":1}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/password-dictionary":{"patch":{"summary":"Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password","operationId":"projectsUpdateAuthPasswordDictionary","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthPasswordDictionary","weight":131,"cookies":false,"type":"","demo":"projects\/update-auth-password-dictionary.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to enable checking user's password against most commonly used passwords. Default is false.","default":null,"x-example":false}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/auth\/password-history":{"patch":{"summary":"Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.","operationId":"projectsUpdateAuthPasswordHistory","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthPasswordHistory","weight":130,"cookies":false,"type":"","demo":"projects\/update-auth-password-history.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0","default":null,"x-example":0}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/personal-data":{"patch":{"summary":"Enable or disable checking user passwords for similarity with their personal data.","operationId":"projectsUpdatePersonalDataCheck","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updatePersonalDataCheck","weight":132,"cookies":false,"type":"","demo":"projects\/update-personal-data-check.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to check a password for similarity with personal data. Default is false.","default":null,"x-example":false}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/auth\/{method}":{"patch":{"summary":"Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.","operationId":"projectsUpdateAuthStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthStatus","weight":129,"cookies":false,"type":"","demo":"projects\/update-auth-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"method","description":"Auth Method. Possible values: email-password,magic-url,anonymous,invites,jwt,phone","required":true,"type":"string","x-example":"email-password","enum":["email-password","magic-url","anonymous","invites","jwt","phone"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Set the status of this auth method.","default":null,"x-example":false}},"required":["status"]}}]}},"\/projects\/{projectId}\/domains":{"get":{"summary":"List Domains","operationId":"projectsListDomains","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Domains List","schema":{"$ref":"#\/definitions\/domainList"}}},"x-appwrite":{"method":"listDomains","weight":152,"cookies":false,"type":"","demo":"projects\/list-domains.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Domain","operationId":"projectsCreateDomain","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Domain","schema":{"$ref":"#\/definitions\/domain"}}},"x-appwrite":{"method":"createDomain","weight":151,"cookies":false,"type":"","demo":"projects\/create-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain name.","default":null,"x-example":null}},"required":["domain"]}}]}},"\/projects\/{projectId}\/domains\/{domainId}":{"get":{"summary":"Get Domain","operationId":"projectsGetDomain","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Domain","schema":{"$ref":"#\/definitions\/domain"}}},"x-appwrite":{"method":"getDomain","weight":153,"cookies":false,"type":"","demo":"projects\/get-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"type":"string","x-example":"[DOMAIN_ID]","in":"path"}]},"delete":{"summary":"Delete Domain","operationId":"projectsDeleteDomain","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDomain","weight":155,"cookies":false,"type":"","demo":"projects\/delete-domain.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"type":"string","x-example":"[DOMAIN_ID]","in":"path"}]}},"\/projects\/{projectId}\/domains\/{domainId}\/verification":{"patch":{"summary":"Update Domain Verification Status","operationId":"projectsUpdateDomainVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Domain","schema":{"$ref":"#\/definitions\/domain"}}},"x-appwrite":{"method":"updateDomainVerification","weight":154,"cookies":false,"type":"","demo":"projects\/update-domain-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"domainId","description":"Domain unique ID.","required":true,"type":"string","x-example":"[DOMAIN_ID]","in":"path"}]}},"\/projects\/{projectId}\/keys":{"get":{"summary":"List Keys","operationId":"projectsListKeys","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"API Keys List","schema":{"$ref":"#\/definitions\/keyList"}}},"x-appwrite":{"method":"listKeys","weight":142,"cookies":false,"type":"","demo":"projects\/list-keys.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Key","operationId":"projectsCreateKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"createKey","weight":141,"cookies":false,"type":"","demo":"projects\/create-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 scopes are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","default":null,"x-example":null}},"required":["name","scopes"]}}]}},"\/projects\/{projectId}\/keys\/{keyId}":{"get":{"summary":"Get Key","operationId":"projectsGetKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"getKey","weight":143,"cookies":false,"type":"","demo":"projects\/get-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"}]},"put":{"summary":"Update Key","operationId":"projectsUpdateKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"updateKey","weight":144,"cookies":false,"type":"","demo":"projects\/update-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","default":null,"x-example":null}},"required":["name","scopes"]}}]},"delete":{"summary":"Delete Key","operationId":"projectsDeleteKey","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteKey","weight":145,"cookies":false,"type":"","demo":"projects\/delete-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"}]}},"\/projects\/{projectId}\/oauth2":{"patch":{"summary":"Update Project OAuth2","operationId":"projectsUpdateOAuth2","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateOAuth2","weight":126,"cookies":false,"type":"","demo":"projects\/update-o-auth2.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"provider":{"type":"string","description":"Provider Name","default":null,"x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":null,"x-enum-keys":[]},"appId":{"type":"string","description":"Provider app ID. Max length: 256 chars.","default":null,"x-example":"[APP_ID]"},"secret":{"type":"string","description":"Provider secret key. Max length: 512 chars.","default":null,"x-example":"[SECRET]"},"enabled":{"type":"boolean","description":"Provider status. Set to 'false' to disable new session creation.","default":null,"x-example":false}},"required":["provider"]}}]}},"\/projects\/{projectId}\/platforms":{"get":{"summary":"List Platforms","operationId":"projectsListPlatforms","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platforms List","schema":{"$ref":"#\/definitions\/platformList"}}},"x-appwrite":{"method":"listPlatforms","weight":147,"cookies":false,"type":"","demo":"projects\/list-platforms.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Platform","operationId":"projectsCreatePlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"createPlatform","weight":146,"cookies":false,"type":"","demo":"projects\/create-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"type":{"type":"string","description":"Platform type.","default":null,"x-example":"web","enum":["web","flutter-web","flutter-ios","flutter-android","flutter-linux","flutter-macos","flutter-windows","apple-ios","apple-macos","apple-watchos","apple-tvos","android","unity"],"x-enum-name":"PlatformType","x-enum-keys":[]},"name":{"type":"string","description":"Platform name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"key":{"type":"string","description":"Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.","default":"","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","default":"","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client hostname. Max length: 256 chars.","default":"","x-example":null}},"required":["type","name"]}}]}},"\/projects\/{projectId}\/platforms\/{platformId}":{"get":{"summary":"Get Platform","operationId":"projectsGetPlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"getPlatform","weight":148,"cookies":false,"type":"","demo":"projects\/get-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"}]},"put":{"summary":"Update Platform","operationId":"projectsUpdatePlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"updatePlatform","weight":149,"cookies":false,"type":"","demo":"projects\/update-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Platform name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"key":{"type":"string","description":"Package name for android or bundle ID for iOS. Max length: 256 chars.","default":"","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","default":"","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client URL. Max length: 256 chars.","default":"","x-example":null}},"required":["name"]}}]},"delete":{"summary":"Delete Platform","operationId":"projectsDeletePlatform","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deletePlatform","weight":150,"cookies":false,"type":"","demo":"projects\/delete-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"}]}},"\/projects\/{projectId}\/service":{"patch":{"summary":"Update service status","operationId":"projectsUpdateServiceStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateServiceStatus","weight":124,"cookies":false,"type":"","demo":"projects\/update-service-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"service":{"type":"string","description":"Service name.","default":null,"x-example":"account","enum":["account","avatars","databases","locale","health","storage","teams","users","functions","graphql"],"x-enum-name":null,"x-enum-keys":[]},"status":{"type":"boolean","description":"Service status.","default":null,"x-example":false}},"required":["service","status"]}}]}},"\/projects\/{projectId}\/service\/all":{"patch":{"summary":"Update all service status","operationId":"projectsUpdateServiceStatusAll","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateServiceStatusAll","weight":125,"cookies":false,"type":"","demo":"projects\/update-service-status-all.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Service status.","default":null,"x-example":false}},"required":["status"]}}]}},"\/projects\/{projectId}\/smtp":{"patch":{"summary":"Update SMTP configuration","operationId":"projectsUpdateSmtpConfiguration","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateSmtpConfiguration","weight":156,"cookies":false,"type":"","demo":"projects\/update-smtp-configuration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable custom SMTP service","default":null,"x-example":false},"sender":{"type":"string","description":"SMTP sender email","default":null,"x-example":"email@example.com"},"host":{"type":"string","description":"SMTP server host name","default":null,"x-example":null},"port":{"type":"integer","description":"SMTP server port","default":null,"x-example":null},"username":{"type":"string","description":"SMTP server username","default":null,"x-example":"[USERNAME]"},"password":{"type":"string","description":"SMTP server password","default":null,"x-example":"[PASSWORD]"},"secure":{"type":"string","description":"Does SMTP server use secure connection","default":"","x-example":"tls","enum":["tls"],"x-enum-name":null,"x-enum-keys":[]}},"required":["enabled","sender","host","port","username","password"]}}]}},"\/projects\/{projectId}\/team":{"patch":{"summary":"Update Project Team","operationId":"projectsUpdateTeam","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateTeam","weight":123,"cookies":false,"type":"","demo":"projects\/update-team.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID of the team to transfer project to.","default":null,"x-example":"[TEAM_ID]"}},"required":["teamId"]}}]}},"\/projects\/{projectId}\/templates\/email\/{type}\/{locale}":{"get":{"summary":"Get custom email template","operationId":"projectsGetEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","schema":{"$ref":"#\/definitions\/emailTemplate"}}},"x-appwrite":{"method":"getEmailTemplate","weight":158,"cookies":false,"type":"","demo":"projects\/get-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]},"patch":{"summary":"Update custom email templates","operationId":"projectsUpdateEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateEmailTemplate","weight":160,"cookies":false,"type":"","demo":"projects\/update-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"senderName":{"type":"string","description":"Name of the email sender","default":null,"x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","default":null,"x-example":"email@example.com"},"subject":{"type":"string","description":"Email Subject","default":null,"x-example":"[SUBJECT]"},"message":{"type":"string","description":"Template message","default":null,"x-example":"[MESSAGE]"},"replyTo":{"type":"string","description":"Reply to email","default":"","x-example":"email@example.com"}},"required":["senderName","senderEmail","subject","message"]}}]},"delete":{"summary":"Reset custom email template","operationId":"projectsDeleteEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","schema":{"$ref":"#\/definitions\/emailTemplate"}}},"x-appwrite":{"method":"deleteEmailTemplate","weight":162,"cookies":false,"type":"","demo":"projects\/delete-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]}},"\/projects\/{projectId}\/templates\/sms\/{type}\/{locale}":{"get":{"summary":"Get custom SMS template","operationId":"projectsGetSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"getSmsTemplate","weight":157,"cookies":false,"type":"","demo":"projects\/get-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]},"patch":{"summary":"Update custom SMS template","operationId":"projectsUpdateSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"updateSmsTemplate","weight":159,"cookies":false,"type":"","demo":"projects\/update-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"message":{"type":"string","description":"Template message","default":null,"x-example":"[MESSAGE]"}},"required":["message"]}}]},"delete":{"summary":"Reset custom SMS template","operationId":"projectsDeleteSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"deleteSmsTemplate","weight":161,"cookies":false,"type":"","demo":"projects\/delete-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]}},"\/projects\/{projectId}\/webhooks":{"get":{"summary":"List Webhooks","operationId":"projectsListWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhooks List","schema":{"$ref":"#\/definitions\/webhookList"}}},"x-appwrite":{"method":"listWebhooks","weight":136,"cookies":false,"type":"","demo":"projects\/list-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Webhook","operationId":"projectsCreateWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"createWebhook","weight":135,"cookies":false,"type":"","demo":"projects\/create-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","default":null,"x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","default":null,"x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","default":"","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","default":"","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}":{"get":{"summary":"Get Webhook","operationId":"projectsGetWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"getWebhook","weight":137,"cookies":false,"type":"","demo":"projects\/get-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]},"put":{"summary":"Update Webhook","operationId":"projectsUpdateWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"updateWebhook","weight":138,"cookies":false,"type":"","demo":"projects\/update-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","default":null,"x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","default":null,"x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","default":"","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","default":"","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}]},"delete":{"summary":"Delete Webhook","operationId":"projectsDeleteWebhook","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteWebhook","weight":140,"cookies":false,"type":"","demo":"projects\/delete-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}\/signature":{"patch":{"summary":"Update Webhook Signature Key","operationId":"projectsUpdateWebhookSignature","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"updateWebhookSignature","weight":139,"cookies":false,"type":"","demo":"projects\/update-webhook-signature.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","schema":{"$ref":"#\/definitions\/bucketList"}}},"x-appwrite":{"method":"listBuckets","weight":165,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"createBucket","weight":164,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","default":30000000,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["bucketId","name"]}}]}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"getBucket","weight":166,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"updateBucket","weight":167,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","default":null,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":168,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/usage":{"get":{"summary":"Get usage stats for storage","operationId":"storageGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"","responses":{"200":{"description":"StorageUsage","schema":{"$ref":"#\/definitions\/usageStorage"}}},"x-appwrite":{"method":"getUsage","weight":177,"cookies":false,"type":"","demo":"storage\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/storage\/{bucketId}\/usage":{"get":{"summary":"Get usage stats for storage bucket","operationId":"storageGetBucketUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"","responses":{"200":{"description":"UsageBuckets","schema":{"$ref":"#\/definitions\/usageBuckets"}}},"x-appwrite":{"method":"getBucketUsage","weight":178,"cookies":false,"type":"","demo":"storage\/get-bucket-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"bucketId","description":"Bucket ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/logs":{"get":{"summary":"List Team Logs","operationId":"teamsListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":192,"cookies":false,"type":"","demo":"teams\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","schema":{"$ref":"#\/definitions\/userList"}}},"x-appwrite":{"method":"list","weight":201,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":193,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","default":"","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId"]}}]}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createArgon2User","weight":196,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createBcryptUser","weight":194,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createMD5User","weight":195,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createPHPassUser","weight":198,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptUser","weight":199,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","default":null,"x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","default":null,"x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","default":null,"x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}]}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":200,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","default":null,"x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","default":null,"x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}]}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createSHAUser","weight":197,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","default":null,"x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","default":"","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/usage":{"get":{"summary":"Get usage stats for the users API","operationId":"usersGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"","responses":{"200":{"description":"UsageUsers","schema":{"$ref":"#\/definitions\/usageUsers"}}},"x-appwrite":{"method":"getUsage","weight":220,"cookies":false,"type":"","demo":"users\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":202,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":219,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":213,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"}},"required":["email"]}}]}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateLabels","weight":208,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["labels"]}}]}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":206,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":205,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":211,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":212,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null}},"required":["password"]}}]}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":214,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","default":null,"x-example":"+12065550100"}},"required":["number"]}}]}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":203,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":216,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":204,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":218,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":217,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":207,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","default":null,"x-example":false}},"required":["status"]}}]}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmailVerification","weight":215,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","default":null,"x-example":false}},"required":["emailVerification"]}}]}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":210,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","default":null,"x-example":false}},"required":["phoneVerification"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"type":"object","$ref":"#\/definitions\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"type":"object","$ref":"#\/definitions\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"type":"object","$ref":"#\/definitions\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"type":"object","$ref":"#\/definitions\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"type":"object","$ref":"#\/definitions\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"type":"object","$ref":"#\/definitions\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"type":"object","$ref":"#\/definitions\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"projectList":{"description":"Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"type":"object","$ref":"#\/definitions\/project"},"x-example":""}},"required":["total","projects"]},"webhookList":{"description":"Webhooks List","type":"object","properties":{"total":{"type":"integer","description":"Total number of webhooks documents that matched your query.","x-example":5,"format":"int32"},"webhooks":{"type":"array","description":"List of webhooks.","items":{"type":"object","$ref":"#\/definitions\/webhook"},"x-example":""}},"required":["total","webhooks"]},"keyList":{"description":"API Keys List","type":"object","properties":{"total":{"type":"integer","description":"Total number of keys documents that matched your query.","x-example":5,"format":"int32"},"keys":{"type":"array","description":"List of keys.","items":{"type":"object","$ref":"#\/definitions\/key"},"x-example":""}},"required":["total","keys"]},"platformList":{"description":"Platforms List","type":"object","properties":{"total":{"type":"integer","description":"Total number of platforms documents that matched your query.","x-example":5,"format":"int32"},"platforms":{"type":"array","description":"List of platforms.","items":{"type":"object","$ref":"#\/definitions\/platform"},"x-example":""}},"required":["total","platforms"]},"domainList":{"description":"Domains List","type":"object","properties":{"total":{"type":"integer","description":"Total number of domains documents that matched your query.","x-example":5,"format":"int32"},"domains":{"type":"array","description":"List of domains.","items":{"type":"object","$ref":"#\/definitions\/domain"},"x-example":""}},"required":["total","domains"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"Database enabled.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","x-nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","x-nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","x-nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","x-nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","x-nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","x-nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"x-nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"account":{"description":"Account","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":15,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","runtime","deployment","vars","events","schedule","timeout"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"enabled"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"pending\", \"ready\", and \"failed\".","x-example":"ready"},"buildStdout":{"type":"string","description":"The build stdout.","x-example":"enabled"},"buildStderr":{"type":"string","description":"The build stderr.","x-example":"enabled"},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildStdout","buildStderr","buildTime"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"project":{"description":"Project","type":"object","properties":{"$id":{"type":"string","description":"Project ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Project creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Project update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Project name.","x-example":"New Project"},"description":{"type":"string","description":"Project description.","x-example":"This is a new project."},"teamId":{"type":"string","description":"Project team ID.","x-example":"1592981250"},"logo":{"type":"string","description":"Project logo file ID.","x-example":"5f5c451b403cb"},"url":{"type":"string","description":"Project website URL.","x-example":"5f5c451b403cb"},"legalName":{"type":"string","description":"Company legal name.","x-example":"Company LTD."},"legalCountry":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format.","x-example":"US"},"legalState":{"type":"string","description":"State name.","x-example":"New York"},"legalCity":{"type":"string","description":"City name.","x-example":"New York City."},"legalAddress":{"type":"string","description":"Company Address.","x-example":"620 Eighth Avenue, New York, NY 10018"},"legalTaxId":{"type":"string","description":"Company Tax ID.","x-example":"131102020"},"authDuration":{"type":"integer","description":"Session duration in seconds.","x-example":60,"format":"int32"},"authLimit":{"type":"integer","description":"Max users allowed. 0 is unlimited.","x-example":100,"format":"int32"},"authSessionsLimit":{"type":"integer","description":"Max sessions allowed per user. 100 maximum.","x-example":10,"format":"int32"},"authPasswordHistory":{"type":"integer","description":"Max allowed passwords in the history list per user. Max passwords limit allowed in history is 20. Use 0 for disabling password history.","x-example":5,"format":"int32"},"authPasswordDictionary":{"type":"boolean","description":"Whether or not to check user's password against most commonly used passwords.","x-example":true},"authPersonalDataCheck":{"type":"boolean","description":"Whether or not to check the user password for similarity with their personal data.","x-example":true},"providers":{"type":"array","description":"List of Providers.","items":{"type":"object","$ref":"#\/definitions\/provider"},"x-example":[{}]},"platforms":{"type":"array","description":"List of Platforms.","items":{"type":"object","$ref":"#\/definitions\/platform"},"x-example":{}},"webhooks":{"type":"array","description":"List of Webhooks.","items":{"type":"object","$ref":"#\/definitions\/webhook"},"x-example":{}},"keys":{"type":"array","description":"List of API Keys.","items":{"type":"object","$ref":"#\/definitions\/key"},"x-example":{}},"domains":{"type":"array","description":"List of Domains.","items":{"type":"object","$ref":"#\/definitions\/domain"},"x-example":{}},"smtpEnabled":{"type":"boolean","description":"Status for custom SMTP","x-example":false},"smtpSender":{"type":"string","description":"SMTP sender email","x-example":"john@appwrite.io"},"smtpHost":{"type":"string","description":"SMTP server host name","x-example":"mail.appwrite.io"},"smtpPort":{"type":"integer","description":"SMTP server port","x-example":25,"format":"int32"},"smtpUsername":{"type":"string","description":"SMTP server username","x-example":"emailuser"},"smtpPassword":{"type":"string","description":"SMTP server password","x-example":"securepassword"},"smtpSecure":{"type":"string","description":"SMTP server secure protocol","x-example":"tls"},"authEmailPassword":{"type":"boolean","description":"Email\/Password auth method status","x-example":true},"authUsersAuthMagicURL":{"type":"boolean","description":"Magic URL auth method status","x-example":true},"authAnonymous":{"type":"boolean","description":"Anonymous auth method status","x-example":true},"authInvites":{"type":"boolean","description":"Invites auth method status","x-example":true},"authJWT":{"type":"boolean","description":"JWT auth method status","x-example":true},"authPhone":{"type":"boolean","description":"Phone auth method status","x-example":true},"serviceStatusForAccount":{"type":"boolean","description":"Account service status","x-example":true},"serviceStatusForAvatars":{"type":"boolean","description":"Avatars service status","x-example":true},"serviceStatusForDatabases":{"type":"boolean","description":"Databases service status","x-example":true},"serviceStatusForLocale":{"type":"boolean","description":"Locale service status","x-example":true},"serviceStatusForHealth":{"type":"boolean","description":"Health service status","x-example":true},"serviceStatusForStorage":{"type":"boolean","description":"Storage service status","x-example":true},"serviceStatusForTeams":{"type":"boolean","description":"Teams service status","x-example":true},"serviceStatusForUsers":{"type":"boolean","description":"Users service status","x-example":true},"serviceStatusForFunctions":{"type":"boolean","description":"Functions service status","x-example":true},"serviceStatusForGraphql":{"type":"boolean","description":"GraphQL service status","x-example":true}},"required":["$id","$createdAt","$updatedAt","name","description","teamId","logo","url","legalName","legalCountry","legalState","legalCity","legalAddress","legalTaxId","authDuration","authLimit","authSessionsLimit","authPasswordHistory","authPasswordDictionary","authPersonalDataCheck","providers","platforms","webhooks","keys","domains","smtpEnabled","smtpSender","smtpHost","smtpPort","smtpUsername","smtpPassword","smtpSecure","authEmailPassword","authUsersAuthMagicURL","authAnonymous","authInvites","authJWT","authPhone","serviceStatusForAccount","serviceStatusForAvatars","serviceStatusForDatabases","serviceStatusForLocale","serviceStatusForHealth","serviceStatusForStorage","serviceStatusForTeams","serviceStatusForUsers","serviceStatusForFunctions","serviceStatusForGraphql"]},"webhook":{"description":"Webhook","type":"object","properties":{"$id":{"type":"string","description":"Webhook ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Webhook creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Webhook update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Webhook name.","x-example":"My Webhook"},"url":{"type":"string","description":"Webhook URL endpoint.","x-example":"https:\/\/example.com\/webhook"},"events":{"type":"array","description":"Webhook trigger events.","items":{"type":"string"},"x-example":"database.collections.update"},"security":{"type":"boolean","description":"Indicated if SSL \/ TLS Certificate verification is enabled.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"},"signatureKey":{"type":"string","description":"Signature key which can be used to validated incoming","x-example":"ad3d581ca230e2b7059c545e5a"}},"required":["$id","$createdAt","$updatedAt","name","url","events","security","httpUser","httpPass","signatureKey"]},"key":{"description":"Key","type":"object","properties":{"$id":{"type":"string","description":"Key ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Key creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Key update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Key name.","x-example":"My API Key"},"expire":{"type":"string","description":"Key expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"scopes":{"type":"array","description":"Allowed permission scopes.","items":{"type":"string"},"x-example":"users.read"},"secret":{"type":"string","description":"Secret key.","x-example":"919c2d18fb5d4...a2ae413da83346ad2"},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"},"sdks":{"type":"array","description":"List of SDK user agents that used this key.","items":{"type":"string"},"x-example":"appwrite:flutter"}},"required":["$id","$createdAt","$updatedAt","name","expire","scopes","secret","accessedAt","sdks"]},"domain":{"description":"Domain","type":"object","properties":{"$id":{"type":"string","description":"Domain ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Domain creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Domain update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"domain":{"type":"string","description":"Domain name.","x-example":"appwrite.company.com"},"registerable":{"type":"string","description":"Registerable domain name.","x-example":"company.com"},"tld":{"type":"string","description":"TLD name.","x-example":"com"},"verification":{"type":"boolean","description":"Verification process status.","x-example":true},"certificateId":{"type":"string","description":"Certificate ID.","x-example":"6ejea5c13377e"}},"required":["$id","$createdAt","$updatedAt","domain","registerable","tld","verification","certificateId"]},"provider":{"description":"Provider","type":"object","properties":{"key":{"type":"string","description":"Provider.","x-example":"github"},"name":{"type":"string","description":"Provider name.","x-example":"GitHub"},"appId":{"type":"string","description":"OAuth 2.0 application ID.","x-example":"259125845563242502"},"secret":{"type":"string","description":"OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.","x-example":"Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ"},"enabled":{"type":"boolean","description":"Provider is active and can be used to create session.","x-example":""}},"required":["key","name","appId","secret","enabled"]},"platform":{"description":"Platform","type":"object","properties":{"$id":{"type":"string","description":"Platform ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Platform creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Platform update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Platform name.","x-example":"My Web App"},"type":{"type":"string","description":"Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, and unity.","x-example":"web"},"key":{"type":"string","description":"Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.","x-example":"com.company.appname"},"store":{"type":"string","description":"App store or Google Play store ID.","x-example":""},"hostname":{"type":"string","description":"Web app hostname. Empty string for other platforms.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"}},"required":["$id","$createdAt","$updatedAt","name","type","key","store","hostname","httpUser","httpPass"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"}},"required":["$id","$createdAt","$updatedAt","key","value","functionId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"metric":{"description":"Metric","type":"object","properties":{"value":{"type":"integer","description":"The value of this metric at the timestamp.","x-example":1,"format":"int32"},"date":{"type":"string","description":"The date at which this metric was aggregated in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["value","date"]},"usageDatabases":{"description":"UsageDatabases","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"databasesTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsTotal":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","databasesTotal","collectionsTotal","documentsTotal"]},"usageDatabase":{"description":"UsageDatabase","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"collectionsTotal":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","collectionsTotal","documentsTotal"]},"usageCollection":{"description":"UsageCollection","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsTotal":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","documentsTotal"]},"usageUsers":{"description":"UsageUsers","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"usersTotal":{"type":"array","description":"Aggregated stats for total number of users.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"sessionsTotal":{"type":"array","description":"Aggregated stats for sessions created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","usersTotal","sessionsTotal"]},"usageStorage":{"description":"StorageUsage","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"bucketsTotal":{"type":"array","description":"Aggregated stats for total number of buckets.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesTotal":{"type":"array","description":"Aggregated stats for total number of files.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","bucketsTotal","filesTotal","filesStorage"]},"usageBuckets":{"description":"UsageBuckets","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"filesTotal":{"type":"array","description":"Aggregated stats for total number of files in this bucket.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for total storage of files in this bucket.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","filesTotal","filesStorage"]},"usageFunctions":{"description":"UsageFunctions","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"functionsTotal":{"type":"array","description":"Aggregated stats for number of functions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"deploymentsTotal":{"type":"array","description":"Aggregated stats for number of function deployments.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"deploymentsStorage":{"type":"array","description":"Aggregated stats for function deployments storage.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsTotal":{"type":"array","description":"Aggregated stats for number of function builds.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsStorage":{"type":"array","description":"Aggregated stats for builds storage.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsTime":{"type":"array","description":"Aggregated stats for function build compute.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsTotal":{"type":"array","description":"Aggregated stats for number of function executions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsTime":{"type":"array","description":"Aggregated stats for function execution compute.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","functionsTotal","deploymentsTotal","deploymentsStorage","buildsTotal","buildsStorage","buildsTime","executionsTotal","executionsTime"]},"usageProject":{"description":"UsageProject","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"requestsTotal":{"type":"array","description":"Aggregated stats for number of requests.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"network":{"type":"array","description":"Aggregated stats for consumed bandwidth.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsTotal":{"type":"array","description":"Aggregated stats for function executions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsTotal":{"type":"array","description":"Aggregated stats for number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesTotal":{"type":"array","description":"Aggregated stats for number of databases.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersTotal":{"type":"array","description":"Aggregated stats for number of users.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsTotal":{"type":"array","description":"Aggregated stats for number of buckets.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","requestsTotal","network","executionsTotal","documentsTotal","databasesTotal","usersTotal","filesStorage","bucketsTotal"]},"smsTemplate":{"description":"SmsTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."}},"required":["type","locale","message"]},"emailTemplate":{"description":"EmailTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."},"senderName":{"type":"string","description":"Name of the sender","x-example":"My User"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"mail@appwrite.io"},"replyTo":{"type":"string","description":"Reply to email address","x-example":"emails@appwrite.io"},"subject":{"type":"string","description":"Email subject","x-example":"Please verify your email address"}},"required":["type","locale","message","senderName","senderEmail","replyTo","subject"]},"consoleVariables":{"description":"Console Variables","type":"object","properties":{"_APP_DOMAIN_TARGET":{"type":"string","description":"CNAME target for your Appwrite custom domains.","x-example":"appwrite.io"},"_APP_STORAGE_LIMIT":{"type":"integer","description":"Maximum file size allowed for file upload in bytes.","x-example":"30000000","format":"int32"},"_APP_FUNCTIONS_SIZE_LIMIT":{"type":"integer","description":"Maximum file size allowed for deployment in bytes.","x-example":"30000000","format":"int32"},"_APP_USAGE_STATS":{"type":"string","description":"Defines if usage stats are enabled. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'.","x-example":"enabled"}},"required":["_APP_DOMAIN_TARGET","_APP_STORAGE_LIMIT","_APP_FUNCTIONS_SIZE_LIMIT","_APP_USAGE_STATS"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}},"Mode":{"type":"apiKey","name":"X-Appwrite-Mode","description":"","in":"header","x-appwrite":{"demo":""}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"post":{"summary":"Create Account","operationId":"accountCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [\/account\/verfication](\/docs\/client\/account#accountCreateVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](\/docs\/client\/account#accountCreateSession).","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"account\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/account\/jwt":{"post":{"summary":"Create JWT","operationId":"accountCreateJWT","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.","responses":{"201":{"description":"JWT","schema":{"$ref":"#\/definitions\/jwt"}}},"x-appwrite":{"method":"createJWT","cookies":false,"type":"","demo":"account\/create-j-w-t.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-jwt.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/anonymous":{"post":{"summary":"Create Anonymous Session","operationId":"accountCreateAnonymousSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](\/docs\/client\/account#accountUpdateEmail) or create an [OAuth2 session](\/docs\/client\/account#accountCreateOAuth2Session).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createAnonymousSession","cookies":false,"type":"","demo":"account\/create-anonymous-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-anonymous.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/account\/sessions\/email":{"post":{"summary":"Create Email Session","operationId":"accountCreateEmailSession","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"createEmailSession","cookies":false,"type":"","demo":"account\/create-email-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-email.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/sessions\/magic-url":{"post":{"summary":"Create Magic URL session","operationId":"accountCreateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/magic-url](\/docs\/client\/account#accountUpdateMagicURLSession) 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](\/docs\/authentication-security#limits).\n","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createMagicURLSession","cookies":false,"type":"","demo":"account\/create-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-email}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":"","x-example":"https:\/\/example.com"}},"required":["userId","email"]}}]},"put":{"summary":"Create Magic URL session (confirmation)","operationId":"accountUpdateMagicURLSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating the session with the Magic URL. 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\/sessions\/magic-url](\/docs\/client\/account#accountCreateMagicURLSession) 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.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateMagicURLSession","cookies":false,"type":"","demo":"account\/update-magic-u-r-l-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-magic-url-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/oauth2\/{provider}":{"get":{"summary":"Create OAuth2 Session","operationId":"accountCreateOAuth2Session","consumes":["application\/json"],"produces":["text\/html"],"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](\/docs\/authentication-security#limits).\n","responses":{"301":{"description":"No content"}},"x-appwrite":{"method":"createOAuth2Session","cookies":false,"type":"webAuth","demo":"account\/create-o-auth2session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-session-oauth2.md","rate-limit":50,"rate-time":3600,"rate-key":"ip:{ip}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"provider","description":"OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.","required":true,"type":"string","x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":"Provider","x-enum-keys":[],"in":"path"},{"name":"success","description":"URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"failure","description":"URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's 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.","required":false,"type":"string","format":"url","x-example":"https:\/\/example.com","default":"","in":"query"},{"name":"scopes","description":"A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/sessions\/phone":{"post":{"summary":"Create Phone session","operationId":"accountCreatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"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 [PUT \/account\/sessions\/phone](\/docs\/client\/account#accountUpdatePhoneSession) 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](\/docs\/authentication-security#limits).","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneSession","cookies":false,"type":"","demo":"account\/create-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},email:{param-phone}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"}},"required":["userId","phone"]}}]},"put":{"summary":"Create Phone Session (confirmation)","operationId":"accountUpdatePhoneSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](\/docs\/client\/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updatePhoneSession","cookies":false,"type":"","demo":"account\/update-phone-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/console\/assistant":{"post":{"summary":"Ask Query","operationId":"assistantChat","consumes":["application\/json"],"produces":["text\/plain"],"tags":["assistant"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"chat","cookies":false,"type":"","demo":"assistant\/chat.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/assistant\/chat.md","rate-limit":15,"rate-time":3600,"rate-key":"userId:{userId}","scope":"assistant.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prompt":{"type":"string","description":"Prompt. A string containing questions asked to the AI assistant.","default":null,"x-example":"[PROMPT]"}},"required":["prompt"]}}]}},"\/console\/variables":{"get":{"summary":"Get Variables","operationId":"consoleVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["console"],"description":"Get all Environment Variables that are relevant for the console.","responses":{"200":{"description":"Console Variables","schema":{"$ref":"#\/definitions\/consoleVariables"}}},"x-appwrite":{"method":"variables","cookies":false,"type":"","demo":"console\/variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/console\/variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","schema":{"$ref":"#\/definitions\/databaseList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["databaseId","name"]}}]}},"\/databases\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabases","schema":{"$ref":"#\/definitions\/usageDatabases"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"databases\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"`Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Database","operationId":"databasesDelete","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","schema":{"$ref":"#\/definitions\/collectionList"}}},"x-appwrite":{"method":"listCollections","cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"createCollection","cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["collectionId","name"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"getCollection","cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"updateCollection","cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","schema":{"$ref":"#\/definitions\/attributeList"}}},"x-appwrite":{"method":"listAttributes","cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"createBooleanAttribute","cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"updateBooleanAttribute","cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"createDatetimeAttribute","cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"updateDatetimeAttribute","cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"createEmailAttribute","cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"updateEmailAttribute","cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"createEnumAttribute","cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","elements","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"updateEnumAttribute","cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"createFloatAttribute","cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"updateFloatAttribute","cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"createIntegerAttribute","cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"updateIntegerAttribute","cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"createIpAttribute","cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"updateIpAttribute","cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"createRelationshipAttribute","cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","default":null,"x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","default":null,"x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","default":false,"x-example":false},"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","default":null,"x-example":null},"onDelete":{"type":"string","description":"Constraints option","default":"restrict","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"createStringAttribute","cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","default":null,"x-example":1},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false},"encrypt":{"type":"boolean","description":"Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.","default":false,"x-example":false}},"required":["key","size","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"updateStringAttribute","cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"createUrlAttribute","cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"updateUrlAttribute","cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","schema":{"x-oneOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]}}},"x-appwrite":{"method":"getAttribute","cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"updateRelationshipAttribute","cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","default":null,"x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/logs":{"get":{"summary":"List Document Logs","operationId":"databasesListDocumentLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the document activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listDocumentLogs","cookies":false,"type":"","demo":"databases\/list-document-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","schema":{"$ref":"#\/definitions\/indexList"}}},"x-appwrite":{"method":"listIndexes","cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"createIndex","cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","default":null,"x-example":null},"type":{"type":"string","description":"Index type.","default":null,"x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","default":[],"x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"getIndex","cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/logs":{"get":{"summary":"List Collection Logs","operationId":"databasesListCollectionLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the collection activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listCollectionLogs","cookies":false,"type":"","demo":"databases\/list-collection-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/usage":{"get":{"summary":"Get usage stats for a collection","operationId":"databasesGetCollectionUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageCollection","schema":{"$ref":"#\/definitions\/usageCollection"}}},"x-appwrite":{"method":"getCollectionUsage","cookies":false,"type":"","demo":"databases\/get-collection-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/logs":{"get":{"summary":"List Database Logs","operationId":"databasesListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get the database activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"databases\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/usage":{"get":{"summary":"Get usage stats for the database","operationId":"databasesGetDatabaseUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"UsageDatabase","schema":{"$ref":"#\/definitions\/usageDatabase"}}},"x-appwrite":{"method":"getDatabaseUsage","cookies":false,"type":"","demo":"databases\/get-database-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"range","description":"`Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","schema":{"$ref":"#\/definitions\/functionList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","default":true,"x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","default":true,"x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","default":"","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","default":"","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Control System) deployment.","default":"","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function.","default":"","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function.","default":"","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","default":false,"x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"},"templateRepository":{"type":"string","description":"Repository name of the template.","default":"","x-example":"[TEMPLATE_REPOSITORY]"},"templateOwner":{"type":"string","description":"The name of the owner of the template.","default":"","x-example":"[TEMPLATE_OWNER]"},"templateRootDirectory":{"type":"string","description":"Path to function code in the template repo.","default":"","x-example":"[TEMPLATE_ROOT_DIRECTORY]"},"templateBranch":{"type":"string","description":"Production branch for the repo linked to the function template.","default":"","x-example":"[TEMPLATE_BRANCH]"}},"required":["functionId","name","runtime"]}}]}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","schema":{"$ref":"#\/definitions\/runtimeList"}}},"x-appwrite":{"method":"listRuntimes","cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/usage":{"get":{"summary":"Get Functions Usage","operationId":"functionsGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","schema":{"$ref":"#\/definitions\/usageFunctions"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"functions\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","default":true,"x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","default":true,"x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","default":"","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","default":"","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Controle System) deployment.","default":"","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function","default":"","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function","default":"","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","default":false,"x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"}},"required":["name","runtime"]}}]},"delete":{"summary":"Delete Function","operationId":"functionsDelete","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","schema":{"$ref":"#\/definitions\/deploymentList"}}},"x-appwrite":{"method":"listDeployments","cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: size, buildId, activate, entrypoint, commands","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","consumes":["multipart\/form-data"],"produces":["application\/json"],"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](\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.","responses":{"202":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"createDeployment","cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"entrypoint","description":"Entrypoint File.","required":false,"type":"string","x-example":"[ENTRYPOINT]","in":"formData"},{"name":"commands","description":"Build Commands.","required":false,"type":"string","x-example":"[COMMANDS]","in":"formData"},{"name":"code","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","required":true,"type":"file","in":"formData"},{"name":"activate","description":"Automatically activate the deployment when it is finished building.","required":true,"type":"boolean","x-example":false,"in":"formData"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"getDeployment","cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"updateDeployment","cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Create a new build for an Appwrite Function deployment. This endpoint can be used to retry a failed build.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"type":"string","x-example":"[BUILD_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/download":{"get":{"summary":"Download Deployment","operationId":"functionsDownloadDeployment","consumes":["application\/json"],"produces":["*\/*"],"tags":["functions"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"downloadDeployment","cookies":false,"type":"location","demo":"functions\/download-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/download-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","default":"","x-example":"[BODY]"},"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":"[PATH]"},"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":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","default":[],"x-example":"{}"}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/usage":{"get":{"summary":"Get Function Usage","operationId":"functionsGetFunctionUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"","responses":{"200":{"description":"UsageFunctions","schema":{"$ref":"#\/definitions\/usageFunctions"}}},"x-appwrite":{"method":"getFunctionUsage","cookies":false,"type":"","demo":"functions\/get-function-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","schema":{"$ref":"#\/definitions\/healthAntivirus"}}},"x-appwrite":{"method":"getAntivirus","cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getCache","cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getDB","cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getPubSub","cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getQueue","cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueCertificates","cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueFunctions","cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueLogs","cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueWebhooks","cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getStorageLocal","cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","schema":{"$ref":"#\/definitions\/healthTime"}}},"x-appwrite":{"method":"getTime","cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/migrations":{"get":{"summary":"List Migrations","operationId":"migrationsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migrations List","schema":{"$ref":"#\/definitions\/migrationList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"migrations\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/list-migrations.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: status, stage, source, resources, statusCounters, resourceData, errors","required":false,"type":"string","default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]}},"\/migrations\/appwrite":{"post":{"summary":"Migrate Appwrite Data","operationId":"migrationsCreateAppwriteMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createAppwriteMigration","cookies":false,"type":"","demo":"migrations\/create-appwrite-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-appwrite.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"endpoint":{"type":"string","description":"Source's Appwrite Endpoint","default":null,"x-example":"https:\/\/example.com"},"projectId":{"type":"string","description":"Source's Project ID","default":null,"x-example":"[PROJECT_ID]"},"apiKey":{"type":"string","description":"Source's API Key","default":null,"x-example":"[API_KEY]"}},"required":["resources","endpoint","projectId","apiKey"]}}]}},"\/migrations\/appwrite\/report":{"get":{"summary":"Generate a report on Appwrite Data","operationId":"migrationsGetAppwriteReport","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getAppwriteReport","cookies":false,"type":"","demo":"migrations\/get-appwrite-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-appwrite-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"endpoint","description":"Source's Appwrite Endpoint","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"projectID","description":"Source's Project ID","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"query"},{"name":"key","description":"Source's API Key","required":true,"type":"string","x-example":"[KEY]","in":"query"}]}},"\/migrations\/firebase":{"post":{"summary":"Migrate Firebase Data (Service Account)","operationId":"migrationsCreateFirebaseMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createFirebaseMigration","cookies":false,"type":"","demo":"migrations\/create-firebase-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"serviceAccount":{"type":"string","description":"JSON of the Firebase service account credentials","default":null,"x-example":"[SERVICE_ACCOUNT]"}},"required":["resources","serviceAccount"]}}]}},"\/migrations\/firebase\/deauthorize":{"get":{"summary":"Revoke Appwrite's authorization to access Firebase Projects","operationId":"migrationsDeleteFirebaseAuth","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"deleteFirebaseAuth","cookies":false,"type":"","demo":"migrations\/delete-firebase-auth.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/migrations\/firebase\/oauth":{"post":{"summary":"Migrate Firebase Data (OAuth)","operationId":"migrationsCreateFirebaseOAuthMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createFirebaseOAuthMigration","cookies":false,"type":"","demo":"migrations\/create-firebase-o-auth-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"projectId":{"type":"string","description":"Project ID of the Firebase Project","default":null,"x-example":"[PROJECT_ID]"}},"required":["resources","projectId"]}}]}},"\/migrations\/firebase\/projects":{"get":{"summary":"List Firebase Projects","operationId":"migrationsListFirebaseProjects","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migrations Firebase Projects List","schema":{"$ref":"#\/definitions\/firebaseProjectList"}}},"x-appwrite":{"method":"listFirebaseProjects","cookies":false,"type":"","demo":"migrations\/list-firebase-projects.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]}},"\/migrations\/firebase\/report":{"get":{"summary":"Generate a report on Firebase Data","operationId":"migrationsGetFirebaseReport","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getFirebaseReport","cookies":false,"type":"","demo":"migrations\/get-firebase-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"serviceAccount","description":"JSON of the Firebase service account credentials","required":true,"type":"string","x-example":"[SERVICE_ACCOUNT]","in":"query"}]}},"\/migrations\/firebase\/report\/oauth":{"get":{"summary":"Generate a report on Firebase Data using OAuth","operationId":"migrationsGetFirebaseReportOAuth","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getFirebaseReportOAuth","cookies":false,"type":"","demo":"migrations\/get-firebase-report-o-auth.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-firebase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"projectId","description":"Project ID","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"query"}]}},"\/migrations\/nhost":{"post":{"summary":"Migrate NHost Data","operationId":"migrationsCreateNHostMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createNHostMigration","cookies":false,"type":"","demo":"migrations\/create-n-host-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-nhost.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"subdomain":{"type":"string","description":"Source's Subdomain","default":null,"x-example":"[SUBDOMAIN]"},"region":{"type":"string","description":"Source's Region","default":null,"x-example":"[REGION]"},"adminSecret":{"type":"string","description":"Source's Admin Secret","default":null,"x-example":"[ADMIN_SECRET]"},"database":{"type":"string","description":"Source's Database Name","default":null,"x-example":"[DATABASE]"},"username":{"type":"string","description":"Source's Database Username","default":null,"x-example":"[USERNAME]"},"password":{"type":"string","description":"Source's Database Password","default":null,"x-example":"[PASSWORD]"},"port":{"type":"integer","description":"Source's Database Port","default":5432,"x-example":null}},"required":["resources","subdomain","region","adminSecret","database","username","password"]}}]}},"\/migrations\/nhost\/report":{"get":{"summary":"Generate a report on NHost Data","operationId":"migrationsGetNHostReport","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getNHostReport","cookies":false,"type":"","demo":"migrations\/get-n-host-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-nhost-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate.","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"subdomain","description":"Source's Subdomain.","required":true,"type":"string","x-example":"[SUBDOMAIN]","in":"query"},{"name":"region","description":"Source's Region.","required":true,"type":"string","x-example":"[REGION]","in":"query"},{"name":"adminSecret","description":"Source's Admin Secret.","required":true,"type":"string","x-example":"[ADMIN_SECRET]","in":"query"},{"name":"database","description":"Source's Database Name.","required":true,"type":"string","x-example":"[DATABASE]","in":"query"},{"name":"username","description":"Source's Database Username.","required":true,"type":"string","x-example":"[USERNAME]","in":"query"},{"name":"password","description":"Source's Database Password.","required":true,"type":"string","x-example":"[PASSWORD]","in":"query"},{"name":"port","description":"Source's Database Port.","required":false,"type":"integer","format":"int32","default":5432,"in":"query"}]}},"\/migrations\/supabase":{"post":{"summary":"Migrate Supabase Data","operationId":"migrationsCreateSupabaseMigration","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"createSupabaseMigration","cookies":false,"type":"","demo":"migrations\/create-supabase-migration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-supabase.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"resources":{"type":"array","description":"List of resources to migrate","default":null,"x-example":null,"items":{"type":"string"}},"endpoint":{"type":"string","description":"Source's Supabase Endpoint","default":null,"x-example":"https:\/\/example.com"},"apiKey":{"type":"string","description":"Source's API Key","default":null,"x-example":"[API_KEY]"},"databaseHost":{"type":"string","description":"Source's Database Host","default":null,"x-example":"[DATABASE_HOST]"},"username":{"type":"string","description":"Source's Database Username","default":null,"x-example":"[USERNAME]"},"password":{"type":"string","description":"Source's Database Password","default":null,"x-example":"[PASSWORD]"},"port":{"type":"integer","description":"Source's Database Port","default":5432,"x-example":null}},"required":["resources","endpoint","apiKey","databaseHost","username","password"]}}]}},"\/migrations\/supabase\/report":{"get":{"summary":"Generate a report on Supabase Data","operationId":"migrationsGetSupabaseReport","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration Report","schema":{"$ref":"#\/definitions\/migrationReport"}}},"x-appwrite":{"method":"getSupabaseReport","cookies":false,"type":"","demo":"migrations\/get-supabase-report.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/migration-supabase-report.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"resources","description":"List of resources to migrate","required":true,"type":"array","collectionFormat":"multi","items":{"type":"string"},"in":"query"},{"name":"endpoint","description":"Source's Supabase Endpoint.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"apiKey","description":"Source's API Key.","required":true,"type":"string","x-example":"[API_KEY]","in":"query"},{"name":"databaseHost","description":"Source's Database Host.","required":true,"type":"string","x-example":"[DATABASE_HOST]","in":"query"},{"name":"username","description":"Source's Database Username.","required":true,"type":"string","x-example":"[USERNAME]","in":"query"},{"name":"password","description":"Source's Database Password.","required":true,"type":"string","x-example":"[PASSWORD]","in":"query"},{"name":"port","description":"Source's Database Port.","required":false,"type":"integer","format":"int32","default":5432,"in":"query"}]}},"\/migrations\/{migrationId}":{"get":{"summary":"Get Migration","operationId":"migrationsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"200":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"migrations\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/get-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration unique ID.","required":true,"type":"string","x-example":"[MIGRATION_ID]","in":"path"}]},"patch":{"summary":"Retry Migration","operationId":"migrationsRetry","consumes":["application\/json"],"produces":["application\/json"],"tags":["migrations"],"description":"","responses":{"202":{"description":"Migration","schema":{"$ref":"#\/definitions\/migration"}}},"x-appwrite":{"method":"retry","cookies":false,"type":"","demo":"migrations\/retry.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/migrations\/retry-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration unique ID.","required":true,"type":"string","x-example":"[MIGRATION_ID]","in":"path"}]},"delete":{"summary":"Delete Migration","operationId":"migrationsDelete","consumes":["application\/json"],"produces":[],"tags":["migrations"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"migrations\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-migration.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"migrations.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"migrationId","description":"Migration ID.","required":true,"type":"string","x-example":"[MIGRATION_ID]","in":"path"}]}},"\/project\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"","responses":{"200":{"description":"UsageProject","schema":{"$ref":"#\/definitions\/usageProject"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"project\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/project\/variables":{"get":{"summary":"List Variables","operationId":"projectListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"Get a list of all project variables. These variables will be accessible in all Appwrite Functions at runtime.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","cookies":false,"type":"","demo":"project\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}]},"post":{"summary":"Create Variable","operationId":"projectCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"Create a new project variable. This variable will be accessible in all Appwrite Functions at runtime.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","cookies":false,"type":"","demo":"project\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/project\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"projectGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"Get a project variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","cookies":false,"type":"","demo":"project\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"projectUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["project"],"description":"Update project variable by its unique ID. This variable will be accessible in all Appwrite Functions at runtime.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","cookies":false,"type":"","demo":"project\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"projectDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["project"],"description":"Delete a project variable by its unique ID. ","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","cookies":false,"type":"","demo":"project\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/project\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/projects":{"get":{"summary":"List Projects","operationId":"projectsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Projects List","schema":{"$ref":"#\/definitions\/projectList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"projects\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Project","operationId":"projectsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"projects\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"projectId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":null},"name":{"type":"string","description":"Project name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"teamId":{"type":"string","description":"Team unique ID.","default":null,"x-example":"[TEAM_ID]"},"region":{"type":"string","description":"Project Region.","default":"default","x-example":"default","enum":["default"],"x-enum-name":null,"x-enum-keys":[]},"description":{"type":"string","description":"Project description. Max length: 256 chars.","default":"","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","default":"","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","default":"","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal Name. Max length: 256 chars.","default":"","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal Country. Max length: 256 chars.","default":"","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal State. Max length: 256 chars.","default":"","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal City. Max length: 256 chars.","default":"","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal Address. Max length: 256 chars.","default":"","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal Tax ID. Max length: 256 chars.","default":"","x-example":"[LEGAL_TAX_ID]"}},"required":["projectId","name","teamId"]}}]}},"\/projects\/{projectId}":{"get":{"summary":"Get Project","operationId":"projectsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"projects\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"patch":{"summary":"Update Project","operationId":"projectsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"update","cookies":false,"type":"","demo":"projects\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"description":{"type":"string","description":"Project description. Max length: 256 chars.","default":"","x-example":"[DESCRIPTION]"},"logo":{"type":"string","description":"Project logo.","default":"","x-example":"[LOGO]"},"url":{"type":"string","description":"Project URL.","default":"","x-example":"https:\/\/example.com"},"legalName":{"type":"string","description":"Project legal name. Max length: 256 chars.","default":"","x-example":"[LEGAL_NAME]"},"legalCountry":{"type":"string","description":"Project legal country. Max length: 256 chars.","default":"","x-example":"[LEGAL_COUNTRY]"},"legalState":{"type":"string","description":"Project legal state. Max length: 256 chars.","default":"","x-example":"[LEGAL_STATE]"},"legalCity":{"type":"string","description":"Project legal city. Max length: 256 chars.","default":"","x-example":"[LEGAL_CITY]"},"legalAddress":{"type":"string","description":"Project legal address. Max length: 256 chars.","default":"","x-example":"[LEGAL_ADDRESS]"},"legalTaxId":{"type":"string","description":"Project legal tax ID. Max length: 256 chars.","default":"","x-example":"[LEGAL_TAX_ID]"}},"required":["name"]}}]},"delete":{"summary":"Delete Project","operationId":"projectsDelete","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"projects\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]}},"\/projects\/{projectId}\/auth\/duration":{"patch":{"summary":"Update Project Authentication Duration","operationId":"projectsUpdateAuthDuration","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthDuration","cookies":false,"type":"","demo":"projects\/update-auth-duration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"duration":{"type":"integer","description":"Project session length in seconds. Max length: 31536000 seconds.","default":null,"x-example":0}},"required":["duration"]}}]}},"\/projects\/{projectId}\/auth\/limit":{"patch":{"summary":"Update Project users limit","operationId":"projectsUpdateAuthLimit","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthLimit","cookies":false,"type":"","demo":"projects\/update-auth-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Use 0 for unlimited.","default":null,"x-example":0}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/max-sessions":{"patch":{"summary":"Update Project user sessions limit","operationId":"projectsUpdateAuthSessionsLimit","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthSessionsLimit","cookies":false,"type":"","demo":"projects\/update-auth-sessions-limit.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10","default":null,"x-example":1}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/password-dictionary":{"patch":{"summary":"Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password","operationId":"projectsUpdateAuthPasswordDictionary","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthPasswordDictionary","cookies":false,"type":"","demo":"projects\/update-auth-password-dictionary.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to enable checking user's password against most commonly used passwords. Default is false.","default":null,"x-example":false}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/auth\/password-history":{"patch":{"summary":"Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.","operationId":"projectsUpdateAuthPasswordHistory","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthPasswordHistory","cookies":false,"type":"","demo":"projects\/update-auth-password-history.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0","default":null,"x-example":0}},"required":["limit"]}}]}},"\/projects\/{projectId}\/auth\/personal-data":{"patch":{"summary":"Enable or disable checking user passwords for similarity with their personal data.","operationId":"projectsUpdatePersonalDataCheck","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updatePersonalDataCheck","cookies":false,"type":"","demo":"projects\/update-personal-data-check.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Set whether or not to check a password for similarity with personal data. Default is false.","default":null,"x-example":false}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/auth\/{method}":{"patch":{"summary":"Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.","operationId":"projectsUpdateAuthStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateAuthStatus","cookies":false,"type":"","demo":"projects\/update-auth-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"method","description":"Auth Method. Possible values: email-password,magic-url,anonymous,invites,jwt,phone","required":true,"type":"string","x-example":"email-password","enum":["email-password","magic-url","anonymous","invites","jwt","phone"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Set the status of this auth method.","default":null,"x-example":false}},"required":["status"]}}]}},"\/projects\/{projectId}\/keys":{"get":{"summary":"List Keys","operationId":"projectsListKeys","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"API Keys List","schema":{"$ref":"#\/definitions\/keyList"}}},"x-appwrite":{"method":"listKeys","cookies":false,"type":"","demo":"projects\/list-keys.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Key","operationId":"projectsCreateKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"createKey","cookies":false,"type":"","demo":"projects\/create-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 scopes are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","default":null,"x-example":null}},"required":["name","scopes"]}}]}},"\/projects\/{projectId}\/keys\/{keyId}":{"get":{"summary":"Get Key","operationId":"projectsGetKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"getKey","cookies":false,"type":"","demo":"projects\/get-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"}]},"put":{"summary":"Update Key","operationId":"projectsUpdateKey","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Key","schema":{"$ref":"#\/definitions\/key"}}},"x-appwrite":{"method":"updateKey","cookies":false,"type":"","demo":"projects\/update-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Key name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"scopes":{"type":"array","description":"Key scopes list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"expire":{"type":"string","description":"Expiration time in ISO 8601 format. Use null for unlimited expiration.","default":null,"x-example":null}},"required":["name","scopes"]}}]},"delete":{"summary":"Delete Key","operationId":"projectsDeleteKey","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteKey","cookies":false,"type":"","demo":"projects\/delete-key.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"keyId","description":"Key unique ID.","required":true,"type":"string","x-example":"[KEY_ID]","in":"path"}]}},"\/projects\/{projectId}\/oauth2":{"patch":{"summary":"Update Project OAuth2","operationId":"projectsUpdateOAuth2","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateOAuth2","cookies":false,"type":"","demo":"projects\/update-o-auth2.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"provider":{"type":"string","description":"Provider Name","default":null,"x-example":"amazon","enum":["amazon","apple","auth0","authentik","autodesk","bitbucket","bitly","box","dailymotion","discord","disqus","dropbox","etsy","facebook","github","gitlab","google","linkedin","microsoft","notion","oidc","okta","paypal","paypalSandbox","podio","salesforce","slack","spotify","stripe","tradeshift","tradeshiftBox","twitch","wordpress","yahoo","yammer","yandex","zoom","mock"],"x-enum-name":null,"x-enum-keys":[]},"appId":{"type":"string","description":"Provider app ID. Max length: 256 chars.","default":null,"x-example":"[APP_ID]"},"secret":{"type":"string","description":"Provider secret key. Max length: 512 chars.","default":null,"x-example":"[SECRET]"},"enabled":{"type":"boolean","description":"Provider status. Set to 'false' to disable new session creation.","default":null,"x-example":false}},"required":["provider"]}}]}},"\/projects\/{projectId}\/platforms":{"get":{"summary":"List Platforms","operationId":"projectsListPlatforms","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platforms List","schema":{"$ref":"#\/definitions\/platformList"}}},"x-appwrite":{"method":"listPlatforms","cookies":false,"type":"","demo":"projects\/list-platforms.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Platform","operationId":"projectsCreatePlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"createPlatform","cookies":false,"type":"","demo":"projects\/create-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"type":{"type":"string","description":"Platform type.","default":null,"x-example":"web","enum":["web","flutter-web","flutter-ios","flutter-android","flutter-linux","flutter-macos","flutter-windows","apple-ios","apple-macos","apple-watchos","apple-tvos","android","unity"],"x-enum-name":"PlatformType","x-enum-keys":[]},"name":{"type":"string","description":"Platform name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"key":{"type":"string","description":"Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.","default":"","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","default":"","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client hostname. Max length: 256 chars.","default":"","x-example":null}},"required":["type","name"]}}]}},"\/projects\/{projectId}\/platforms\/{platformId}":{"get":{"summary":"Get Platform","operationId":"projectsGetPlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"getPlatform","cookies":false,"type":"","demo":"projects\/get-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"}]},"put":{"summary":"Update Platform","operationId":"projectsUpdatePlatform","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Platform","schema":{"$ref":"#\/definitions\/platform"}}},"x-appwrite":{"method":"updatePlatform","cookies":false,"type":"","demo":"projects\/update-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Platform name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"key":{"type":"string","description":"Package name for android or bundle ID for iOS. Max length: 256 chars.","default":"","x-example":"[KEY]"},"store":{"type":"string","description":"App store or Google Play store ID. Max length: 256 chars.","default":"","x-example":"[STORE]"},"hostname":{"type":"string","description":"Platform client URL. Max length: 256 chars.","default":"","x-example":null}},"required":["name"]}}]},"delete":{"summary":"Delete Platform","operationId":"projectsDeletePlatform","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deletePlatform","cookies":false,"type":"","demo":"projects\/delete-platform.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"platformId","description":"Platform unique ID.","required":true,"type":"string","x-example":"[PLATFORM_ID]","in":"path"}]}},"\/projects\/{projectId}\/service":{"patch":{"summary":"Update service status","operationId":"projectsUpdateServiceStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateServiceStatus","cookies":false,"type":"","demo":"projects\/update-service-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"service":{"type":"string","description":"Service name.","default":null,"x-example":"account","enum":["account","avatars","databases","locale","health","storage","teams","users","vcs","functions","proxy","graphql","migrations"],"x-enum-name":null,"x-enum-keys":[]},"status":{"type":"boolean","description":"Service status.","default":null,"x-example":false}},"required":["service","status"]}}]}},"\/projects\/{projectId}\/service\/all":{"patch":{"summary":"Update all service status","operationId":"projectsUpdateServiceStatusAll","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateServiceStatusAll","cookies":false,"type":"","demo":"projects\/update-service-status-all.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"Service status.","default":null,"x-example":false}},"required":["status"]}}]}},"\/projects\/{projectId}\/smtp":{"patch":{"summary":"Update SMTP configuration","operationId":"projectsUpdateSmtpConfiguration","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateSmtpConfiguration","cookies":false,"type":"","demo":"projects\/update-smtp-configuration.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable custom SMTP service","default":null,"x-example":false},"senderName":{"type":"string","description":"Name of the email sender","default":"","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","default":"","x-example":"email@example.com"},"replyTo":{"type":"string","description":"Reply to email","default":"","x-example":"email@example.com"},"host":{"type":"string","description":"SMTP server host name","default":"","x-example":null},"port":{"type":"integer","description":"SMTP server port","default":587,"x-example":null},"username":{"type":"string","description":"SMTP server username","default":"","x-example":"[USERNAME]"},"password":{"type":"string","description":"SMTP server password","default":"","x-example":"[PASSWORD]"},"secure":{"type":"string","description":"Does SMTP server use secure connection","default":"","x-example":"tls","enum":["tls"],"x-enum-name":null,"x-enum-keys":[]}},"required":["enabled"]}}]}},"\/projects\/{projectId}\/team":{"patch":{"summary":"Update Project Team","operationId":"projectsUpdateTeam","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateTeam","cookies":false,"type":"","demo":"projects\/update-team.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID of the team to transfer project to.","default":null,"x-example":"[TEAM_ID]"}},"required":["teamId"]}}]}},"\/projects\/{projectId}\/templates\/email\/{type}\/{locale}":{"get":{"summary":"Get custom email template","operationId":"projectsGetEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","schema":{"$ref":"#\/definitions\/emailTemplate"}}},"x-appwrite":{"method":"getEmailTemplate","cookies":false,"type":"","demo":"projects\/get-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]},"patch":{"summary":"Update custom email templates","operationId":"projectsUpdateEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Project","schema":{"$ref":"#\/definitions\/project"}}},"x-appwrite":{"method":"updateEmailTemplate","cookies":false,"type":"","demo":"projects\/update-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"subject":{"type":"string","description":"Email Subject","default":null,"x-example":"[SUBJECT]"},"message":{"type":"string","description":"Template message","default":null,"x-example":"[MESSAGE]"},"senderName":{"type":"string","description":"Name of the email sender","default":"","x-example":"[SENDER_NAME]"},"senderEmail":{"type":"string","description":"Email of the sender","default":"","x-example":"email@example.com"},"replyTo":{"type":"string","description":"Reply to email","default":"","x-example":"email@example.com"}},"required":["subject","message"]}}]},"delete":{"summary":"Reset custom email template","operationId":"projectsDeleteEmailTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"EmailTemplate","schema":{"$ref":"#\/definitions\/emailTemplate"}}},"x-appwrite":{"method":"deleteEmailTemplate","cookies":false,"type":"","demo":"projects\/delete-email-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","magicsession","recovery","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]}},"\/projects\/{projectId}\/templates\/sms\/{type}\/{locale}":{"get":{"summary":"Get custom SMS template","operationId":"projectsGetSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"getSmsTemplate","cookies":false,"type":"","demo":"projects\/get-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]},"patch":{"summary":"Update custom SMS template","operationId":"projectsUpdateSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"updateSmsTemplate","cookies":false,"type":"","demo":"projects\/update-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"message":{"type":"string","description":"Template message","default":null,"x-example":"[MESSAGE]"}},"required":["message"]}}]},"delete":{"summary":"Reset custom SMS template","operationId":"projectsDeleteSmsTemplate","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"SmsTemplate","schema":{"$ref":"#\/definitions\/smsTemplate"}}},"x-appwrite":{"method":"deleteSmsTemplate","cookies":false,"type":"","demo":"projects\/delete-sms-template.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"type","description":"Template type","required":true,"type":"string","x-example":"verification","enum":["verification","login","invitation"],"x-enum-name":null,"x-enum-keys":[],"in":"path"},{"name":"locale","description":"Template locale","required":true,"type":"string","x-example":"af","enum":["af","ar-ae","ar-bh","ar-dz","ar-eg","ar-iq","ar-jo","ar-kw","ar-lb","ar-ly","ar-ma","ar-om","ar-qa","ar-sa","ar-sy","ar-tn","ar-ye","as","az","be","bg","bh","bn","bs","ca","cs","cy","da","de","de-at","de-ch","de-li","de-lu","el","en","en-au","en-bz","en-ca","en-gb","en-ie","en-jm","en-nz","en-tt","en-us","en-za","eo","es","es-ar","es-bo","es-cl","es-co","es-cr","es-do","es-ec","es-gt","es-hn","es-mx","es-ni","es-pa","es-pe","es-pr","es-py","es-sv","es-uy","es-ve","et","eu","fa","fi","fo","fr","fr-be","fr-ca","fr-ch","fr-lu","ga","gd","he","hi","hr","hu","id","is","it","it-ch","ja","ji","ko","ku","lt","lv","mk","ml","ms","mt","nb","ne","nl","nl-be","nn","no","pa","pl","pt","pt-br","rm","ro","ro-md","ru","ru-md","sb","sk","sl","sq","sr","sv","sv-fi","th","tn","tr","ts","ua","ur","ve","vi","xh","zh-cn","zh-hk","zh-sg","zh-tw","zu"],"x-enum-name":null,"x-enum-keys":[],"in":"path"}]}},"\/projects\/{projectId}\/usage":{"get":{"summary":"Get usage stats for a project","operationId":"projectsGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"UsageProject","schema":{"$ref":"#\/definitions\/usageProject"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"projects\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":[],"default":"30d","in":"query"}]}},"\/projects\/{projectId}\/webhooks":{"get":{"summary":"List Webhooks","operationId":"projectsListWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhooks List","schema":{"$ref":"#\/definitions\/webhookList"}}},"x-appwrite":{"method":"listWebhooks","cookies":false,"type":"","demo":"projects\/list-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"}]},"post":{"summary":"Create Webhook","operationId":"projectsCreateWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"201":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"createWebhook","cookies":false,"type":"","demo":"projects\/create-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","default":null,"x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","default":null,"x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","default":"","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","default":"","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}":{"get":{"summary":"Get Webhook","operationId":"projectsGetWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"getWebhook","cookies":false,"type":"","demo":"projects\/get-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]},"put":{"summary":"Update Webhook","operationId":"projectsUpdateWebhook","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"updateWebhook","cookies":false,"type":"","demo":"projects\/update-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"Webhook URL.","default":null,"x-example":"https:\/\/example.com"},"security":{"type":"boolean","description":"Certificate verification, false for disabled or true for enabled.","default":null,"x-example":false},"httpUser":{"type":"string","description":"Webhook HTTP user. Max length: 256 chars.","default":"","x-example":"[HTTP_USER]"},"httpPass":{"type":"string","description":"Webhook HTTP password. Max length: 256 chars.","default":"","x-example":"[HTTP_PASS]"}},"required":["name","events","url","security"]}}]},"delete":{"summary":"Delete Webhook","operationId":"projectsDeleteWebhook","consumes":["application\/json"],"produces":[],"tags":["projects"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteWebhook","cookies":false,"type":"","demo":"projects\/delete-webhook.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]}},"\/projects\/{projectId}\/webhooks\/{webhookId}\/signature":{"patch":{"summary":"Update Webhook Signature Key","operationId":"projectsUpdateWebhookSignature","consumes":["application\/json"],"produces":["application\/json"],"tags":["projects"],"description":"","responses":{"200":{"description":"Webhook","schema":{"$ref":"#\/definitions\/webhook"}}},"x-appwrite":{"method":"updateWebhookSignature","cookies":false,"type":"","demo":"projects\/update-webhook-signature.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"projects.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"projectId","description":"Project unique ID.","required":true,"type":"string","x-example":"[PROJECT_ID]","in":"path"},{"name":"webhookId","description":"Webhook unique ID.","required":true,"type":"string","x-example":"[WEBHOOK_ID]","in":"path"}]}},"\/proxy\/rules":{"get":{"summary":"List Rules","operationId":"proxyListRules","consumes":["application\/json"],"produces":["application\/json"],"tags":["proxy"],"description":"Get a list of all the proxy rules. You can use the query params to filter your results.","responses":{"200":{"description":"Rule List","schema":{"$ref":"#\/definitions\/proxyRuleList"}}},"x-appwrite":{"method":"listRules","cookies":false,"type":"","demo":"proxy\/list-rules.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/list-rules.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: domain, resourceType, resourceId, url","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Rule","operationId":"proxyCreateRule","consumes":["application\/json"],"produces":["application\/json"],"tags":["proxy"],"description":"Create a new proxy rule.","responses":{"201":{"description":"Rule","schema":{"$ref":"#\/definitions\/proxyRule"}}},"x-appwrite":{"method":"createRule","cookies":false,"type":"","demo":"proxy\/create-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/create-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain name.","default":null,"x-example":null},"resourceType":{"type":"string","description":"Action definition for the rule. Possible values are \"api\", \"function\"","default":null,"x-example":"api","enum":["api","function"],"x-enum-name":null,"x-enum-keys":[]},"resourceId":{"type":"string","description":"ID of resource for the action type. If resourceType is \"api\", leave empty. If resourceType is \"function\", provide ID of the function.","default":"","x-example":"[RESOURCE_ID]"}},"required":["domain","resourceType"]}}]}},"\/proxy\/rules\/{ruleId}":{"get":{"summary":"Get Rule","operationId":"proxyGetRule","consumes":["application\/json"],"produces":["application\/json"],"tags":["proxy"],"description":"Get a proxy rule by its unique ID.","responses":{"200":{"description":"Rule","schema":{"$ref":"#\/definitions\/proxyRule"}}},"x-appwrite":{"method":"getRule","cookies":false,"type":"","demo":"proxy\/get-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/get-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"type":"string","x-example":"[RULE_ID]","in":"path"}]},"delete":{"summary":"Delete Rule","operationId":"proxyDeleteRule","consumes":["application\/json"],"produces":[],"tags":["proxy"],"description":"Delete a proxy rule by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteRule","cookies":false,"type":"","demo":"proxy\/delete-rule.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/proxy\/delete-rule.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"type":"string","x-example":"[RULE_ID]","in":"path"}]}},"\/proxy\/rules\/{ruleId}\/verification":{"patch":{"summary":"Update Rule Verification Status","operationId":"proxyUpdateRuleVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["proxy"],"description":"","responses":{"200":{"description":"Rule","schema":{"$ref":"#\/definitions\/proxyRule"}}},"x-appwrite":{"method":"updateRuleVerification","cookies":false,"type":"","demo":"proxy\/update-rule-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"rules.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"ruleId","description":"Rule ID.","required":true,"type":"string","x-example":"[RULE_ID]","in":"path"}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","schema":{"$ref":"#\/definitions\/bucketList"}}},"x-appwrite":{"method":"listBuckets","cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"createBucket","cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","default":30000000,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["bucketId","name"]}}]}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"getBucket","cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"updateBucket","cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","default":null,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/usage":{"get":{"summary":"Get usage stats for storage","operationId":"storageGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"","responses":{"200":{"description":"StorageUsage","schema":{"$ref":"#\/definitions\/usageStorage"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"storage\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/storage\/{bucketId}\/usage":{"get":{"summary":"Get usage stats for a storage bucket","operationId":"storageGetBucketUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"","responses":{"200":{"description":"UsageBuckets","schema":{"$ref":"#\/definitions\/usageBuckets"}}},"x-appwrite":{"method":"getBucketUsage","cookies":false,"type":"","demo":"storage\/get-bucket-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"bucketId","description":"Bucket ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/logs":{"get":{"summary":"List Team Logs","operationId":"teamsListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"teams\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembership","cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","schema":{"$ref":"#\/definitions\/userList"}}},"x-appwrite":{"method":"list","cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","default":"","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId"]}}]}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createArgon2User","cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createBcryptUser","cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/identities":{"get":{"summary":"List Identities","operationId":"usersListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get identities for all users.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","cookies":false,"type":"","demo":"users\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]}},"\/users\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"usersDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","cookies":false,"type":"","demo":"users\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createMD5User","cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createPHPassUser","cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptUser","cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","default":null,"x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","default":null,"x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","default":null,"x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}]}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptModifiedUser","cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","default":null,"x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","default":null,"x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}]}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createSHAUser","cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","default":null,"x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","default":"","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/usage":{"get":{"summary":"Get usage stats for the users API","operationId":"usersGetUsage","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"","responses":{"200":{"description":"UsageUsers","schema":{"$ref":"#\/definitions\/usageUsers"}}},"x-appwrite":{"method":"getUsage","cookies":false,"type":"","demo":"users\/get-usage.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"range","description":"Date range.","required":false,"type":"string","x-example":"24h","enum":["24h","7d","30d","90d"],"x-enum-name":null,"x-enum-keys":["Twenty Four Hours","Seven Days","Thirty Days","Ninety Days"],"default":"30d","in":"query"},{"name":"provider","description":"Provider Name.","required":false,"type":"string","x-example":"email","default":"","in":"query"}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"}},"required":["email"]}}]}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateLabels","cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["labels"]}}]}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null}},"required":["password"]}}]}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","default":null,"x-example":"+12065550100"}},"required":["number"]}}]}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","default":null,"x-example":false}},"required":["status"]}}]}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmailVerification","cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","default":null,"x-example":false}},"required":["emailVerification"]}}]}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhoneVerification","cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","default":null,"x-example":false}},"required":["phoneVerification"]}}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories":{"get":{"summary":"List Repositories","operationId":"vcsListRepositories","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Provider Repositories List","schema":{"$ref":"#\/definitions\/providerRepositoryList"}}},"x-appwrite":{"method":"listRepositories","cookies":false,"type":"","demo":"vcs\/list-repositories.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create repository","operationId":"vcsCreateRepository","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"ProviderRepository","schema":{"$ref":"#\/definitions\/providerRepository"}}},"x-appwrite":{"method":"createRepository","cookies":false,"type":"","demo":"vcs\/create-repository.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Repository name (slug)","default":null,"x-example":"[NAME]"},"private":{"type":"boolean","description":"Mark repository public or private","default":null,"x-example":false}},"required":["name","private"]}}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}":{"get":{"summary":"Get repository","operationId":"vcsGetRepository","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"ProviderRepository","schema":{"$ref":"#\/definitions\/providerRepository"}}},"x-appwrite":{"method":"getRepository","cookies":false,"type":"","demo":"vcs\/get-repository.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]","in":"path"}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/branches":{"get":{"summary":"List Repository Branches","operationId":"vcsListRepositoryBranches","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Branches List","schema":{"$ref":"#\/definitions\/branchList"}}},"x-appwrite":{"method":"listRepositoryBranches","cookies":false,"type":"","demo":"vcs\/list-repository-branches.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]","in":"path"}]}},"\/vcs\/github\/installations\/{installationId}\/providerRepositories\/{providerRepositoryId}\/detection":{"post":{"summary":"Detect runtime settings from source code","operationId":"vcsCreateRepositoryDetection","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Detection","schema":{"$ref":"#\/definitions\/detection"}}},"x-appwrite":{"method":"createRepositoryDetection","cookies":false,"type":"","demo":"vcs\/create-repository-detection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"providerRepositoryId","description":"Repository Id","required":true,"type":"string","x-example":"[PROVIDER_REPOSITORY_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"providerRootDirectory":{"type":"string","description":"Path to Root Directory","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"}}}}]}},"\/vcs\/github\/installations\/{installationId}\/repositories\/{repositoryId}":{"patch":{"summary":"Authorize external deployment","operationId":"vcsUpdateExternalDeployments","consumes":["application\/json"],"produces":[],"tags":["vcs"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"updateExternalDeployments","cookies":false,"type":"","demo":"vcs\/update-external-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"},{"name":"repositoryId","description":"VCS Repository Id","required":true,"type":"string","x-example":"[REPOSITORY_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"providerPullRequestId":{"type":"string","description":"GitHub Pull Request Id","default":null,"x-example":"[PROVIDER_PULL_REQUEST_ID]"}},"required":["providerPullRequestId"]}}]}},"\/vcs\/installations":{"get":{"summary":"List installations","operationId":"vcsListInstallations","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Installations List","schema":{"$ref":"#\/definitions\/installationList"}}},"x-appwrite":{"method":"listInstallations","cookies":false,"type":"","demo":"vcs\/list-installations.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/list-installations.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: provider, organization","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]}},"\/vcs\/installations\/{installationId}":{"get":{"summary":"Get installation","operationId":"vcsGetInstallation","consumes":["application\/json"],"produces":["application\/json"],"tags":["vcs"],"description":"","responses":{"200":{"description":"Installation","schema":{"$ref":"#\/definitions\/installation"}}},"x-appwrite":{"method":"getInstallation","cookies":false,"type":"","demo":"vcs\/get-installation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/get-installation.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.read","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"}]},"delete":{"summary":"Delete Installation","operationId":"vcsDeleteInstallation","consumes":["application\/json"],"produces":[],"tags":["vcs"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteInstallation","cookies":false,"type":"","demo":"vcs\/delete-installation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/vcs\/delete-installation.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"vcs.write","platforms":["console"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[]}},"security":[{"Project":[]}],"parameters":[{"name":"installationId","description":"Installation Id","required":true,"type":"string","x-example":"[INSTALLATION_ID]","in":"path"}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"type":"object","$ref":"#\/definitions\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"type":"object","$ref":"#\/definitions\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"type":"object","$ref":"#\/definitions\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"type":"object","$ref":"#\/definitions\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"type":"object","$ref":"#\/definitions\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"type":"object","$ref":"#\/definitions\/function"},"x-example":""}},"required":["total","functions"]},"installationList":{"description":"Installations List","type":"object","properties":{"total":{"type":"integer","description":"Total number of installations documents that matched your query.","x-example":5,"format":"int32"},"installations":{"type":"array","description":"List of installations.","items":{"type":"object","$ref":"#\/definitions\/installation"},"x-example":""}},"required":["total","installations"]},"providerRepositoryList":{"description":"Provider Repositories List","type":"object","properties":{"total":{"type":"integer","description":"Total number of providerRepositories documents that matched your query.","x-example":5,"format":"int32"},"providerRepositories":{"type":"array","description":"List of providerRepositories.","items":{"type":"object","$ref":"#\/definitions\/providerRepository"},"x-example":""}},"required":["total","providerRepositories"]},"branchList":{"description":"Branches List","type":"object","properties":{"total":{"type":"integer","description":"Total number of branches documents that matched your query.","x-example":5,"format":"int32"},"branches":{"type":"array","description":"List of branches.","items":{"type":"object","$ref":"#\/definitions\/branch"},"x-example":""}},"required":["total","branches"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"type":"object","$ref":"#\/definitions\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"type":"object","$ref":"#\/definitions\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"projectList":{"description":"Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"type":"object","$ref":"#\/definitions\/project"},"x-example":""}},"required":["total","projects"]},"webhookList":{"description":"Webhooks List","type":"object","properties":{"total":{"type":"integer","description":"Total number of webhooks documents that matched your query.","x-example":5,"format":"int32"},"webhooks":{"type":"array","description":"List of webhooks.","items":{"type":"object","$ref":"#\/definitions\/webhook"},"x-example":""}},"required":["total","webhooks"]},"keyList":{"description":"API Keys List","type":"object","properties":{"total":{"type":"integer","description":"Total number of keys documents that matched your query.","x-example":5,"format":"int32"},"keys":{"type":"array","description":"List of keys.","items":{"type":"object","$ref":"#\/definitions\/key"},"x-example":""}},"required":["total","keys"]},"platformList":{"description":"Platforms List","type":"object","properties":{"total":{"type":"integer","description":"Total number of platforms documents that matched your query.","x-example":5,"format":"int32"},"platforms":{"type":"array","description":"List of platforms.","items":{"type":"object","$ref":"#\/definitions\/platform"},"x-example":""}},"required":["total","platforms"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":""}},"required":["total","variables"]},"proxyRuleList":{"description":"Rule List","type":"object","properties":{"total":{"type":"integer","description":"Total number of rules documents that matched your query.","x-example":5,"format":"int32"},"rules":{"type":"array","description":"List of rules.","items":{"type":"object","$ref":"#\/definitions\/proxyRule"},"x-example":""}},"required":["total","rules"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"migrationList":{"description":"Migrations List","type":"object","properties":{"total":{"type":"integer","description":"Total number of migrations documents that matched your query.","x-example":5,"format":"int32"},"migrations":{"type":"array","description":"List of migrations.","items":{"type":"object","$ref":"#\/definitions\/migration"},"x-example":""}},"required":["total","migrations"]},"firebaseProjectList":{"description":"Migrations Firebase Projects List","type":"object","properties":{"total":{"type":"integer","description":"Total number of projects documents that matched your query.","x-example":5,"format":"int32"},"projects":{"type":"array","description":"List of projects.","items":{"type":"object","$ref":"#\/definitions\/firebaseProject"},"x-example":""}},"required":["total","projects"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"If database is enabled. Can be 'enabled' or 'disabled'. When disabled, the database is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled. Can be 'enabled' or 'disabled'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","x-nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","x-nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","x-nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","x-nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","x-nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","x-nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"x-nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"jwt":{"description":"JWT","type":"object","properties":{"jwt":{"type":"string","description":"JWT encoded string.","x-example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}},"required":["jwt"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"live":{"type":"boolean","description":"Is the function deployed with the latest configuration? This is set to false if you've changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":300,"format":"int32"},"entrypoint":{"type":"string","description":"The entrypoint file used to execute the deployment.","x-example":"index.js"},"commands":{"type":"string","description":"The build command used to build the deployment.","x-example":"npm install"},"version":{"type":"string","description":"Version of Open Runtimes used for the function.","x-example":"v2"},"installationId":{"type":"string","description":"Function VCS (Version Control System) installation id.","x-example":"6m40at4ejk5h2u9s1hboo"},"providerRepositoryId":{"type":"string","description":"VCS (Version Control System) Repository ID","x-example":"appwrite"},"providerBranch":{"type":"string","description":"VCS (Version Control System) branch name","x-example":"main"},"providerRootDirectory":{"type":"string","description":"Path to function in VCS (Version Control System) repository","x-example":"functions\/helloWorld"},"providerSilentMode":{"type":"boolean","description":"Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests","x-example":false}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","live","logging","runtime","deployment","vars","events","schedule","timeout","entrypoint","commands","version","installationId","providerRepositoryId","providerBranch","providerRootDirectory","providerSilentMode"]},"installation":{"description":"Installation","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"VCS (Version Control System) provider name.","x-example":"github"},"organization":{"type":"string","description":"VCS (Version Control System) organization name.","x-example":"appwrite"},"providerInstallationId":{"type":"string","description":"VCS (Version Control System) installation ID.","x-example":"5322"}},"required":["$id","$createdAt","$updatedAt","provider","organization","providerInstallationId"]},"providerRepository":{"description":"ProviderRepository","type":"object","properties":{"id":{"type":"string","description":"VCS (Version Control System) repository ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"VCS (Version Control System) repository name.","x-example":"appwrite"},"organization":{"type":"string","description":"VCS (Version Control System) organization name","x-example":"appwrite"},"provider":{"type":"string","description":"VCS (Version Control System) provider name.","x-example":"github"},"private":{"type":"boolean","description":"Is VCS (Version Control System) repository private?","x-example":true},"runtime":{"type":"string","description":"Auto-detected runtime suggestion. Empty if getting response of getRuntime().","x-example":"node"},"pushedAt":{"type":"string","description":"Last commit date in ISO 8601 format.","x-example":"datetime"}},"required":["id","name","organization","provider","private","runtime","pushedAt"]},"detection":{"description":"Detection","type":"object","properties":{"runtime":{"type":"string","description":"Runtime","x-example":"node"}},"required":["runtime"]},"branch":{"description":"Branch","type":"object","properties":{"name":{"type":"string","description":"Branch Name.","x-example":"main"}},"required":["name"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"type":{"type":"string","description":"Type of deployment.","x-example":"vcs"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"index.js"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"waiting\", \"ready\", and \"failed\".","x-example":"ready"},"buildLogs":{"type":"string","description":"The build logs.","x-example":"Compiling source files..."},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"},"providerRepositoryName":{"type":"string","description":"The name of the vcs provider repository","x-example":"database"},"providerRepositoryOwner":{"type":"string","description":"The name of the vcs provider repository owner","x-example":"utopia"},"providerRepositoryUrl":{"type":"string","description":"The url of the vcs provider repository","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function"},"providerBranch":{"type":"string","description":"The branch of the vcs repository","x-example":"0.7.x"},"providerCommitHash":{"type":"string","description":"The commit hash of the vcs commit","x-example":"7c3f25d"},"providerCommitAuthorUrl":{"type":"string","description":"The url of vcs commit author","x-example":"https:\/\/github.com\/vermakhushboo"},"providerCommitAuthor":{"type":"string","description":"The name of vcs commit author","x-example":"Khushboo Verma"},"providerCommitMessage":{"type":"string","description":"The commit message","x-example":"Update index.js"},"providerCommitUrl":{"type":"string","description":"The url of the vcs commit","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function\/commit\/60c0416257a9cbcdd96b2d370c38d8f8d150ccfb"},"providerBranchUrl":{"type":"string","description":"The branch of the vcs repository","x-example":"https:\/\/github.com\/vermakhushboo\/appwrite\/tree\/0.7.x"}},"required":["$id","$createdAt","$updatedAt","type","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildLogs","buildTime","providerRepositoryName","providerRepositoryOwner","providerRepositoryUrl","providerBranch","providerCommitHash","providerCommitAuthorUrl","providerCommitAuthor","providerCommitMessage","providerCommitUrl","providerBranchUrl"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"project":{"description":"Project","type":"object","properties":{"$id":{"type":"string","description":"Project ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Project creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Project update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Project name.","x-example":"New Project"},"description":{"type":"string","description":"Project description.","x-example":"This is a new project."},"teamId":{"type":"string","description":"Project team ID.","x-example":"1592981250"},"logo":{"type":"string","description":"Project logo file ID.","x-example":"5f5c451b403cb"},"url":{"type":"string","description":"Project website URL.","x-example":"5f5c451b403cb"},"legalName":{"type":"string","description":"Company legal name.","x-example":"Company LTD."},"legalCountry":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format.","x-example":"US"},"legalState":{"type":"string","description":"State name.","x-example":"New York"},"legalCity":{"type":"string","description":"City name.","x-example":"New York City."},"legalAddress":{"type":"string","description":"Company Address.","x-example":"620 Eighth Avenue, New York, NY 10018"},"legalTaxId":{"type":"string","description":"Company Tax ID.","x-example":"131102020"},"authDuration":{"type":"integer","description":"Session duration in seconds.","x-example":60,"format":"int32"},"authLimit":{"type":"integer","description":"Max users allowed. 0 is unlimited.","x-example":100,"format":"int32"},"authSessionsLimit":{"type":"integer","description":"Max sessions allowed per user. 100 maximum.","x-example":10,"format":"int32"},"authPasswordHistory":{"type":"integer","description":"Max allowed passwords in the history list per user. Max passwords limit allowed in history is 20. Use 0 for disabling password history.","x-example":5,"format":"int32"},"authPasswordDictionary":{"type":"boolean","description":"Whether or not to check user's password against most commonly used passwords.","x-example":true},"authPersonalDataCheck":{"type":"boolean","description":"Whether or not to check the user password for similarity with their personal data.","x-example":true},"providers":{"type":"array","description":"List of Providers.","items":{"type":"object","$ref":"#\/definitions\/provider"},"x-example":[{}]},"platforms":{"type":"array","description":"List of Platforms.","items":{"type":"object","$ref":"#\/definitions\/platform"},"x-example":{}},"webhooks":{"type":"array","description":"List of Webhooks.","items":{"type":"object","$ref":"#\/definitions\/webhook"},"x-example":{}},"keys":{"type":"array","description":"List of API Keys.","items":{"type":"object","$ref":"#\/definitions\/key"},"x-example":{}},"smtpEnabled":{"type":"boolean","description":"Status for custom SMTP","x-example":false},"smtpSenderName":{"type":"string","description":"SMTP sender name","x-example":"John Appwrite"},"smtpSenderEmail":{"type":"string","description":"SMTP sender email","x-example":"john@appwrite.io"},"smtpReplyTo":{"type":"string","description":"SMTP reply to email","x-example":"support@appwrite.io"},"smtpHost":{"type":"string","description":"SMTP server host name","x-example":"mail.appwrite.io"},"smtpPort":{"type":"integer","description":"SMTP server port","x-example":25,"format":"int32"},"smtpUsername":{"type":"string","description":"SMTP server username","x-example":"emailuser"},"smtpPassword":{"type":"string","description":"SMTP server password","x-example":"securepassword"},"smtpSecure":{"type":"string","description":"SMTP server secure protocol","x-example":"tls"},"authEmailPassword":{"type":"boolean","description":"Email\/Password auth method status","x-example":true},"authUsersAuthMagicURL":{"type":"boolean","description":"Magic URL auth method status","x-example":true},"authAnonymous":{"type":"boolean","description":"Anonymous auth method status","x-example":true},"authInvites":{"type":"boolean","description":"Invites auth method status","x-example":true},"authJWT":{"type":"boolean","description":"JWT auth method status","x-example":true},"authPhone":{"type":"boolean","description":"Phone auth method status","x-example":true},"serviceStatusForAccount":{"type":"boolean","description":"Account service status","x-example":true},"serviceStatusForAvatars":{"type":"boolean","description":"Avatars service status","x-example":true},"serviceStatusForDatabases":{"type":"boolean","description":"Databases service status","x-example":true},"serviceStatusForLocale":{"type":"boolean","description":"Locale service status","x-example":true},"serviceStatusForHealth":{"type":"boolean","description":"Health service status","x-example":true},"serviceStatusForStorage":{"type":"boolean","description":"Storage service status","x-example":true},"serviceStatusForTeams":{"type":"boolean","description":"Teams service status","x-example":true},"serviceStatusForUsers":{"type":"boolean","description":"Users service status","x-example":true},"serviceStatusForVcs":{"type":"boolean","description":"VCS service status","x-example":true},"serviceStatusForFunctions":{"type":"boolean","description":"Functions service status","x-example":true},"serviceStatusForProxy":{"type":"boolean","description":"Proxy service status","x-example":true},"serviceStatusForGraphql":{"type":"boolean","description":"GraphQL service status","x-example":true},"serviceStatusForMigrations":{"type":"boolean","description":"Migrations service status","x-example":true}},"required":["$id","$createdAt","$updatedAt","name","description","teamId","logo","url","legalName","legalCountry","legalState","legalCity","legalAddress","legalTaxId","authDuration","authLimit","authSessionsLimit","authPasswordHistory","authPasswordDictionary","authPersonalDataCheck","providers","platforms","webhooks","keys","smtpEnabled","smtpSenderName","smtpSenderEmail","smtpReplyTo","smtpHost","smtpPort","smtpUsername","smtpPassword","smtpSecure","authEmailPassword","authUsersAuthMagicURL","authAnonymous","authInvites","authJWT","authPhone","serviceStatusForAccount","serviceStatusForAvatars","serviceStatusForDatabases","serviceStatusForLocale","serviceStatusForHealth","serviceStatusForStorage","serviceStatusForTeams","serviceStatusForUsers","serviceStatusForVcs","serviceStatusForFunctions","serviceStatusForProxy","serviceStatusForGraphql","serviceStatusForMigrations"]},"webhook":{"description":"Webhook","type":"object","properties":{"$id":{"type":"string","description":"Webhook ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Webhook creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Webhook update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Webhook name.","x-example":"My Webhook"},"url":{"type":"string","description":"Webhook URL endpoint.","x-example":"https:\/\/example.com\/webhook"},"events":{"type":"array","description":"Webhook trigger events.","items":{"type":"string"},"x-example":"database.collections.update"},"security":{"type":"boolean","description":"Indicated if SSL \/ TLS Certificate verification is enabled.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"},"signatureKey":{"type":"string","description":"Signature key which can be used to validated incoming","x-example":"ad3d581ca230e2b7059c545e5a"}},"required":["$id","$createdAt","$updatedAt","name","url","events","security","httpUser","httpPass","signatureKey"]},"key":{"description":"Key","type":"object","properties":{"$id":{"type":"string","description":"Key ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Key creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Key update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Key name.","x-example":"My API Key"},"expire":{"type":"string","description":"Key expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"scopes":{"type":"array","description":"Allowed permission scopes.","items":{"type":"string"},"x-example":"users.read"},"secret":{"type":"string","description":"Secret key.","x-example":"919c2d18fb5d4...a2ae413da83346ad2"},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"},"sdks":{"type":"array","description":"List of SDK user agents that used this key.","items":{"type":"string"},"x-example":"appwrite:flutter"}},"required":["$id","$createdAt","$updatedAt","name","expire","scopes","secret","accessedAt","sdks"]},"provider":{"description":"Provider","type":"object","properties":{"key":{"type":"string","description":"Provider.","x-example":"github"},"name":{"type":"string","description":"Provider name.","x-example":"GitHub"},"appId":{"type":"string","description":"OAuth 2.0 application ID.","x-example":"259125845563242502"},"secret":{"type":"string","description":"OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.","x-example":"Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ"},"enabled":{"type":"boolean","description":"Provider is active and can be used to create session.","x-example":""}},"required":["key","name","appId","secret","enabled"]},"platform":{"description":"Platform","type":"object","properties":{"$id":{"type":"string","description":"Platform ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Platform creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Platform update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Platform name.","x-example":"My Web App"},"type":{"type":"string","description":"Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, and unity.","x-example":"web"},"key":{"type":"string","description":"Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.","x-example":"com.company.appname"},"store":{"type":"string","description":"App store or Google Play store ID.","x-example":""},"hostname":{"type":"string","description":"Web app hostname. Empty string for other platforms.","x-example":true},"httpUser":{"type":"string","description":"HTTP basic authentication username.","x-example":"username"},"httpPass":{"type":"string","description":"HTTP basic authentication password.","x-example":"password"}},"required":["$id","$createdAt","$updatedAt","name","type","key","store","hostname","httpUser","httpPass"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"resourceType":{"type":"string","description":"Service to which the variable belongs. Possible values are \"project\", \"function\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource to which the variable belongs. If resourceType is \"project\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"}},"required":["$id","$createdAt","$updatedAt","key","value","resourceType","resourceId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"metric":{"description":"Metric","type":"object","properties":{"value":{"type":"integer","description":"The value of this metric at the timestamp.","x-example":1,"format":"int32"},"date":{"type":"string","description":"The date at which this metric was aggregated in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["value","date"]},"usageDatabases":{"description":"UsageDatabases","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"databasesCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsCount":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databasesDelete":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsCreate":{"type":"array","description":"Aggregated stats for collections created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsRead":{"type":"array","description":"Aggregated stats for collections read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsUpdate":{"type":"array","description":"Aggregated stats for collections updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsDelete":{"type":"array","description":"Aggregated stats for collections delete.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","databasesCount","documentsCount","collectionsCount","databasesCreate","databasesRead","databasesUpdate","databasesDelete","documentsCreate","documentsRead","documentsUpdate","documentsDelete","collectionsCreate","collectionsRead","collectionsUpdate","collectionsDelete"]},"usageDatabase":{"description":"UsageDatabase","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsCount":{"type":"array","description":"Aggregated stats for total number of collections.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsCreate":{"type":"array","description":"Aggregated stats for collections created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsRead":{"type":"array","description":"Aggregated stats for collections read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsUpdate":{"type":"array","description":"Aggregated stats for collections updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"collectionsDelete":{"type":"array","description":"Aggregated stats for collections delete.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","documentsCount","collectionsCount","documentsCreate","documentsRead","documentsUpdate","documentsDelete","collectionsCreate","collectionsRead","collectionsUpdate","collectionsDelete"]},"usageCollection":{"description":"UsageCollection","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"documentsCount":{"type":"array","description":"Aggregated stats for total number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsCreate":{"type":"array","description":"Aggregated stats for documents created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsRead":{"type":"array","description":"Aggregated stats for documents read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsUpdate":{"type":"array","description":"Aggregated stats for documents updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documentsDelete":{"type":"array","description":"Aggregated stats for documents deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","documentsCount","documentsCreate","documentsRead","documentsUpdate","documentsDelete"]},"usageUsers":{"description":"UsageUsers","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"usersCount":{"type":"array","description":"Aggregated stats for total number of users.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersCreate":{"type":"array","description":"Aggregated stats for users created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersRead":{"type":"array","description":"Aggregated stats for users read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersUpdate":{"type":"array","description":"Aggregated stats for users updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"usersDelete":{"type":"array","description":"Aggregated stats for users deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"sessionsCreate":{"type":"array","description":"Aggregated stats for sessions created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"sessionsProviderCreate":{"type":"array","description":"Aggregated stats for sessions created for a provider ( email, anonymous or oauth2 ).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"sessionsDelete":{"type":"array","description":"Aggregated stats for sessions deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","usersCount","usersCreate","usersRead","usersUpdate","usersDelete","sessionsCreate","sessionsProviderCreate","sessionsDelete"]},"usageStorage":{"description":"StorageUsage","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"storage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesCount":{"type":"array","description":"Aggregated stats for total number of files.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsCount":{"type":"array","description":"Aggregated stats for total number of buckets.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsCreate":{"type":"array","description":"Aggregated stats for buckets created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsRead":{"type":"array","description":"Aggregated stats for buckets read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsUpdate":{"type":"array","description":"Aggregated stats for buckets updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"bucketsDelete":{"type":"array","description":"Aggregated stats for buckets deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesCreate":{"type":"array","description":"Aggregated stats for files created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesRead":{"type":"array","description":"Aggregated stats for files read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesUpdate":{"type":"array","description":"Aggregated stats for files updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesDelete":{"type":"array","description":"Aggregated stats for files deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","storage","filesCount","bucketsCount","bucketsCreate","bucketsRead","bucketsUpdate","bucketsDelete","filesCreate","filesRead","filesUpdate","filesDelete"]},"usageBuckets":{"description":"UsageBuckets","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"filesCount":{"type":"array","description":"Aggregated stats for total number of files in this bucket.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesStorage":{"type":"array","description":"Aggregated stats for total storage of files in this bucket.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesCreate":{"type":"array","description":"Aggregated stats for files created.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesRead":{"type":"array","description":"Aggregated stats for files read.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesUpdate":{"type":"array","description":"Aggregated stats for files updated.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"filesDelete":{"type":"array","description":"Aggregated stats for files deleted.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","filesCount","filesStorage","filesCreate","filesRead","filesUpdate","filesDelete"]},"usageFunctions":{"description":"UsageFunctions","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"executionsTotal":{"type":"array","description":"Aggregated stats for number of function executions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsFailure":{"type":"array","description":"Aggregated stats for function execution failures.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsSuccess":{"type":"array","description":"Aggregated stats for function execution successes.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executionsTime":{"type":"array","description":"Aggregated stats for function execution duration.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsTotal":{"type":"array","description":"Aggregated stats for number of function builds.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsFailure":{"type":"array","description":"Aggregated stats for function build failures.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsSuccess":{"type":"array","description":"Aggregated stats for function build successes.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buildsTime":{"type":"array","description":"Aggregated stats for function build duration.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","executionsTotal","executionsFailure","executionsSuccess","executionsTime","buildsTotal","buildsFailure","buildsSuccess","buildsTime"]},"usageProject":{"description":"UsageProject","type":"object","properties":{"range":{"type":"string","description":"The time range of the usage stats.","x-example":"30d"},"requests":{"type":"array","description":"Aggregated stats for number of requests.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"network":{"type":"array","description":"Aggregated stats for consumed bandwidth.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"executions":{"type":"array","description":"Aggregated stats for function executions.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"documents":{"type":"array","description":"Aggregated stats for number of documents.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"databases":{"type":"array","description":"Aggregated stats for number of databases.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"users":{"type":"array","description":"Aggregated stats for number of users.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"storage":{"type":"array","description":"Aggregated stats for the occupied storage size (in bytes).","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]},"buckets":{"type":"array","description":"Aggregated stats for number of buckets.","items":{"type":"object","$ref":"#\/definitions\/metric"},"x-example":[]}},"required":["range","requests","network","executions","documents","databases","users","storage","buckets"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]},"proxyRule":{"description":"Rule","type":"object","properties":{"$id":{"type":"string","description":"Rule ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Rule creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Rule update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"domain":{"type":"string","description":"Domain name.","x-example":"appwrite.company.com"},"resourceType":{"type":"string","description":"Action definition for the rule. Possible values are \"api\", \"function\", or \"redirect\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource for the action type. If resourceType is \"api\" or \"url\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"},"status":{"type":"string","description":"Domain verification status. Possible values are \"created\", \"verifying\", \"verified\" and \"unverified\"","x-example":"verified"},"logs":{"type":"string","description":"Certificate generation logs. This will return an empty string if generation did not run, or succeeded.","x-example":"HTTP challegne failed."},"renewAt":{"type":"string","description":"Certificate auto-renewal date in ISO 8601 format.","x-example":"datetime"}},"required":["$id","$createdAt","$updatedAt","domain","resourceType","resourceId","status","logs","renewAt"]},"smsTemplate":{"description":"SmsTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."}},"required":["type","locale","message"]},"emailTemplate":{"description":"EmailTemplate","type":"object","properties":{"type":{"type":"string","description":"Template type","x-example":"verification"},"locale":{"type":"string","description":"Template locale","x-example":"en_us"},"message":{"type":"string","description":"Template message","x-example":"Click on the link to verify your account."},"senderName":{"type":"string","description":"Name of the sender","x-example":"My User"},"senderEmail":{"type":"string","description":"Email of the sender","x-example":"mail@appwrite.io"},"replyTo":{"type":"string","description":"Reply to email address","x-example":"emails@appwrite.io"},"subject":{"type":"string","description":"Email subject","x-example":"Please verify your email address"}},"required":["type","locale","message","senderName","senderEmail","replyTo","subject"]},"consoleVariables":{"description":"Console Variables","type":"object","properties":{"_APP_DOMAIN_TARGET":{"type":"string","description":"CNAME target for your Appwrite custom domains.","x-example":"appwrite.io"},"_APP_STORAGE_LIMIT":{"type":"integer","description":"Maximum file size allowed for file upload in bytes.","x-example":"30000000","format":"int32"},"_APP_FUNCTIONS_SIZE_LIMIT":{"type":"integer","description":"Maximum file size allowed for deployment in bytes.","x-example":"30000000","format":"int32"},"_APP_USAGE_STATS":{"type":"string","description":"Defines if usage stats are enabled. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'.","x-example":"enabled"},"_APP_VCS_ENABLED":{"type":"boolean","description":"Defines if VCS (Version Control System) is enabled.","x-example":true},"_APP_DOMAIN_ENABLED":{"type":"boolean","description":"Defines if main domain is configured. If so, custom domains can be created.","x-example":true},"_APP_ASSISTANT_ENABLED":{"type":"boolean","description":"Defines if AI assistant is enabled.","x-example":true}},"required":["_APP_DOMAIN_TARGET","_APP_STORAGE_LIMIT","_APP_FUNCTIONS_SIZE_LIMIT","_APP_USAGE_STATS","_APP_VCS_ENABLED","_APP_DOMAIN_ENABLED","_APP_ASSISTANT_ENABLED"]},"migration":{"description":"Migration","type":"object","properties":{"$id":{"type":"string","description":"Migration ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"string","description":"Migration status ( pending, processing, failed, completed ) ","x-example":"pending"},"stage":{"type":"string","description":"Migration stage ( init, processing, source-check, destination-check, migrating, finished )","x-example":"init"},"source":{"type":"string","description":"A string containing the type of source of the migration.","x-example":"Appwrite"},"resources":{"type":"array","description":"Resources to migration.","items":{"type":"string"},"x-example":["user"]},"statusCounters":{"type":"object","additionalProperties":true,"description":"A group of counters that represent the total progress of the migration.","x-example":"{\"Database\": {\"PENDING\": 0, \"SUCCESS\": 1, \"ERROR\": 0, \"SKIP\": 0, \"PROCESSING\": 0, \"WARNING\": 0}}"},"resourceData":{"type":"object","additionalProperties":true,"description":"An array of objects containing the report data of the resources that were migrated.","x-example":"[{\"resource\":\"Database\",\"id\":\"public\",\"status\":\"SUCCESS\",\"message\":\"\"}]"},"errors":{"type":"string","description":"All errors that occurred during the migration process.","x-example":[]}},"required":["$id","$createdAt","$updatedAt","status","stage","source","resources","statusCounters","resourceData","errors"]},"migrationReport":{"description":"Migration Report","type":"object","properties":{"user":{"type":"integer","description":"Number of users to be migrated.","x-example":20,"format":"int32"},"team":{"type":"integer","description":"Number of teams to be migrated.","x-example":20,"format":"int32"},"database":{"type":"integer","description":"Number of databases to be migrated.","x-example":20,"format":"int32"},"document":{"type":"integer","description":"Number of documents to be migrated.","x-example":20,"format":"int32"},"file":{"type":"integer","description":"Number of files to be migrated.","x-example":20,"format":"int32"},"bucket":{"type":"integer","description":"Number of buckets to be migrated.","x-example":20,"format":"int32"},"function":{"type":"integer","description":"Number of functions to be migrated.","x-example":20,"format":"int32"},"size":{"type":"integer","description":"Size of files to be migrated in mb.","x-example":30000,"format":"int32"},"version":{"type":"string","description":"Version of the Appwrite instance to be migrated.","x-example":"1.4.0"}},"required":["user","team","database","document","file","bucket","function","size","version"]},"firebaseProject":{"description":"MigrationFirebaseProject","type":"object","properties":{"projectId":{"type":"string","description":"Project ID.","x-example":"my-project"},"displayName":{"type":"string","description":"Project display name.","x-example":"My Project"}},"required":["projectId","displayName"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index ece98a393e..fc50cbbe5b 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"1.3.8","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user data as JSON object.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":19,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":26,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":22,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":24,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":25,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":27,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user preferences as a key-value object.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":20,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":28,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":33,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":34,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get currently logged in user list of active sessions across different devices.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":21,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":32,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":23,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":31,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":30,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":29,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":35,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":36,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":40,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":39,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","schema":{"$ref":"#\/definitions\/databaseList"}}},"x-appwrite":{"method":"list","weight":50,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"create","weight":49,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","default":true,"x-example":false}},"required":["databaseId","name"]}}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"get","weight":51,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"update","weight":53,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Database","operationId":"databasesDelete","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":54,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","schema":{"$ref":"#\/definitions\/collectionList"}}},"x-appwrite":{"method":"listCollections","weight":56,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"createCollection","weight":55,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","default":true,"x-example":false}},"required":["collectionId","name"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"getCollection","weight":57,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"updateCollection","weight":59,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":60,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","schema":{"$ref":"#\/definitions\/attributeList"}}},"x-appwrite":{"method":"listAttributes","weight":71,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"createBooleanAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"createEmailAttribute","weight":62,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"updateEmailAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"createEnumAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","elements","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"updateEnumAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"createFloatAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"updateFloatAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"createIntegerAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"createIpAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"updateIpAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","default":null,"x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","default":null,"x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","default":false,"x-example":false},"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","default":null,"x-example":null},"onDelete":{"type":"string","description":"Constraints option","default":"restrict","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"createStringAttribute","weight":61,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","default":null,"x-example":1},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","size","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"updateStringAttribute","weight":73,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"createUrlAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"updateUrlAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","schema":{"x-oneOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]}}},"x-appwrite":{"method":"getAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","default":null,"x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":89,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":88,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":90,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":92,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":93,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","schema":{"$ref":"#\/definitions\/indexList"}}},"x-appwrite":{"method":"listIndexes","weight":85,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"createIndex","weight":84,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","default":null,"x-example":null},"type":{"type":"string","description":"Index type.","default":null,"x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","default":[],"x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"getIndex","weight":86,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":87,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","schema":{"$ref":"#\/definitions\/functionList"}}},"x-appwrite":{"method":"list","weight":222,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"create","weight":221,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","php-8.0","php-8.1","ruby-3.0","ruby-3.1","python-3.8","python-3.9","python-3.10","dart-2.15","dart-2.16","dart-2.17","dotnet-3.1","dotnet-6.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","kotlin-1.6","cpp-17.0"],"x-enum-name":null,"x-enum-keys":[]},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","default":true,"x-example":false}},"required":["functionId","name","runtime"]}}]}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","schema":{"$ref":"#\/definitions\/runtimeList"}}},"x-appwrite":{"method":"listRuntimes","weight":223,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"get","weight":224,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"update","weight":227,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"execute":{"type":"array","description":"An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https:\/\/appwrite.io\/docs\/permissions). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled?","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Function","operationId":"functionsDelete","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":229,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","schema":{"$ref":"#\/definitions\/deploymentList"}}},"x-appwrite":{"method":"listDeployments","weight":231,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: entrypoint, size, buildId, activate","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","consumes":["multipart\/form-data"],"produces":["application\/json"],"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](\/docs\/functions).\n\nUse the \"command\" param to set the entry point used to execute your code.","responses":{"202":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"createDeployment","weight":230,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"entrypoint","description":"Entrypoint File.","required":true,"type":"string","x-example":"[ENTRYPOINT]","in":"formData"},{"name":"code","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","required":true,"type":"file","in":"formData"},{"name":"activate","description":"Automatically activate the deployment when it is finished building.","required":true,"type":"boolean","x-example":false,"in":"formData"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"getDeployment","weight":232,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"updateDeployment","weight":228,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":233,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":234,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"type":"string","x-example":"[BUILD_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":236,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, statusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":235,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},userId:{userId}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"string","description":"String of custom data to send to function.","default":"","x-example":"[DATA]"},"async":{"type":"boolean","description":"Execute code in the background. Default value is false.","default":false,"x-example":false}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":237,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","weight":239,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function variable. These variables can be accessed within function in the `env` object under the request variable.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","weight":238,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","weight":240,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","weight":241,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":242,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":273,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":272,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"get","weight":105,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","schema":{"$ref":"#\/definitions\/healthAntivirus"}}},"x-appwrite":{"method":"getAntivirus","weight":117,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getCache","weight":108,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getDB","weight":107,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getPubSub","weight":110,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getQueue","weight":109,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueCertificates","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueFunctions","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueLogs","weight":113,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueWebhooks","weight":112,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getStorageLocal","weight":116,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","schema":{"$ref":"#\/definitions\/healthTime"}}},"x-appwrite":{"method":"getTime","weight":111,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":97,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":98,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":102,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":99,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":100,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":103,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":104,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","schema":{"$ref":"#\/definitions\/bucketList"}}},"x-appwrite":{"method":"listBuckets","weight":165,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"createBucket","weight":164,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","default":30000000,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["bucketId","name"]}}]}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"getBucket","weight":166,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"updateBucket","weight":167,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled?","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](\/docs\/environment-variables#storage)","default":null,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":168,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":170,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":169,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":171,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":175,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":176,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":173,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":172,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":174,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":180,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":179,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":181,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":183,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":185,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":187,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":186,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":188,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership Roles","operationId":"teamsUpdateMembershipRoles","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipRoles","weight":189,"cookies":false,"type":"","demo":"teams\/update-membership-roles.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-roles.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":191,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":190,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":182,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":184,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","schema":{"$ref":"#\/definitions\/userList"}}},"x-appwrite":{"method":"list","weight":201,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":193,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","default":"","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId"]}}]}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createArgon2User","weight":196,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createBcryptUser","weight":194,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createMD5User","weight":195,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createPHPassUser","weight":198,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptUser","weight":199,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","default":null,"x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","default":null,"x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","default":null,"x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}]}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":200,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","default":null,"x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","default":null,"x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}]}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createSHAUser","weight":197,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","default":null,"x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","default":"","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":202,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":219,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":213,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"}},"required":["email"]}}]}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateLabels","weight":208,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["labels"]}}]}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":206,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":205,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":211,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":212,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null}},"required":["password"]}}]}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":214,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","default":null,"x-example":"+12065550100"}},"required":["number"]}}]}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":203,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":216,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":204,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":218,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":217,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":207,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","default":null,"x-example":false}},"required":["status"]}}]}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmailVerification","weight":215,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","default":null,"x-example":false}},"required":["emailVerification"]}}]}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":210,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","default":null,"x-example":false}},"required":["phoneVerification"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"type":"object","$ref":"#\/definitions\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"type":"object","$ref":"#\/definitions\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"type":"object","$ref":"#\/definitions\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"type":"object","$ref":"#\/definitions\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"type":"object","$ref":"#\/definitions\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"type":"object","$ref":"#\/definitions\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"type":"object","$ref":"#\/definitions\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"Database enabled.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","x-nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","x-nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","x-nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","x-nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","x-nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","x-nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"x-nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":15,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","runtime","deployment","vars","events","schedule","timeout"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"enabled"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"pending\", \"ready\", and \"failed\".","x-example":"ready"},"buildStdout":{"type":"string","description":"The build stdout.","x-example":"enabled"},"buildStderr":{"type":"string","description":"The build stderr.","x-example":"enabled"},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"}},"required":["$id","$createdAt","$updatedAt","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildStdout","buildStderr","buildTime"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"statusCode":{"type":"integer","description":"The script status code.","x-example":0,"format":"int32"},"response":{"type":"string","description":"The script response output string. Logs the last 4,000 characters of the execution response output.","x-example":""},"stdout":{"type":"string","description":"The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"stderr":{"type":"string","description":"The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"The script execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","statusCode","response","stdout","stderr","duration"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"}},"required":["$id","$createdAt","$updatedAt","key","value","functionId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"1.4.0","title":"Appwrite","description":"Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)","termsOfService":"https:\/\/appwrite.io\/policy\/terms","contact":{"name":"Appwrite Team","url":"https:\/\/appwrite.io\/support","email":"team@appwrite.io"},"license":{"name":"BSD-3-Clause","url":"https:\/\/raw.githubusercontent.com\/appwrite\/appwrite\/master\/LICENSE"}},"host":"HOSTNAME","basePath":"\/v1","schemes":["https"],"consumes":["application\/json","multipart\/form-data"],"produces":["application\/json"],"securityDefinitions":{"Project":{"type":"apiKey","name":"X-Appwrite-Project","description":"Your project ID","in":"header","x-appwrite":{"demo":"5df5acd0d48c2"}},"Key":{"type":"apiKey","name":"X-Appwrite-Key","description":"Your secret API key","in":"header","x-appwrite":{"demo":"919c2d18fb5d4...a2ae413da83346ad2"}},"JWT":{"type":"apiKey","name":"X-Appwrite-JWT","description":"Your secret JSON Web Token","in":"header","x-appwrite":{"demo":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."}},"Locale":{"type":"apiKey","name":"X-Appwrite-Locale","description":"","in":"header","x-appwrite":{"demo":"en"}}},"paths":{"\/account":{"get":{"summary":"Get Account","operationId":"accountGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the currently logged in user.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":21,"cookies":false,"type":"","demo":"account\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/email":{"patch":{"summary":"Update Email","operationId":"accountUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":28,"cookies":false,"type":"","demo":"account\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["email","password"]}}]}},"\/account\/identities":{"get":{"summary":"List Identities","operationId":"accountListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of identities for the currently logged in user.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","weight":13,"cookies":false,"type":"","demo":"account\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/identities","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"}]}},"\/account\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"accountDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":14,"cookies":false,"type":"","demo":"account\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/account\/logs":{"get":{"summary":"List Logs","operationId":"accountListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":24,"cookies":false,"type":"","demo":"account\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/account\/name":{"patch":{"summary":"Update Name","operationId":"accountUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account name.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":26,"cookies":false,"type":"","demo":"account\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/account\/password":{"patch":{"summary":"Update Password","operationId":"accountUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":27,"cookies":false,"type":"","demo":"account\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null},"oldPassword":{"type":"string","description":"Current user password. Must be at least 8 chars.","default":"","x-example":"password"}},"required":["password"]}}]}},"\/account\/phone":{"patch":{"summary":"Update Phone","operationId":"accountUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST \/account\/verification\/phone](\/docs\/client\/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":29,"cookies":false,"type":"","demo":"account\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"User password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["phone","password"]}}]}},"\/account\/prefs":{"get":{"summary":"Get Account Preferences","operationId":"accountGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the preferences as a key-value object for the currently logged in user.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":22,"cookies":false,"type":"","demo":"account\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"patch":{"summary":"Update Preferences","operationId":"accountUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePrefs","weight":30,"cookies":false,"type":"","demo":"account\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/prefs","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/account\/recovery":{"post":{"summary":"Create Password Recovery","operationId":"accountCreateRecovery","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT \/account\/recovery](\/docs\/client\/account#accountUpdateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createRecovery","weight":35,"cookies":false,"type":"","demo":"account\/create-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":["url:{url},email:{param-email}","ip:{ip}"],"scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"url":{"type":"string","description":"URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["email","url"]}}]},"put":{"summary":"Create Password Recovery (confirmation)","operationId":"accountUpdateRecovery","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountCreateRecovery) 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.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateRecovery","weight":36,"cookies":false,"type":"","demo":"account\/update-recovery.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-recovery.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid reset token.","default":null,"x-example":"[SECRET]"},"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":"password"},"passwordAgain":{"type":"string","description":"Repeat new user password. Must be at least 8 chars.","default":null,"x-example":"password"}},"required":["userId","secret","password","passwordAgain"]}}]}},"\/account\/sessions":{"get":{"summary":"List Sessions","operationId":"accountListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Get the list of active sessions across different devices for the currently logged in user.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":23,"cookies":false,"type":"","demo":"account\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/list-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"delete":{"summary":"Delete Sessions","operationId":"accountDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Delete all sessions from the user account and remove any sessions cookies from the end client.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":34,"cookies":false,"type":"","demo":"account\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-sessions.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/sessions\/{sessionId}":{"get":{"summary":"Get Session","operationId":"accountGetSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"getSession","weight":25,"cookies":false,"type":"","demo":"account\/get-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/get-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"\/account\/sessions","offline-key":"{sessionId}","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to get the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"patch":{"summary":"Update OAuth Session (Refresh Tokens)","operationId":"accountUpdateSession","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Access tokens have limited lifespan and expire to mitigate security risks. If session was created using an OAuth provider, this route can be used to \"refresh\" the access token.","responses":{"200":{"description":"Session","schema":{"$ref":"#\/definitions\/session"}}},"x-appwrite":{"method":"updateSession","weight":33,"cookies":false,"type":"","demo":"account\/update-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-session.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to update the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]},"delete":{"summary":"Delete Session","operationId":"accountDeleteSession","consumes":["application\/json"],"produces":[],"tags":["account"],"description":"Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](\/docs\/client\/account#accountDeleteSessions) instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":32,"cookies":false,"type":"","demo":"account\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-session.md","rate-limit":100,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"sessionId","description":"Session ID. Use the string 'current' to delete the current device session.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/account\/status":{"patch":{"summary":"Update Status","operationId":"accountUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":31,"cookies":false,"type":"","demo":"account\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]}},"\/account\/verification":{"post":{"summary":"Create Email Verification","operationId":"accountCreateVerification","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/account#accountUpdateEmailVerification). 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","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createVerification","weight":37,"cookies":false,"type":"","demo":"account\/create-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"url":{"type":"string","description":"URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"}},"required":["url"]}}]},"put":{"summary":"Create Email Verification (confirmation)","operationId":"accountUpdateVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updateVerification","weight":38,"cookies":false,"type":"","demo":"account\/update-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-email-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/account\/verification\/phone":{"post":{"summary":"Create Phone Verification","operationId":"accountCreatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](\/docs\/client\/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](\/docs\/client\/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.","responses":{"201":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"createPhoneVerification","weight":39,"cookies":false,"type":"","demo":"account\/create-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{userId}","scope":"account","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}]},"put":{"summary":"Create Phone Verification (confirmation)","operationId":"accountUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["account"],"description":"Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.","responses":{"200":{"description":"Token","schema":{"$ref":"#\/definitions\/token"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":40,"cookies":false,"type":"","demo":"account\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-phone-verification.md","rate-limit":10,"rate-time":3600,"rate-key":"userId:{param-userId}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Valid verification token.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/avatars\/browsers\/{code}":{"get":{"summary":"Get Browser Icon","operationId":"avatarsGetBrowser","consumes":["application\/json"],"produces":["image\/png"],"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](\/docs\/client\/account#accountGetSessions) 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.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getBrowser","weight":42,"cookies":false,"type":"location","demo":"avatars\/get-browser.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-browser.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Browser Code.","required":true,"type":"string","x-example":"aa","enum":["aa","an","ch","ci","cm","cr","ff","sf","mf","ps","oi","om","op","on"],"x-enum-name":"Browser","x-enum-keys":["Avant Browser","Android WebView Beta","Google Chrome","Google Chrome (iOS)","Google Chrome (Mobile)","Chromium","Mozilla Firefox","Safari","Mobile Safari","Microsoft Edge","Microsoft Edge (iOS)","Opera Mini","Opera","Opera (Next)"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/credit-cards\/{code}":{"get":{"summary":"Get Credit Card Icon","operationId":"avatarsGetCreditCard","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getCreditCard","weight":41,"cookies":false,"type":"location","demo":"avatars\/get-credit-card.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-credit-card.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Credit Card Code. Possible values: amex, argencard, cabal, censosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.","required":true,"type":"string","x-example":"amex","enum":["amex","argencard","cabal","censosud","diners","discover","elo","hipercard","jcb","mastercard","naranja","targeta-shopping","union-china-pay","visa","mir","maestro"],"x-enum-name":"CreditCard","x-enum-keys":["American Express","Argencard","Cabal","Consosud","Diners Club","Discover","Elo","Hipercard","JCB","Mastercard","Naranja","Tarjeta Shopping","Union China Pay","Visa","MIR","Maestro"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/favicon":{"get":{"summary":"Get Favicon","operationId":"avatarsGetFavicon","consumes":["application\/json"],"produces":["image\/*"],"tags":["avatars"],"description":"Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL.\n","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFavicon","weight":45,"cookies":false,"type":"location","demo":"avatars\/get-favicon.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-favicon.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Website URL which you want to fetch the favicon from.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"}]}},"\/avatars\/flags\/{code}":{"get":{"summary":"Get Country Flag","operationId":"avatarsGetFlag","consumes":["application\/json"],"produces":["image\/png"],"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](http:\/\/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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFlag","weight":43,"cookies":false,"type":"location","demo":"avatars\/get-flag.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-flag.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"code","description":"Country Code. ISO Alpha-2 country code format.","required":true,"type":"string","x-example":"af","enum":["af","ao","al","ad","ae","ar","am","ag","au","at","az","bi","be","bj","bf","bd","bg","bh","bs","ba","by","bz","bo","br","bb","bn","bt","bw","cf","ca","ch","cl","cn","ci","cm","cd","cg","co","km","cv","cr","cu","cy","cz","de","dj","dm","dk","do","dz","ec","eg","er","es","ee","et","fi","fj","fr","fm","ga","gb","ge","gh","gn","gm","gw","gq","gr","gd","gt","gy","hn","hr","ht","hu","id","in","ie","ir","iq","is","il","it","jm","jo","jp","kz","ke","kg","kh","ki","kn","kr","kw","la","lb","lr","ly","lc","li","lk","ls","lt","lu","lv","ma","mc","md","mg","mv","mx","mh","mk","ml","mt","mm","me","mn","mz","mr","mu","mw","my","na","ne","ng","ni","nl","no","np","nr","nz","om","pk","pa","pe","ph","pw","pg","pl","kp","pt","py","qa","ro","ru","rw","sa","sd","sn","sg","sb","sl","sv","sm","so","rs","ss","st","sr","sk","si","se","sz","sc","sy","td","tg","th","tj","tm","tl","to","tt","tn","tr","tv","tz","ug","ua","uy","us","uz","va","vc","ve","vn","vu","ws","ye","za","zm","zw"],"x-enum-name":"Flag","x-enum-keys":["Afghanistan","Angola","Albania","Andorra","United Arab Emirates","Argentina","Armenia","Antigua and Barbuda","Australia","Austria","Azerbaijan","Burundi","Belgium","Benin","Burkina Faso","Bangladesh","Bulgaria","Bahrain","Bahamas","Bosnia and Herzegovina","Belarus","Belize","Bolivia","Brazil","Barbados","Brunei Darussalam","Bhutan","Botswana","Central African Republic","Canada","Switzerland","Chile","China","C\u00f4te d'Ivoire","Cameroon","Democratic Republic of the Congo","Republic of the Congo","Colombia","Comoros","Cape Verde","Costa Rica","Cuba","Cyprus","Czech Republic","Germany","Djibouti","Dominica","Denmark","Dominican Republic","Algeria","Ecuador","Egypt","Eritrea","Spain","Estonia","Ethiopia","Finland","Fiji","France","Micronesia (Federated States of)","Gabon","United Kingdom","Georgia","Ghana","Guinea","Gambia","Guinea-Bissau","Equatorial Guinea","Greece","Grenada","Guatemala","Guyana","Honduras","Croatia","Haiti","Hungary","Indonesia","India","Ireland","Iran (Islamic Republic of)","Iraq","Iceland","Israel","Italy","Jamaica","Jordan","Japan","Kazakhstan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Saint Kitts and Nevis","South Korea","Kuwait","Lao People's Democratic Republic","Lebanon","Liberia","Libya","Saint Lucia","Liechtenstein","Sri Lanka","Lesotho","Lithuania","Luxembourg","Latvia","Morocco","Monaco","Moldova","Madagascar","Maldives","Mexico","Marshall Islands","North Macedonia","Mali","Malta","Myanmar","Montenegro","Mongolia","Mozambique","Mauritania","Mauritius","Malawi","Malaysia","Namibia","Niger","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","New Zealand","Oman","Pakistan","Panama","Peru","Philippines","Palau","Papua New Guinea","Poland","North Korea","Portugal","Paraguay","Qatar","Romania","Russia","Rwanda","Saudi Arabia","Sudan","Senegal","Singapore","Solomon Islands","Sierra Leone","El Salvador","San Marino","Somalia","Serbia","South Sudan","Sao Tome and Principe","Suriname","Slovakia","Slovenia","Sweden","Eswatini","Seychelles","Syria","Chad","Togo","Thailand","Tajikistan","Turkmenistan","Timor-Leste","Tonga","Trinidad and Tobago","Tunisia","Turkey","Tuvalu","Tanzania","Uganda","Ukraine","Uruguay","United States","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","Vietnam","Vanuatu","Samoa","Yemen","South Africa","Zambia","Zimbabwe"],"in":"path"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"quality","description":"Image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"}]}},"\/avatars\/image":{"get":{"summary":"Get Image from URL","operationId":"avatarsGetImage","consumes":["application\/json"],"produces":["image\/*"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getImage","weight":44,"cookies":false,"type":"location","demo":"avatars\/get-image.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-image.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"url","description":"Image URL which you want to crop.","required":true,"type":"string","format":"url","x-example":"https:\/\/example.com","in":"query"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":0,"default":400,"in":"query"}]}},"\/avatars\/initials":{"get":{"summary":"Get User Initials","operationId":"avatarsGetInitials","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getInitials","weight":47,"cookies":false,"type":"location","demo":"avatars\/get-initials.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-initials.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"name","description":"Full Name. When empty, current user name or email will be used. Max length: 128 chars.","required":false,"type":"string","x-example":"[NAME]","default":"","in":"query"},{"name":"width","description":"Image width. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"height","description":"Image height. Pass an integer between 0 to 2000. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":500,"in":"query"},{"name":"background","description":"Changes background color. By default a random color will be picked and stay will persistent to the given name.","required":false,"type":"string","default":"","in":"query"}]}},"\/avatars\/qr":{"get":{"summary":"Get QR Code","operationId":"avatarsGetQR","consumes":["application\/json"],"produces":["image\/png"],"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","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getQR","weight":46,"cookies":false,"type":"location","demo":"avatars\/get-q-r.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/avatars\/get-qr.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"avatars.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"text","description":"Plain text to be converted to QR code image.","required":true,"type":"string","x-example":"[TEXT]","in":"query"},{"name":"size","description":"QR code size. Pass an integer between 1 to 1000. Defaults to 400.","required":false,"type":"integer","format":"int32","x-example":1,"default":400,"in":"query"},{"name":"margin","description":"Margin from edge. Pass an integer between 0 to 10. Defaults to 1.","required":false,"type":"integer","format":"int32","x-example":0,"default":1,"in":"query"},{"name":"download","description":"Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.","required":false,"type":"boolean","x-example":false,"default":false,"in":"query"}]}},"\/databases":{"get":{"summary":"List Databases","operationId":"databasesList","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.","responses":{"200":{"description":"Databases List","schema":{"$ref":"#\/definitions\/databaseList"}}},"x-appwrite":{"method":"list","weight":52,"cookies":false,"type":"","demo":"databases\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Database","operationId":"databasesCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Database.\n","responses":{"201":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"create","weight":51,"cookies":false,"type":"","demo":"databases\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"databaseId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DATABASE_ID]","x-global":true},"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["databaseId","name"]}}]}},"\/databases\/{databaseId}":{"get":{"summary":"Get Database","operationId":"databasesGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"get","weight":53,"cookies":false,"type":"","demo":"databases\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]},"put":{"summary":"Update Database","operationId":"databasesUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a database by its unique ID.","responses":{"200":{"description":"Database","schema":{"$ref":"#\/definitions\/database"}}},"x-appwrite":{"method":"update","weight":55,"cookies":false,"type":"","demo":"databases\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Database name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"enabled":{"type":"boolean","description":"Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Database","operationId":"databasesDelete","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":56,"cookies":false,"type":"","demo":"databases\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"databases.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections":{"get":{"summary":"List Collections","operationId":"databasesListCollections","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.","responses":{"200":{"description":"Collections List","schema":{"$ref":"#\/definitions\/collectionList"}}},"x-appwrite":{"method":"listCollections","weight":58,"cookies":false,"type":"","demo":"databases\/list-collections.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-collections.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Collection","operationId":"databasesCreateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"createCollection","weight":57,"cookies":false,"type":"","demo":"databases\/create-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"collectionId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[COLLECTION_ID]"},"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["collectionId","name"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}":{"get":{"summary":"Get Collection","operationId":"databasesGetCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"getCollection","weight":59,"cookies":false,"type":"","demo":"databases\/get-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]},"put":{"summary":"Update Collection","operationId":"databasesUpdateCollection","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a collection by its unique ID.","responses":{"200":{"description":"Collection","schema":{"$ref":"#\/definitions\/collection"}}},"x-appwrite":{"method":"updateCollection","weight":61,"cookies":false,"type":"","demo":"databases\/update-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Collection name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"documentSecurity":{"type":"boolean","description":"Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Collection","operationId":"databasesDeleteCollection","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteCollection","weight":62,"cookies":false,"type":"","demo":"databases\/delete-collection.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-collection.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes":{"get":{"summary":"List Attributes","operationId":"databasesListAttributes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Attributes List","schema":{"$ref":"#\/definitions\/attributeList"}}},"x-appwrite":{"method":"listAttributes","weight":73,"cookies":false,"type":"","demo":"databases\/list-attributes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-attributes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean":{"post":{"summary":"Create Boolean Attribute","operationId":"databasesCreateBooleanAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a boolean attribute.\n","responses":{"202":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"createBooleanAttribute","weight":70,"cookies":false,"type":"","demo":"databases\/create-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/boolean\/{key}":{"patch":{"summary":"Update Boolean Attribute","operationId":"databasesUpdateBooleanAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean","schema":{"$ref":"#\/definitions\/attributeBoolean"}}},"x-appwrite":{"method":"updateBooleanAttribute","weight":82,"cookies":false,"type":"","demo":"databases\/update-boolean-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-boolean-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":false,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime":{"post":{"summary":"Create DateTime Attribute","operationId":"databasesCreateDatetimeAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"createDatetimeAttribute","weight":71,"cookies":false,"type":"","demo":"databases\/create-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/datetime\/{key}":{"patch":{"summary":"Update DateTime Attribute","operationId":"databasesUpdateDatetimeAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeDatetime","schema":{"$ref":"#\/definitions\/attributeDatetime"}}},"x-appwrite":{"method":"updateDatetimeAttribute","weight":83,"cookies":false,"type":"","demo":"databases\/update-datetime-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-datetime-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email":{"post":{"summary":"Create Email Attribute","operationId":"databasesCreateEmailAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an email attribute.\n","responses":{"202":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"createEmailAttribute","weight":64,"cookies":false,"type":"","demo":"databases\/create-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/email\/{key}":{"patch":{"summary":"Update Email Attribute","operationId":"databasesUpdateEmailAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an email attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEmail","schema":{"$ref":"#\/definitions\/attributeEmail"}}},"x-appwrite":{"method":"updateEmailAttribute","weight":76,"cookies":false,"type":"","demo":"databases\/update-email-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-email-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"email@example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum":{"post":{"summary":"Create Enum Attribute","operationId":"databasesCreateEnumAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"createEnumAttribute","weight":65,"cookies":false,"type":"","demo":"databases\/create-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-attribute-enum.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","elements","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/enum\/{key}":{"patch":{"summary":"Update Enum Attribute","operationId":"databasesUpdateEnumAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an enum attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeEnum","schema":{"$ref":"#\/definitions\/attributeEnum"}}},"x-appwrite":{"method":"updateEnumAttribute","weight":77,"cookies":false,"type":"","demo":"databases\/update-enum-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-enum-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"elements":{"type":"array","description":"Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of 100 elements are allowed, each 4096 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["elements","required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float":{"post":{"summary":"Create Float Attribute","operationId":"databasesCreateFloatAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a float attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"createFloatAttribute","weight":69,"cookies":false,"type":"","demo":"databases\/create-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/float\/{key}":{"patch":{"summary":"Update Float Attribute","operationId":"databasesUpdateFloatAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a float attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeFloat","schema":{"$ref":"#\/definitions\/attributeFloat"}}},"x-appwrite":{"method":"updateFloatAttribute","weight":81,"cookies":false,"type":"","demo":"databases\/update-float-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-float-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"number","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"number","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer":{"post":{"summary":"Create Integer Attribute","operationId":"databasesCreateIntegerAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create an integer attribute. Optionally, minimum and maximum values can be provided.\n","responses":{"202":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"createIntegerAttribute","weight":68,"cookies":false,"type":"","demo":"databases\/create-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/integer\/{key}":{"patch":{"summary":"Update Integer Attribute","operationId":"databasesUpdateIntegerAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an integer attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeInteger","schema":{"$ref":"#\/definitions\/attributeInteger"}}},"x-appwrite":{"method":"updateIntegerAttribute","weight":80,"cookies":false,"type":"","demo":"databases\/update-integer-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-integer-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"min":{"type":"integer","description":"Minimum value to enforce on new documents","default":null,"x-example":null},"max":{"type":"integer","description":"Maximum value to enforce on new documents","default":null,"x-example":null},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","min","max","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip":{"post":{"summary":"Create IP Address Attribute","operationId":"databasesCreateIpAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create IP address attribute.\n","responses":{"202":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"createIpAttribute","weight":66,"cookies":false,"type":"","demo":"databases\/create-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/ip\/{key}":{"patch":{"summary":"Update IP Address Attribute","operationId":"databasesUpdateIpAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an ip attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeIP","schema":{"$ref":"#\/definitions\/attributeIp"}}},"x-appwrite":{"method":"updateIpAttribute","weight":78,"cookies":false,"type":"","demo":"databases\/update-ip-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-ip-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":null,"x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/relationship":{"post":{"summary":"Create Relationship Attribute","operationId":"databasesCreateRelationshipAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"202":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"createRelationshipAttribute","weight":72,"cookies":false,"type":"","demo":"databases\/create-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"relatedCollectionId":{"type":"string","description":"Related Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","default":null,"x-example":"[RELATED_COLLECTION_ID]"},"type":{"type":"string","description":"Relation type","default":null,"x-example":"oneToOne","enum":["oneToOne","manyToOne","manyToMany","oneToMany"],"x-enum-name":"RelationshipType","x-enum-keys":[]},"twoWay":{"type":"boolean","description":"Is Two Way?","default":false,"x-example":false},"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"twoWayKey":{"type":"string","description":"Two Way Attribute Key.","default":null,"x-example":null},"onDelete":{"type":"string","description":"Constraints option","default":"restrict","x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}},"required":["relatedCollectionId","type"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string":{"post":{"summary":"Create String Attribute","operationId":"databasesCreateStringAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a string attribute.\n","responses":{"202":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"createStringAttribute","weight":63,"cookies":false,"type":"","demo":"databases\/create-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"size":{"type":"integer","description":"Attribute size for text attributes, in number of characters.","default":null,"x-example":1},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false},"encrypt":{"type":"boolean","description":"Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.","default":false,"x-example":false}},"required":["key","size","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/string\/{key}":{"patch":{"summary":"Update String Attribute","operationId":"databasesUpdateStringAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update a string attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeString","schema":{"$ref":"#\/definitions\/attributeString"}}},"x-appwrite":{"method":"updateStringAttribute","weight":75,"cookies":false,"type":"","demo":"databases\/update-string-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-string-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"[DEFAULT]","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url":{"post":{"summary":"Create URL Attribute","operationId":"databasesCreateUrlAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a URL attribute.\n","responses":{"202":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"createUrlAttribute","weight":67,"cookies":false,"type":"","demo":"databases\/create-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","default":null,"x-example":null},"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com"},"array":{"type":"boolean","description":"Is attribute an array?","default":false,"x-example":false}},"required":["key","required"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/url\/{key}":{"patch":{"summary":"Update URL Attribute","operationId":"databasesUpdateUrlAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update an url attribute. Changing the `default` value will not update already existing documents.\n","responses":{"200":{"description":"AttributeURL","schema":{"$ref":"#\/definitions\/attributeUrl"}}},"x-appwrite":{"method":"updateUrlAttribute","weight":79,"cookies":false,"type":"","demo":"databases\/update-url-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-url-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"required":{"type":"boolean","description":"Is attribute required?","default":null,"x-example":false},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","default":null,"x-example":"https:\/\/example.com","x-nullable":true}},"required":["required","default"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}":{"get":{"summary":"Get Attribute","operationId":"databasesGetAttribute","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"AttributeBoolean, or AttributeInteger, or AttributeFloat, or AttributeEmail, or AttributeEnum, or AttributeURL, or AttributeIP, or AttributeDatetime, or AttributeRelationship, or AttributeString","schema":{"x-oneOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]}}},"x-appwrite":{"method":"getAttribute","weight":74,"cookies":false,"type":"","demo":"databases\/get-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Attribute","operationId":"databasesDeleteAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteAttribute","weight":85,"cookies":false,"type":"","demo":"databases\/delete-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/attributes\/{key}\/relationship":{"patch":{"summary":"Update Relationship Attribute","operationId":"databasesUpdateRelationshipAttribute","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Update relationship attribute. [Learn more about relationship attributes](\/docs\/databases-relationships#relationship-attributes).\n","responses":{"200":{"description":"AttributeRelationship","schema":{"$ref":"#\/definitions\/attributeRelationship"}}},"x-appwrite":{"method":"updateRelationshipAttribute","weight":84,"cookies":false,"type":"","demo":"databases\/update-relationship-attribute.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-relationship-attribute.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Attribute Key.","required":true,"type":"string","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"onDelete":{"type":"string","description":"Constraints option","default":null,"x-example":"cascade","enum":["cascade","restrict","setNull"],"x-enum-name":"RelationMutate","x-enum-keys":[]}}}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents":{"get":{"summary":"List Documents","operationId":"databasesListDocuments","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a list of all the user's documents in a given collection. You can use the query params to filter your results.","responses":{"200":{"description":"Documents List","schema":{"$ref":"#\/definitions\/documentList"}}},"x-appwrite":{"method":"listDocuments","weight":91,"cookies":false,"type":"","demo":"databases\/list-documents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-documents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Document","operationId":"databasesCreateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.","responses":{"201":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"createDocument","weight":90,"cookies":false,"type":"","demo":"databases\/create-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection). Make sure to define attributes before creating documents.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"documentId":{"type":"string","description":"Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[DOCUMENT_ID]"},"data":{"type":"object","description":"Document data as JSON object.","default":{},"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}},"required":["documentId","data"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}":{"get":{"summary":"Get Document","operationId":"databasesGetDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Get a document by its unique ID. This endpoint response returns a JSON object with the document data.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"getDocument","weight":92,"cookies":false,"type":"","demo":"databases\/get-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-document.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"documents.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/databases#querying-documents). Only method allowed is select.","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"patch":{"summary":"Update Document","operationId":"databasesUpdateDocument","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.","responses":{"200":{"description":"Document","schema":{"$ref":"#\/definitions\/document"}}},"x-appwrite":{"method":"updateDocument","weight":94,"cookies":false,"type":"","demo":"databases\/update-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-document.md","rate-limit":120,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID.","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"data":{"type":"object","description":"Document data as JSON object. Include only attribute and value pairs to be updated.","default":[],"x-example":"{}"},"permissions":{"type":"array","description":"An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete Document","operationId":"databasesDeleteDocument","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"Delete a document by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDocument","weight":95,"cookies":false,"type":"","demo":"databases\/delete-document.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-document.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"documents.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/databases\/{databaseId}\/collections\/{collectionId}\/documents","offline-key":"{documentId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"documentId","description":"Document ID.","required":true,"type":"string","x-example":"[DOCUMENT_ID]","in":"path"}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes":{"get":{"summary":"List Indexes","operationId":"databasesListIndexes","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Indexes List","schema":{"$ref":"#\/definitions\/indexList"}}},"x-appwrite":{"method":"listIndexes","weight":87,"cookies":false,"type":"","demo":"databases\/list-indexes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/list-indexes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]},"post":{"summary":"Create Index","operationId":"databasesCreateIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"202":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"createIndex","weight":86,"cookies":false,"type":"","demo":"databases\/create-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/create-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Index Key.","default":null,"x-example":null},"type":{"type":"string","description":"Index type.","default":null,"x-example":"key","enum":["key","fulltext","unique","spatial","array"],"x-enum-name":"IndexType","x-enum-keys":[]},"attributes":{"type":"array","description":"Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"orders":{"type":"array","description":"Array of index orders. Maximum of 100 orders are allowed.","default":[],"x-example":null,"items":{"type":"string"}}},"required":["key","type","attributes"]}}]}},"\/databases\/{databaseId}\/collections\/{collectionId}\/indexes\/{key}":{"get":{"summary":"Get Index","operationId":"databasesGetIndex","consumes":["application\/json"],"produces":["application\/json"],"tags":["databases"],"description":"","responses":{"200":{"description":"Index","schema":{"$ref":"#\/definitions\/index"}}},"x-appwrite":{"method":"getIndex","weight":88,"cookies":false,"type":"","demo":"databases\/get-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/get-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]},"delete":{"summary":"Delete Index","operationId":"databasesDeleteIndex","consumes":["application\/json"],"produces":[],"tags":["databases"],"description":"","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIndex","weight":89,"cookies":false,"type":"","demo":"databases\/delete-index.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-index.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"collections.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"databaseId","description":"Database ID.","required":true,"x-global":true,"type":"string","x-example":"[DATABASE_ID]","in":"path"},{"name":"collectionId","description":"Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).","required":true,"type":"string","x-example":"[COLLECTION_ID]","in":"path"},{"name":"key","description":"Index Key.","required":true,"type":"string","in":"path"}]}},"\/functions":{"get":{"summary":"List Functions","operationId":"functionsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's functions. You can use the query params to filter your results.","responses":{"200":{"description":"Functions List","schema":{"$ref":"#\/definitions\/functionList"}}},"x-appwrite":{"method":"list","weight":238,"cookies":false,"type":"","demo":"functions\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deployment, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Function","operationId":"functionsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function. You can pass a list of [permissions](\/docs\/permissions) to allow different project users or team with access to execute the function using the client API.","responses":{"201":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"create","weight":237,"cookies":false,"type":"","demo":"functions\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"functionId":{"type":"string","description":"Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[FUNCTION_ID]"},"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Function maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","default":true,"x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","default":true,"x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","default":"","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","default":"","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Control System) deployment.","default":"","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function.","default":"","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function.","default":"","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","default":false,"x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"},"templateRepository":{"type":"string","description":"Repository name of the template.","default":"","x-example":"[TEMPLATE_REPOSITORY]"},"templateOwner":{"type":"string","description":"The name of the owner of the template.","default":"","x-example":"[TEMPLATE_OWNER]"},"templateRootDirectory":{"type":"string","description":"Path to function code in the template repo.","default":"","x-example":"[TEMPLATE_ROOT_DIRECTORY]"},"templateBranch":{"type":"string","description":"Production branch for the repo linked to the function template.","default":"","x-example":"[TEMPLATE_BRANCH]"}},"required":["functionId","name","runtime"]}}]}},"\/functions\/runtimes":{"get":{"summary":"List runtimes","operationId":"functionsListRuntimes","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all runtimes that are currently active on your instance.","responses":{"200":{"description":"Runtimes List","schema":{"$ref":"#\/definitions\/runtimeList"}}},"x-appwrite":{"method":"listRuntimes","weight":239,"cookies":false,"type":"","demo":"functions\/list-runtimes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-runtimes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/functions\/{functionId}":{"get":{"summary":"Get Function","operationId":"functionsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"get","weight":240,"cookies":false,"type":"","demo":"functions\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"put":{"summary":"Update Function","operationId":"functionsUpdate","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update function by its unique ID.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"update","weight":243,"cookies":false,"type":"","demo":"functions\/update.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Function name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"runtime":{"type":"string","description":"Execution runtime.","default":null,"x-example":"node-14.5","enum":["node-14.5","node-16.0","node-18.0","node-19.0","node-20.0","php-8.0","php-8.1","php-8.2","ruby-3.0","ruby-3.1","ruby-3.2","python-3.8","python-3.9","python-3.10","python-3.11","dart-2.15","dart-2.16","dart-2.17","dart-2.18","dart-3.0","dotnet-3.1","dotnet-6.0","dotnet-7.0","java-8.0","java-11.0","java-17.0","java-18.0","swift-5.5","swift-5.8","kotlin-1.6","kotlin-1.8","cpp-17","cpp-20"],"x-enum-name":null,"x-enum-keys":[]},"execute":{"type":"array","description":"An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https:\/\/appwrite.io\/docs\/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.","default":[],"x-example":"[\"any\"]","items":{"type":"string"}},"events":{"type":"array","description":"Events list. Maximum of 100 events are allowed.","default":[],"x-example":null,"items":{"type":"string"}},"schedule":{"type":"string","description":"Schedule CRON syntax.","default":"","x-example":null},"timeout":{"type":"integer","description":"Maximum execution time in seconds.","default":15,"x-example":1},"enabled":{"type":"boolean","description":"Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.","default":true,"x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","default":true,"x-example":false},"entrypoint":{"type":"string","description":"Entrypoint File. This path is relative to the \"providerRootDirectory\".","default":"","x-example":"[ENTRYPOINT]"},"commands":{"type":"string","description":"Build Commands.","default":"","x-example":"[COMMANDS]"},"installationId":{"type":"string","description":"Appwrite Installation ID for VCS (Version Controle System) deployment.","default":"","x-example":"[INSTALLATION_ID]"},"providerRepositoryId":{"type":"string","description":"Repository ID of the repo linked to the function","default":"","x-example":"[PROVIDER_REPOSITORY_ID]"},"providerBranch":{"type":"string","description":"Production branch for the repo linked to the function","default":"","x-example":"[PROVIDER_BRANCH]"},"providerSilentMode":{"type":"boolean","description":"Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.","default":false,"x-example":false},"providerRootDirectory":{"type":"string","description":"Path to function code in the linked repo.","default":"","x-example":"[PROVIDER_ROOT_DIRECTORY]"}},"required":["name","runtime"]}}]},"delete":{"summary":"Delete Function","operationId":"functionsDelete","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a function by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":246,"cookies":false,"type":"","demo":"functions\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-function.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments":{"get":{"summary":"List Deployments","operationId":"functionsListDeployments","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the project's code deployments. You can use the query params to filter your results.","responses":{"200":{"description":"Deployments List","schema":{"$ref":"#\/definitions\/deploymentList"}}},"x-appwrite":{"method":"listDeployments","weight":248,"cookies":false,"type":"","demo":"functions\/list-deployments.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-deployments.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: size, buildId, activate, entrypoint, commands","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Deployment","operationId":"functionsCreateDeployment","consumes":["multipart\/form-data"],"produces":["application\/json"],"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](\/docs\/functions).\n\nUse the \"command\" param to set the entrypoint used to execute your code.","responses":{"202":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"createDeployment","weight":247,"cookies":false,"type":"","demo":"functions\/create-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":true,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"entrypoint","description":"Entrypoint File.","required":false,"type":"string","x-example":"[ENTRYPOINT]","in":"formData"},{"name":"commands","description":"Build Commands.","required":false,"type":"string","x-example":"[COMMANDS]","in":"formData"},{"name":"code","description":"Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.","required":true,"type":"file","in":"formData"},{"name":"activate","description":"Automatically activate the deployment when it is finished building.","required":true,"type":"boolean","x-example":false,"in":"formData"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}":{"get":{"summary":"Get Deployment","operationId":"functionsGetDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a code deployment by its unique ID.","responses":{"200":{"description":"Deployment","schema":{"$ref":"#\/definitions\/deployment"}}},"x-appwrite":{"method":"getDeployment","weight":249,"cookies":false,"type":"","demo":"functions\/get-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"patch":{"summary":"Update Function Deployment","operationId":"functionsUpdateDeployment","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update the function code deployment ID using the unique function ID. Use this endpoint to switch the code deployment that should be executed by the execution endpoint.","responses":{"200":{"description":"Function","schema":{"$ref":"#\/definitions\/function"}}},"x-appwrite":{"method":"updateDeployment","weight":245,"cookies":false,"type":"","demo":"functions\/update-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-function-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]},"delete":{"summary":"Delete Deployment","operationId":"functionsDeleteDeployment","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a code deployment by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteDeployment","weight":250,"cookies":false,"type":"","demo":"functions\/delete-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/builds\/{buildId}":{"post":{"summary":"Create Build","operationId":"functionsCreateBuild","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Create a new build for an Appwrite Function deployment. This endpoint can be used to retry a failed build.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"createBuild","weight":251,"cookies":false,"type":"","demo":"functions\/create-build.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-build.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"},{"name":"buildId","description":"Build unique ID.","required":true,"type":"string","x-example":"[BUILD_ID]","in":"path"}]}},"\/functions\/{functionId}\/deployments\/{deploymentId}\/download":{"get":{"summary":"Download Deployment","operationId":"functionsDownloadDeployment","consumes":["application\/json"],"produces":["*\/*"],"tags":["functions"],"description":"","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"downloadDeployment","weight":244,"cookies":false,"type":"location","demo":"functions\/download-deployment.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/download-deployment.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"deploymentId","description":"Deployment ID.","required":true,"type":"string","x-example":"[DEPLOYMENT_ID]","in":"path"}]}},"\/functions\/{functionId}\/executions":{"get":{"summary":"List Executions","operationId":"functionsListExecutions","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all the current user function execution logs. You can use the query params to filter your results.","responses":{"200":{"description":"Executions List","schema":{"$ref":"#\/definitions\/executionList"}}},"x-appwrite":{"method":"listExecutions","weight":253,"cookies":false,"type":"","demo":"functions\/list-executions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Execution","operationId":"functionsCreateExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.","responses":{"201":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"createExecution","weight":252,"cookies":false,"type":"","demo":"functions\/create-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"body":{"type":"string","description":"HTTP body of execution. Default value is empty string.","default":"","x-example":"[BODY]"},"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":"[PATH]"},"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":null,"x-enum-keys":[]},"headers":{"type":"object","description":"HTTP headers of execution. Defaults to empty.","default":[],"x-example":"{}"}}}}]}},"\/functions\/{functionId}\/executions\/{executionId}":{"get":{"summary":"Get Execution","operationId":"functionsGetExecution","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a function execution log by its unique ID.","responses":{"200":{"description":"Execution","schema":{"$ref":"#\/definitions\/execution"}}},"x-appwrite":{"method":"getExecution","weight":254,"cookies":false,"type":"","demo":"functions\/get-execution.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"execution.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"functionId","description":"Function ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"executionId","description":"Execution ID.","required":true,"type":"string","x-example":"[EXECUTION_ID]","in":"path"}]}},"\/functions\/{functionId}\/variables":{"get":{"summary":"List Variables","operationId":"functionsListVariables","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a list of all variables of a specific function.","responses":{"200":{"description":"Variables List","schema":{"$ref":"#\/definitions\/variableList"}}},"x-appwrite":{"method":"listVariables","weight":256,"cookies":false,"type":"","demo":"functions\/list-variables.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-variables.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"}]},"post":{"summary":"Create Variable","operationId":"functionsCreateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.","responses":{"201":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"createVariable","weight":255,"cookies":false,"type":"","demo":"functions\/create-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key","value"]}}]}},"\/functions\/{functionId}\/variables\/{variableId}":{"get":{"summary":"Get Variable","operationId":"functionsGetVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Get a variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"getVariable","weight":257,"cookies":false,"type":"","demo":"functions\/get-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]},"put":{"summary":"Update Variable","operationId":"functionsUpdateVariable","consumes":["application\/json"],"produces":["application\/json"],"tags":["functions"],"description":"Update variable by its unique ID.","responses":{"200":{"description":"Variable","schema":{"$ref":"#\/definitions\/variable"}}},"x-appwrite":{"method":"updateVariable","weight":258,"cookies":false,"type":"","demo":"functions\/update-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/update-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"key":{"type":"string","description":"Variable key. Max length: 255 chars.","default":null,"x-example":"[KEY]"},"value":{"type":"string","description":"Variable value. Max length: 8192 chars.","default":null,"x-example":"[VALUE]"}},"required":["key"]}}]},"delete":{"summary":"Delete Variable","operationId":"functionsDeleteVariable","consumes":["application\/json"],"produces":[],"tags":["functions"],"description":"Delete a variable by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteVariable","weight":259,"cookies":false,"type":"","demo":"functions\/delete-variable.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/delete-variable.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"functions.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"functionId","description":"Function unique ID.","required":true,"type":"string","x-example":"[FUNCTION_ID]","in":"path"},{"name":"variableId","description":"Variable unique ID.","required":true,"type":"string","x-example":"[VARIABLE_ID]","in":"path"}]}},"\/graphql":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlQuery","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"query","weight":293,"cookies":false,"type":"graphql","demo":"graphql\/query.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/graphql\/mutation":{"post":{"summary":"GraphQL Endpoint","operationId":"graphqlMutation","consumes":["application\/json"],"produces":["application\/json"],"tags":["graphql"],"description":"Execute a GraphQL mutation.","responses":{"200":{"description":"Any","schema":{"$ref":"#\/definitions\/any"}}},"x-appwrite":{"method":"mutation","weight":292,"cookies":false,"type":"graphql","demo":"graphql\/mutation.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/graphql\/post.md","rate-limit":60,"rate-time":60,"rate-key":"url:{url},ip:{ip}","scope":"graphql","platforms":["server","client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"query":{"type":"object","description":"The query or queries to execute.","default":{},"x-example":"{}"}},"required":["query"]}}]}},"\/health":{"get":{"summary":"Get HTTP","operationId":"healthGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite HTTP server is up and responsive.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"get","weight":107,"cookies":false,"type":"","demo":"health\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/anti-virus":{"get":{"summary":"Get Antivirus","operationId":"healthGetAntivirus","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite Antivirus server is up and connection is successful.","responses":{"200":{"description":"Health Antivirus","schema":{"$ref":"#\/definitions\/healthAntivirus"}}},"x-appwrite":{"method":"getAntivirus","weight":119,"cookies":false,"type":"","demo":"health\/get-antivirus.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-anti-virus.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/cache":{"get":{"summary":"Get Cache","operationId":"healthGetCache","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite in-memory cache servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getCache","weight":110,"cookies":false,"type":"","demo":"health\/get-cache.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-cache.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/db":{"get":{"summary":"Get DB","operationId":"healthGetDB","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite database servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getDB","weight":109,"cookies":false,"type":"","demo":"health\/get-d-b.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-db.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/pubsub":{"get":{"summary":"Get PubSub","operationId":"healthGetPubSub","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite pub-sub servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getPubSub","weight":112,"cookies":false,"type":"","demo":"health\/get-pub-sub.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-pubsub.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue":{"get":{"summary":"Get Queue","operationId":"healthGetQueue","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite queue messaging servers are up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getQueue","weight":111,"cookies":false,"type":"","demo":"health\/get-queue.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/certificates":{"get":{"summary":"Get Certificates Queue","operationId":"healthGetQueueCertificates","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of certificates that are waiting to be issued against [Letsencrypt](https:\/\/letsencrypt.org\/) in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueCertificates","weight":116,"cookies":false,"type":"","demo":"health\/get-queue-certificates.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-certificates.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/functions":{"get":{"summary":"Get Functions Queue","operationId":"healthGetQueueFunctions","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueFunctions","weight":117,"cookies":false,"type":"","demo":"health\/get-queue-functions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-functions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/logs":{"get":{"summary":"Get Logs Queue","operationId":"healthGetQueueLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of logs that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueLogs","weight":115,"cookies":false,"type":"","demo":"health\/get-queue-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/queue\/webhooks":{"get":{"summary":"Get Webhooks Queue","operationId":"healthGetQueueWebhooks","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.","responses":{"200":{"description":"Health Queue","schema":{"$ref":"#\/definitions\/healthQueue"}}},"x-appwrite":{"method":"getQueueWebhooks","weight":114,"cookies":false,"type":"","demo":"health\/get-queue-webhooks.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-webhooks.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/storage\/local":{"get":{"summary":"Get Local Storage","operationId":"healthGetStorageLocal","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite local storage device is up and connection is successful.","responses":{"200":{"description":"Health Status","schema":{"$ref":"#\/definitions\/healthStatus"}}},"x-appwrite":{"method":"getStorageLocal","weight":118,"cookies":false,"type":"","demo":"health\/get-storage-local.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-storage-local.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/health\/time":{"get":{"summary":"Get Time","operationId":"healthGetTime","consumes":["application\/json"],"produces":["application\/json"],"tags":["health"],"description":"Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.","responses":{"200":{"description":"Health Time","schema":{"$ref":"#\/definitions\/healthTime"}}},"x-appwrite":{"method":"getTime","weight":113,"cookies":false,"type":"","demo":"health\/get-time.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-time.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"health.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}]}},"\/locale":{"get":{"summary":"Get User Locale","operationId":"localeGet","consumes":["application\/json"],"produces":["application\/json"],"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))","responses":{"200":{"description":"Locale","schema":{"$ref":"#\/definitions\/locale"}}},"x-appwrite":{"method":"get","weight":99,"cookies":false,"type":"","demo":"locale\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/get-locale.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/localed","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/codes":{"get":{"summary":"List Locale Codes","operationId":"localeListCodes","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes).","responses":{"200":{"description":"Locale codes list","schema":{"$ref":"#\/definitions\/localeCodeList"}}},"x-appwrite":{"method":"listCodes","weight":100,"cookies":false,"type":"","demo":"locale\/list-codes.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-locale-codes.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/localeCode","offline-key":"current","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/continents":{"get":{"summary":"List Continents","operationId":"localeListContinents","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all continents. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Continents List","schema":{"$ref":"#\/definitions\/continentList"}}},"x-appwrite":{"method":"listContinents","weight":104,"cookies":false,"type":"","demo":"locale\/list-continents.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-continents.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/continents","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries":{"get":{"summary":"List Countries","operationId":"localeListCountries","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountries","weight":101,"cookies":false,"type":"","demo":"locale\/list-countries.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/eu":{"get":{"summary":"List EU Countries","operationId":"localeListCountriesEU","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Countries List","schema":{"$ref":"#\/definitions\/countryList"}}},"x-appwrite":{"method":"listCountriesEU","weight":102,"cookies":false,"type":"","demo":"locale\/list-countries-e-u.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-eu.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/eu","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/countries\/phones":{"get":{"summary":"List Countries Phone Codes","operationId":"localeListCountriesPhones","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all countries phone codes. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Phones List","schema":{"$ref":"#\/definitions\/phoneList"}}},"x-appwrite":{"method":"listCountriesPhones","weight":103,"cookies":false,"type":"","demo":"locale\/list-countries-phones.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-countries-phones.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/countries\/phones","offline-key":"","offline-response-key":"countryCode","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/currencies":{"get":{"summary":"List Currencies","operationId":"localeListCurrencies","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.","responses":{"200":{"description":"Currencies List","schema":{"$ref":"#\/definitions\/currencyList"}}},"x-appwrite":{"method":"listCurrencies","weight":105,"cookies":false,"type":"","demo":"locale\/list-currencies.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-currencies.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/currencies","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/locale\/languages":{"get":{"summary":"List Languages","operationId":"localeListLanguages","consumes":["application\/json"],"produces":["application\/json"],"tags":["locale"],"description":"List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.","responses":{"200":{"description":"Languages List","schema":{"$ref":"#\/definitions\/languageList"}}},"x-appwrite":{"method":"listLanguages","weight":106,"cookies":false,"type":"","demo":"locale\/list-languages.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/locale\/list-languages.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"locale.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/locale\/languages","offline-key":"","offline-response-key":"code","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}]}},"\/storage\/buckets":{"get":{"summary":"List buckets","operationId":"storageListBuckets","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the storage buckets. You can use the query params to filter your results.","responses":{"200":{"description":"Buckets List","schema":{"$ref":"#\/definitions\/bucketList"}}},"x-appwrite":{"method":"listBuckets","weight":168,"cookies":false,"type":"","demo":"storage\/list-buckets.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-buckets.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create bucket","operationId":"storageCreateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new storage bucket.","responses":{"201":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"createBucket","weight":167,"cookies":false,"type":"","demo":"storage\/create-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"bucketId":{"type":"string","description":"Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[BUCKET_ID]"},"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","default":30000000,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["bucketId","name"]}}]}},"\/storage\/buckets\/{bucketId}":{"get":{"summary":"Get Bucket","operationId":"storageGetBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"getBucket","weight":169,"cookies":false,"type":"","demo":"storage\/get-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]},"put":{"summary":"Update Bucket","operationId":"storageUpdateBucket","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a storage bucket by its unique ID.","responses":{"200":{"description":"Bucket","schema":{"$ref":"#\/definitions\/bucket"}}},"x-appwrite":{"method":"updateBucket","weight":170,"cookies":false,"type":"","demo":"storage\/update-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Bucket name","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}},"fileSecurity":{"type":"boolean","description":"Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](\/docs\/permissions).","default":false,"x-example":false},"enabled":{"type":"boolean","description":"Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.","default":true,"x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size allowed in bytes. Maximum allowed value is 30MB.","default":null,"x-example":1},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.","default":[],"x-example":null,"items":{"type":"string"}},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Can be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd), For file size above 20MB compression is skipped even if it's enabled","default":"none","x-example":"none","enum":["none","gzip","zstd"],"x-enum-name":null,"x-enum-keys":[]},"encryption":{"type":"boolean","description":"Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled","default":true,"x-example":false},"antivirus":{"type":"boolean","description":"Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled","default":true,"x-example":false}},"required":["name"]}}]},"delete":{"summary":"Delete Bucket","operationId":"storageDeleteBucket","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a storage bucket by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteBucket","weight":171,"cookies":false,"type":"","demo":"storage\/delete-bucket.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-bucket.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"buckets.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"bucketId","description":"Bucket unique ID.","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files":{"get":{"summary":"List Files","operationId":"storageListFiles","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a list of all the user files. You can use the query params to filter your results.","responses":{"200":{"description":"Files List","schema":{"$ref":"#\/definitions\/fileList"}}},"x-appwrite":{"method":"listFiles","weight":173,"cookies":false,"type":"","demo":"storage\/list-files.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/list-files.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create File","operationId":"storageCreateFile","consumes":["multipart\/form-data"],"produces":["application\/json"],"tags":["storage"],"description":"Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](\/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","responses":{"201":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"createFile","weight":172,"cookies":false,"type":"upload","demo":"storage\/create-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/create-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","required":true,"x-upload-id":true,"type":"string","x-example":"[FILE_ID]","in":"formData"},{"name":"file","description":"Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](\/docs\/storage#file-input).","required":true,"type":"file","in":"formData"},{"name":"permissions","description":"An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](\/docs\/permissions).","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"x-example":"[\"read(\"any\")\"]","in":"formData"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}":{"get":{"summary":"Get File","operationId":"storageGetFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"getFile","weight":174,"cookies":false,"type":"","demo":"storage\/get-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]},"put":{"summary":"Update File","operationId":"storageUpdateFile","consumes":["application\/json"],"produces":["application\/json"],"tags":["storage"],"description":"Update a file by its unique ID. Only users with write permissions have access to update this resource.","responses":{"200":{"description":"File","schema":{"$ref":"#\/definitions\/file"}}},"x-appwrite":{"method":"updateFile","weight":178,"cookies":false,"type":"","demo":"storage\/update-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/update-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File unique ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file","default":null,"x-example":"[NAME]"},"permissions":{"type":"array","description":"An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](\/docs\/permissions).","default":null,"x-example":"[\"read(\"any\")\"]","items":{"type":"string"}}}}}]},"delete":{"summary":"Delete File","operationId":"storageDeleteFile","consumes":["application\/json"],"produces":[],"tags":["storage"],"description":"Delete a file by its unique ID. Only users with write permissions have access to delete this resource.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteFile","weight":179,"cookies":false,"type":"","demo":"storage\/delete-file.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/delete-file.md","rate-limit":60,"rate-time":60,"rate-key":"ip:{ip},method:{method},url:{url},userId:{userId}","scope":"files.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/download":{"get":{"summary":"Get File for Download","operationId":"storageGetFileDownload","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileDownload","weight":176,"cookies":false,"type":"location","demo":"storage\/get-file-download.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-download.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/preview":{"get":{"summary":"Get File Preview","operationId":"storageGetFilePreview","consumes":["application\/json"],"produces":["image\/*"],"tags":["storage"],"description":"Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.","responses":{"200":{"description":"Image","schema":{"type":"file"}}},"x-appwrite":{"method":"getFilePreview","weight":175,"cookies":false,"type":"location","demo":"storage\/get-file-preview.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-preview.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"},{"name":"width","description":"Resize preview image width, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"height","description":"Resize preview image height, Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"gravity","description":"Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right","required":false,"type":"string","x-example":"center","enum":["center","top-left","top","top-right","left","right","bottom-left","bottom","bottom-right"],"x-enum-name":"ImageGravity","x-enum-keys":[],"default":"center","in":"query"},{"name":"quality","description":"Preview image quality. Pass an integer between 0 to 100. Defaults to 100.","required":false,"type":"integer","format":"int32","x-example":0,"default":100,"in":"query"},{"name":"borderWidth","description":"Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"borderColor","description":"Preview image border color. Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"borderRadius","description":"Preview image border radius in pixels. Pass an integer between 0 to 4000.","required":false,"type":"integer","format":"int32","x-example":0,"default":0,"in":"query"},{"name":"opacity","description":"Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.","required":false,"type":"number","format":"float","x-example":0,"default":1,"in":"query"},{"name":"rotation","description":"Preview image rotation in degrees. Pass an integer between -360 and 360.","required":false,"type":"integer","format":"int32","x-example":-360,"default":0,"in":"query"},{"name":"background","description":"Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.","required":false,"type":"string","default":"","in":"query"},{"name":"output","description":"Output format type (jpeg, jpg, png, gif and webp).","required":false,"type":"string","x-example":"jpg","enum":["jpg","jpeg","gif","png","webp"],"x-enum-name":"ImageFormat","x-enum-keys":[],"default":"","in":"query"}]}},"\/storage\/buckets\/{bucketId}\/files\/{fileId}\/view":{"get":{"summary":"Get File for View","operationId":"storageGetFileView","consumes":["application\/json"],"produces":["*\/*"],"tags":["storage"],"description":"Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.","responses":{"200":{"description":"File","schema":{"type":"file"}}},"x-appwrite":{"method":"getFileView","weight":177,"cookies":false,"type":"location","demo":"storage\/get-file-view.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/storage\/get-file-view.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"files.read","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"bucketId","description":"Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](\/docs\/server\/storage#createBucket).","required":true,"type":"string","x-example":"[BUCKET_ID]","in":"path"},{"name":"fileId","description":"File ID.","required":true,"type":"string","x-example":"[FILE_ID]","in":"path"}]}},"\/teams":{"get":{"summary":"List Teams","operationId":"teamsList","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.","responses":{"200":{"description":"Teams List","schema":{"$ref":"#\/definitions\/teamList"}}},"x-appwrite":{"method":"list","weight":183,"cookies":false,"type":"","demo":"teams\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-teams.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team","operationId":"teamsCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.","responses":{"201":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"create","weight":182,"cookies":false,"type":"","demo":"teams\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"teamId":{"type":"string","description":"Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[TEAM_ID]"},"name":{"type":"string","description":"Team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"},"roles":{"type":"array","description":"Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":["owner"],"x-example":null,"items":{"type":"string"}}},"required":["teamId","name"]}}]}},"\/teams\/{teamId}":{"get":{"summary":"Get Team","operationId":"teamsGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team by its ID. All team members have read access for this resource.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"get","weight":184,"cookies":false,"type":"","demo":"teams\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Name","operationId":"teamsUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's name by its unique ID.","responses":{"200":{"description":"Team","schema":{"$ref":"#\/definitions\/team"}}},"x-appwrite":{"method":"updateName","weight":186,"cookies":false,"type":"","demo":"teams\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams","offline-key":"{teamId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"New team name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]},"delete":{"summary":"Delete Team","operationId":"teamsDelete","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"Delete a team using its ID. Only team members with the owner role can delete the team.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":188,"cookies":false,"type":"","demo":"teams\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships":{"get":{"summary":"List Team Memberships","operationId":"teamsListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":190,"cookies":false,"type":"","demo":"teams\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/list-team-members.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create Team Membership","operationId":"teamsCreateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/client\/teams#teamsUpdateMembershipStatus) 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","responses":{"201":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"createMembership","weight":189,"cookies":false,"type":"","demo":"teams\/create-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/create-team-membership.md","rate-limit":10,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"Email of the new team member.","default":"","x-example":"email@example.com"},"userId":{"type":"string","description":"ID of the user to be added to a team.","default":"","x-example":"[USER_ID]"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":"","x-example":"+12065550100"},"roles":{"type":"array","description":"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](\/docs\/permissions). Maximum of 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}},"url":{"type":"string","description":"URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.","default":null,"x-example":"https:\/\/example.com"},"name":{"type":"string","description":"Name of the new team member. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["roles","url"]}}]}},"\/teams\/{teamId}\/memberships\/{membershipId}":{"get":{"summary":"Get Team Membership","operationId":"teamsGetMembership","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get a team member by the membership unique id. All team members have read access for this resource.","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"getMembership","weight":191,"cookies":false,"type":"","demo":"teams\/get-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-member.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/memberships","offline-key":"{membershipId}","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]},"patch":{"summary":"Update Membership","operationId":"teamsUpdateMembership","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions).\n","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembership","weight":192,"cookies":false,"type":"","demo":"teams\/update-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"roles":{"type":"array","description":"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 100 roles are allowed, each 32 characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["roles"]}}]},"delete":{"summary":"Delete Team Membership","operationId":"teamsDeleteMembership","consumes":["application\/json"],"produces":[],"tags":["teams"],"description":"This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteMembership","weight":194,"cookies":false,"type":"","demo":"teams\/delete-membership.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/delete-team-membership.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"}]}},"\/teams\/{teamId}\/memberships\/{membershipId}\/status":{"patch":{"summary":"Update Team Membership Status","operationId":"teamsUpdateMembershipStatus","consumes":["application\/json"],"produces":["application\/json"],"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","responses":{"200":{"description":"Membership","schema":{"$ref":"#\/definitions\/membership"}}},"x-appwrite":{"method":"updateMembershipStatus","weight":193,"cookies":false,"type":"","demo":"teams\/update-membership-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-membership-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"public","platforms":["client","server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"membershipId","description":"Membership ID.","required":true,"type":"string","x-example":"[MEMBERSHIP_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID.","default":null,"x-example":"[USER_ID]"},"secret":{"type":"string","description":"Secret key.","default":null,"x-example":"[SECRET]"}},"required":["userId","secret"]}}]}},"\/teams\/{teamId}\/prefs":{"get":{"summary":"Get Team Preferences","operationId":"teamsGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](\/docs\/client\/account#accountGetPrefs).","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":185,"cookies":false,"type":"","demo":"teams\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/get-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.read","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"}]},"put":{"summary":"Update Preferences","operationId":"teamsUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["teams"],"description":"Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":187,"cookies":false,"type":"","demo":"teams\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/teams\/update-team-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"teams.write","platforms":["client","server"],"packaging":false,"offline-model":"\/teams\/{teamId}\/prefs","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"JWT":[]}},"security":[{"Project":[],"JWT":[]}],"parameters":[{"name":"teamId","description":"Team ID.","required":true,"type":"string","x-example":"[TEAM_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users":{"get":{"summary":"List Users","operationId":"usersList","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a list of all the project's users. You can use the query params to filter your results.","responses":{"200":{"description":"Users List","schema":{"$ref":"#\/definitions\/userList"}}},"x-appwrite":{"method":"list","weight":204,"cookies":false,"type":"","demo":"users\/list.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-users.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]},"post":{"summary":"Create User","operationId":"usersCreate","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"create","weight":196,"cookies":false,"type":"","demo":"users\/create.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"phone":{"type":"string","description":"Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.","default":null,"x-example":"+12065550100"},"password":{"type":"string","description":"Plain text user password. Must be at least 8 chars.","default":"","x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId"]}}]}},"\/users\/argon2":{"post":{"summary":"Create User with Argon2 Password","operationId":"usersCreateArgon2User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Argon2](https:\/\/en.wikipedia.org\/wiki\/Argon2) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createArgon2User","weight":199,"cookies":false,"type":"","demo":"users\/create-argon2user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-argon2-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Argon2.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/bcrypt":{"post":{"summary":"Create User with Bcrypt Password","operationId":"usersCreateBcryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Bcrypt](https:\/\/en.wikipedia.org\/wiki\/Bcrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createBcryptUser","weight":197,"cookies":false,"type":"","demo":"users\/create-bcrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-bcrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Bcrypt.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/identities":{"get":{"summary":"List Identities","operationId":"usersListIdentities","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get identities for all users.","responses":{"200":{"description":"Identities List","schema":{"$ref":"#\/definitions\/identityList"}}},"x-appwrite":{"method":"listIdentities","weight":210,"cookies":false,"type":"","demo":"users\/list-identities.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-identities.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry","required":false,"type":"string","default":[],"in":"query"},{"name":"search","description":"Search term to filter your list results. Max length: 256 chars.","required":false,"type":"string","x-example":"[SEARCH]","default":"","in":"query"}]}},"\/users\/identities\/{identityId}":{"delete":{"summary":"Delete Identity","operationId":"usersDeleteIdentity","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete an identity by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteIdentity","weight":223,"cookies":false,"type":"","demo":"users\/delete-identity.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-identity.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"identityId","description":"Identity ID.","required":true,"type":"string","x-example":"[IDENTITY_ID]","in":"path"}]}},"\/users\/md5":{"post":{"summary":"Create User with MD5 Password","operationId":"usersCreateMD5User","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [MD5](https:\/\/en.wikipedia.org\/wiki\/MD5) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createMD5User","weight":198,"cookies":false,"type":"","demo":"users\/create-m-d5user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-md5-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using MD5.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/phpass":{"post":{"summary":"Create User with PHPass Password","operationId":"usersCreatePHPassUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [PHPass](https:\/\/www.openwall.com\/phpass\/) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createPHPassUser","weight":201,"cookies":false,"type":"","demo":"users\/create-p-h-pass-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-phpass-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using PHPass.","default":null,"x-example":"password"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/scrypt":{"post":{"summary":"Create User with Scrypt Password","operationId":"usersCreateScryptUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt](https:\/\/github.com\/Tarsnap\/scrypt) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptUser","weight":202,"cookies":false,"type":"","demo":"users\/create-scrypt-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Optional salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordCpu":{"type":"integer","description":"Optional CPU cost used to hash password.","default":null,"x-example":null},"passwordMemory":{"type":"integer","description":"Optional memory cost used to hash password.","default":null,"x-example":null},"passwordParallel":{"type":"integer","description":"Optional parallelization cost used to hash password.","default":null,"x-example":null},"passwordLength":{"type":"integer","description":"Optional hash length used to hash password.","default":null,"x-example":null},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordCpu","passwordMemory","passwordParallel","passwordLength"]}}]}},"\/users\/scrypt-modified":{"post":{"summary":"Create User with Scrypt Modified Password","operationId":"usersCreateScryptModifiedUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [Scrypt Modified](https:\/\/gist.github.com\/Meldiron\/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createScryptModifiedUser","weight":203,"cookies":false,"type":"","demo":"users\/create-scrypt-modified-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-scrypt-modified-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using Scrypt Modified.","default":null,"x-example":"password"},"passwordSalt":{"type":"string","description":"Salt used to hash password.","default":null,"x-example":"[PASSWORD_SALT]"},"passwordSaltSeparator":{"type":"string","description":"Salt separator used to hash password.","default":null,"x-example":"[PASSWORD_SALT_SEPARATOR]"},"passwordSignerKey":{"type":"string","description":"Signer key used to hash password.","default":null,"x-example":"[PASSWORD_SIGNER_KEY]"},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password","passwordSalt","passwordSaltSeparator","passwordSignerKey"]}}]}},"\/users\/sha":{"post":{"summary":"Create User with SHA Password","operationId":"usersCreateSHAUser","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Create a new user. Password provided must be hashed with the [SHA](https:\/\/en.wikipedia.org\/wiki\/Secure_Hash_Algorithm) algorithm. Use the [POST \/users](\/docs\/server\/users#usersCreate) endpoint to create users with a plain text password.","responses":{"201":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"createSHAUser","weight":200,"cookies":false,"type":"","demo":"users\/create-s-h-a-user.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/create-sha-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"payload","in":"body","schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.","default":null,"x-example":"[USER_ID]"},"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"},"password":{"type":"string","description":"User password hashed using SHA.","default":null,"x-example":"password"},"passwordVersion":{"type":"string","description":"Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512\/224', 'sha512\/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'","default":"","x-example":"sha1","enum":["sha1","sha224","sha256","sha384","sha512\/224","sha512\/256","sha512","sha3-224","sha3-256","sha3-384","sha3-512"],"x-enum-name":null,"x-enum-keys":[]},"name":{"type":"string","description":"User name. Max length: 128 chars.","default":"","x-example":"[NAME]"}},"required":["userId","email","password"]}}]}},"\/users\/{userId}":{"get":{"summary":"Get User","operationId":"usersGet","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get a user by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"get","weight":205,"cookies":false,"type":"","demo":"users\/get.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User","operationId":"usersDelete","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](\/docs\/server\/users#usersUpdateStatus) endpoint instead.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"delete","weight":222,"cookies":false,"type":"","demo":"users\/delete.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/email":{"patch":{"summary":"Update Email","operationId":"usersUpdateEmail","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmail","weight":216,"cookies":false,"type":"","demo":"users\/update-email.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"email":{"type":"string","description":"User email.","default":null,"x-example":"email@example.com"}},"required":["email"]}}]}},"\/users\/{userId}\/labels":{"put":{"summary":"Update User Labels","operationId":"usersUpdateLabels","consumes":["application\/json"],"produces":["application\/json"],"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](\/docs\/permissions) for more info.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateLabels","weight":212,"cookies":false,"type":"","demo":"users\/update-labels.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-labels.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"labels":{"type":"array","description":"Array of user labels. Replaces the previous labels. Maximum of 5 labels are allowed, each up to 36 alphanumeric characters long.","default":null,"x-example":null,"items":{"type":"string"}}},"required":["labels"]}}]}},"\/users\/{userId}\/logs":{"get":{"summary":"List User Logs","operationId":"usersListLogs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user activity logs list by its unique ID.","responses":{"200":{"description":"Logs List","schema":{"$ref":"#\/definitions\/logList"}}},"x-appwrite":{"method":"listLogs","weight":209,"cookies":false,"type":"","demo":"users\/list-logs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-logs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"queries","description":"Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Only supported methods are limit and offset","required":false,"type":"array","collectionFormat":"multi","items":{"type":"string"},"default":[],"in":"query"}]}},"\/users\/{userId}\/memberships":{"get":{"summary":"List User Memberships","operationId":"usersListMemberships","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user membership list by its unique ID.","responses":{"200":{"description":"Memberships List","schema":{"$ref":"#\/definitions\/membershipList"}}},"x-appwrite":{"method":"listMemberships","weight":208,"cookies":false,"type":"","demo":"users\/list-memberships.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-memberships.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/name":{"patch":{"summary":"Update Name","operationId":"usersUpdateName","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user name by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateName","weight":214,"cookies":false,"type":"","demo":"users\/update-name.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-name.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"name":{"type":"string","description":"User name. Max length: 128 chars.","default":null,"x-example":"[NAME]"}},"required":["name"]}}]}},"\/users\/{userId}\/password":{"patch":{"summary":"Update Password","operationId":"usersUpdatePassword","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user password by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePassword","weight":215,"cookies":false,"type":"","demo":"users\/update-password.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-password.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"password":{"type":"string","description":"New user password. Must be at least 8 chars.","default":null,"x-example":null}},"required":["password"]}}]}},"\/users\/{userId}\/phone":{"patch":{"summary":"Update Phone","operationId":"usersUpdatePhone","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhone","weight":217,"cookies":false,"type":"","demo":"users\/update-phone.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"number":{"type":"string","description":"User phone number.","default":null,"x-example":"+12065550100"}},"required":["number"]}}]}},"\/users\/{userId}\/prefs":{"get":{"summary":"Get User Preferences","operationId":"usersGetPrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user preferences by its unique ID.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"getPrefs","weight":206,"cookies":false,"type":"","demo":"users\/get-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/get-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"patch":{"summary":"Update User Preferences","operationId":"usersUpdatePrefs","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.","responses":{"200":{"description":"Preferences","schema":{"$ref":"#\/definitions\/preferences"}}},"x-appwrite":{"method":"updatePrefs","weight":219,"cookies":false,"type":"","demo":"users\/update-prefs.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-prefs.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"prefs":{"type":"object","description":"Prefs key-value JSON object.","default":{},"x-example":"{}"}},"required":["prefs"]}}]}},"\/users\/{userId}\/sessions":{"get":{"summary":"List User Sessions","operationId":"usersListSessions","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Get the user sessions list by its unique ID.","responses":{"200":{"description":"Sessions List","schema":{"$ref":"#\/definitions\/sessionList"}}},"x-appwrite":{"method":"listSessions","weight":207,"cookies":false,"type":"","demo":"users\/list-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/list-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.read","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]},"delete":{"summary":"Delete User Sessions","operationId":"usersDeleteSessions","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete all user's sessions by using the user's unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSessions","weight":221,"cookies":false,"type":"","demo":"users\/delete-sessions.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-sessions.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"}]}},"\/users\/{userId}\/sessions\/{sessionId}":{"delete":{"summary":"Delete User Session","operationId":"usersDeleteSession","consumes":["application\/json"],"produces":[],"tags":["users"],"description":"Delete a user sessions by its unique ID.","responses":{"204":{"description":"No content"}},"x-appwrite":{"method":"deleteSession","weight":220,"cookies":false,"type":"","demo":"users\/delete-session.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/delete-user-session.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"sessionId","description":"Session ID.","required":true,"type":"string","x-example":"[SESSION_ID]","in":"path"}]}},"\/users\/{userId}\/status":{"patch":{"summary":"Update User Status","operationId":"usersUpdateStatus","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateStatus","weight":211,"cookies":false,"type":"","demo":"users\/update-status.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-status.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"status":{"type":"boolean","description":"User Status. To activate the user pass `true` and to block the user pass `false`.","default":null,"x-example":false}},"required":["status"]}}]}},"\/users\/{userId}\/verification":{"patch":{"summary":"Update Email Verification","operationId":"usersUpdateEmailVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user email verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updateEmailVerification","weight":218,"cookies":false,"type":"","demo":"users\/update-email-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-email-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"emailVerification":{"type":"boolean","description":"User email verification status.","default":null,"x-example":false}},"required":["emailVerification"]}}]}},"\/users\/{userId}\/verification\/phone":{"patch":{"summary":"Update Phone Verification","operationId":"usersUpdatePhoneVerification","consumes":["application\/json"],"produces":["application\/json"],"tags":["users"],"description":"Update the user phone verification status by its unique ID.","responses":{"200":{"description":"User","schema":{"$ref":"#\/definitions\/user"}}},"x-appwrite":{"method":"updatePhoneVerification","weight":213,"cookies":false,"type":"","demo":"users\/update-phone-verification.md","edit":"https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/users\/update-user-phone-verification.md","rate-limit":0,"rate-time":3600,"rate-key":"url:{url},ip:{ip}","scope":"users.write","platforms":["server"],"packaging":false,"offline-model":"","offline-key":"","offline-response-key":"$id","auth":{"Project":[],"Key":[]}},"security":[{"Project":[],"Key":[]}],"parameters":[{"name":"userId","description":"User ID.","required":true,"type":"string","x-example":"[USER_ID]","in":"path"},{"name":"payload","in":"body","schema":{"type":"object","properties":{"phoneVerification":{"type":"boolean","description":"User phone verification status.","default":null,"x-example":false}},"required":["phoneVerification"]}}]}}},"tags":[{"name":"account","description":"The Account service allows you to authenticate and manage a user account.","x-globalAttributes":[]},{"name":"avatars","description":"The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.","x-globalAttributes":[]},{"name":"databases","description":"The Databases service allows you to create structured collections of documents, query and filter lists of documents","x-globalAttributes":["databaseId"]},{"name":"locale","description":"The Locale service allows you to customize your app based on your users' location.","x-globalAttributes":[]},{"name":"health","description":"The Health service allows you to both validate and monitor your Appwrite server's health.","x-globalAttributes":[]},{"name":"projects","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"project","description":"The Project service allows you to manage all the projects in your Appwrite server.","x-globalAttributes":[]},{"name":"storage","description":"The Storage service allows you to manage your project files.","x-globalAttributes":[]},{"name":"teams","description":"The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources","x-globalAttributes":[]},{"name":"users","description":"The Users service allows you to manage your project users.","x-globalAttributes":[]},{"name":"functions","description":"The Functions Service allows you view, create and manage your Cloud Functions.","x-globalAttributes":[]},{"name":"proxy","description":"The Proxy Service allows you to configure actions for your domains beyond DNS configuration.","x-globalAttributes":[]},{"name":"graphql","description":"The GraphQL API allows you to query and mutate your Appwrite server using GraphQL.","x-globalAttributes":[]},{"name":"console","description":"The Console service allows you to interact with console relevant informations.","x-globalAttributes":[]},{"name":"migrations","description":"The Migrations service allows you to migrate third-party data to your Appwrite project.","x-globalAttributes":[]}],"definitions":{"any":{"description":"Any","type":"object","additionalProperties":true},"documentList":{"description":"Documents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of documents documents that matched your query.","x-example":5,"format":"int32"},"documents":{"type":"array","description":"List of documents.","items":{"type":"object","$ref":"#\/definitions\/document"},"x-example":""}},"required":["total","documents"]},"collectionList":{"description":"Collections List","type":"object","properties":{"total":{"type":"integer","description":"Total number of collections documents that matched your query.","x-example":5,"format":"int32"},"collections":{"type":"array","description":"List of collections.","items":{"type":"object","$ref":"#\/definitions\/collection"},"x-example":""}},"required":["total","collections"]},"databaseList":{"description":"Databases List","type":"object","properties":{"total":{"type":"integer","description":"Total number of databases documents that matched your query.","x-example":5,"format":"int32"},"databases":{"type":"array","description":"List of databases.","items":{"type":"object","$ref":"#\/definitions\/database"},"x-example":""}},"required":["total","databases"]},"indexList":{"description":"Indexes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of indexes documents that matched your query.","x-example":5,"format":"int32"},"indexes":{"type":"array","description":"List of indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":""}},"required":["total","indexes"]},"userList":{"description":"Users List","type":"object","properties":{"total":{"type":"integer","description":"Total number of users documents that matched your query.","x-example":5,"format":"int32"},"users":{"type":"array","description":"List of users.","items":{"type":"object","$ref":"#\/definitions\/user"},"x-example":""}},"required":["total","users"]},"sessionList":{"description":"Sessions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of sessions documents that matched your query.","x-example":5,"format":"int32"},"sessions":{"type":"array","description":"List of sessions.","items":{"type":"object","$ref":"#\/definitions\/session"},"x-example":""}},"required":["total","sessions"]},"identityList":{"description":"Identities List","type":"object","properties":{"total":{"type":"integer","description":"Total number of identities documents that matched your query.","x-example":5,"format":"int32"},"identities":{"type":"array","description":"List of identities.","items":{"type":"object","$ref":"#\/definitions\/identity"},"x-example":""}},"required":["total","identities"]},"logList":{"description":"Logs List","type":"object","properties":{"total":{"type":"integer","description":"Total number of logs documents that matched your query.","x-example":5,"format":"int32"},"logs":{"type":"array","description":"List of logs.","items":{"type":"object","$ref":"#\/definitions\/log"},"x-example":""}},"required":["total","logs"]},"fileList":{"description":"Files List","type":"object","properties":{"total":{"type":"integer","description":"Total number of files documents that matched your query.","x-example":5,"format":"int32"},"files":{"type":"array","description":"List of files.","items":{"type":"object","$ref":"#\/definitions\/file"},"x-example":""}},"required":["total","files"]},"bucketList":{"description":"Buckets List","type":"object","properties":{"total":{"type":"integer","description":"Total number of buckets documents that matched your query.","x-example":5,"format":"int32"},"buckets":{"type":"array","description":"List of buckets.","items":{"type":"object","$ref":"#\/definitions\/bucket"},"x-example":""}},"required":["total","buckets"]},"teamList":{"description":"Teams List","type":"object","properties":{"total":{"type":"integer","description":"Total number of teams documents that matched your query.","x-example":5,"format":"int32"},"teams":{"type":"array","description":"List of teams.","items":{"type":"object","$ref":"#\/definitions\/team"},"x-example":""}},"required":["total","teams"]},"membershipList":{"description":"Memberships List","type":"object","properties":{"total":{"type":"integer","description":"Total number of memberships documents that matched your query.","x-example":5,"format":"int32"},"memberships":{"type":"array","description":"List of memberships.","items":{"type":"object","$ref":"#\/definitions\/membership"},"x-example":""}},"required":["total","memberships"]},"functionList":{"description":"Functions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of functions documents that matched your query.","x-example":5,"format":"int32"},"functions":{"type":"array","description":"List of functions.","items":{"type":"object","$ref":"#\/definitions\/function"},"x-example":""}},"required":["total","functions"]},"runtimeList":{"description":"Runtimes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of runtimes documents that matched your query.","x-example":5,"format":"int32"},"runtimes":{"type":"array","description":"List of runtimes.","items":{"type":"object","$ref":"#\/definitions\/runtime"},"x-example":""}},"required":["total","runtimes"]},"deploymentList":{"description":"Deployments List","type":"object","properties":{"total":{"type":"integer","description":"Total number of deployments documents that matched your query.","x-example":5,"format":"int32"},"deployments":{"type":"array","description":"List of deployments.","items":{"type":"object","$ref":"#\/definitions\/deployment"},"x-example":""}},"required":["total","deployments"]},"executionList":{"description":"Executions List","type":"object","properties":{"total":{"type":"integer","description":"Total number of executions documents that matched your query.","x-example":5,"format":"int32"},"executions":{"type":"array","description":"List of executions.","items":{"type":"object","$ref":"#\/definitions\/execution"},"x-example":""}},"required":["total","executions"]},"countryList":{"description":"Countries List","type":"object","properties":{"total":{"type":"integer","description":"Total number of countries documents that matched your query.","x-example":5,"format":"int32"},"countries":{"type":"array","description":"List of countries.","items":{"type":"object","$ref":"#\/definitions\/country"},"x-example":""}},"required":["total","countries"]},"continentList":{"description":"Continents List","type":"object","properties":{"total":{"type":"integer","description":"Total number of continents documents that matched your query.","x-example":5,"format":"int32"},"continents":{"type":"array","description":"List of continents.","items":{"type":"object","$ref":"#\/definitions\/continent"},"x-example":""}},"required":["total","continents"]},"languageList":{"description":"Languages List","type":"object","properties":{"total":{"type":"integer","description":"Total number of languages documents that matched your query.","x-example":5,"format":"int32"},"languages":{"type":"array","description":"List of languages.","items":{"type":"object","$ref":"#\/definitions\/language"},"x-example":""}},"required":["total","languages"]},"currencyList":{"description":"Currencies List","type":"object","properties":{"total":{"type":"integer","description":"Total number of currencies documents that matched your query.","x-example":5,"format":"int32"},"currencies":{"type":"array","description":"List of currencies.","items":{"type":"object","$ref":"#\/definitions\/currency"},"x-example":""}},"required":["total","currencies"]},"phoneList":{"description":"Phones List","type":"object","properties":{"total":{"type":"integer","description":"Total number of phones documents that matched your query.","x-example":5,"format":"int32"},"phones":{"type":"array","description":"List of phones.","items":{"type":"object","$ref":"#\/definitions\/phone"},"x-example":""}},"required":["total","phones"]},"variableList":{"description":"Variables List","type":"object","properties":{"total":{"type":"integer","description":"Total number of variables documents that matched your query.","x-example":5,"format":"int32"},"variables":{"type":"array","description":"List of variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":""}},"required":["total","variables"]},"localeCodeList":{"description":"Locale codes list","type":"object","properties":{"total":{"type":"integer","description":"Total number of localeCodes documents that matched your query.","x-example":5,"format":"int32"},"localeCodes":{"type":"array","description":"List of localeCodes.","items":{"type":"object","$ref":"#\/definitions\/localeCode"},"x-example":""}},"required":["total","localeCodes"]},"database":{"description":"Database","type":"object","properties":{"$id":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Database name.","x-example":"My Database"},"$createdAt":{"type":"string","description":"Database creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Database update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"enabled":{"type":"boolean","description":"If database is enabled. Can be 'enabled' or 'disabled'. When disabled, the database is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false}},"required":["$id","name","$createdAt","$updatedAt","enabled"]},"collection":{"description":"Collection","type":"object","properties":{"$id":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Collection creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Collection update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Collection permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c16897e"},"name":{"type":"string","description":"Collection name.","x-example":"My Collection"},"enabled":{"type":"boolean","description":"Collection enabled. Can be 'enabled' or 'disabled'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.","x-example":false},"documentSecurity":{"type":"boolean","description":"Whether document-level permissions are enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"attributes":{"type":"array","description":"Collection attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":{}},"indexes":{"type":"array","description":"Collection indexes.","items":{"type":"object","$ref":"#\/definitions\/index"},"x-example":{}}},"required":["$id","$createdAt","$updatedAt","$permissions","databaseId","name","enabled","documentSecurity","attributes","indexes"]},"attributeList":{"description":"Attributes List","type":"object","properties":{"total":{"type":"integer","description":"Total number of attributes in the given collection.","x-example":5,"format":"int32"},"attributes":{"type":"array","description":"List of attributes.","items":{"x-anyOf":[{"$ref":"#\/definitions\/attributeBoolean"},{"$ref":"#\/definitions\/attributeInteger"},{"$ref":"#\/definitions\/attributeFloat"},{"$ref":"#\/definitions\/attributeEmail"},{"$ref":"#\/definitions\/attributeEnum"},{"$ref":"#\/definitions\/attributeUrl"},{"$ref":"#\/definitions\/attributeIp"},{"$ref":"#\/definitions\/attributeDatetime"},{"$ref":"#\/definitions\/attributeRelationship"},{"$ref":"#\/definitions\/attributeString"}]},"x-example":""}},"required":["total","attributes"]},"attributeString":{"description":"AttributeString","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"size":{"type":"integer","description":"Attribute size.","x-example":128,"format":"int32"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default","x-nullable":true}},"required":["key","type","status","error","required","size"]},"attributeInteger":{"description":"AttributeInteger","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"count"},"type":{"type":"string","description":"Attribute type.","x-example":"integer"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"integer","description":"Minimum value to enforce for new documents.","x-example":1,"format":"int32","x-nullable":true},"max":{"type":"integer","description":"Maximum value to enforce for new documents.","x-example":10,"format":"int32","x-nullable":true},"default":{"type":"integer","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":10,"format":"int32","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeFloat":{"description":"AttributeFloat","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"percentageCompleted"},"type":{"type":"string","description":"Attribute type.","x-example":"double"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"min":{"type":"number","description":"Minimum value to enforce for new documents.","x-example":1.5,"format":"double","x-nullable":true},"max":{"type":"number","description":"Maximum value to enforce for new documents.","x-example":10.5,"format":"double","x-nullable":true},"default":{"type":"number","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":2.5,"format":"double","x-nullable":true}},"required":["key","type","status","error","required"]},"attributeBoolean":{"description":"AttributeBoolean","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"isEnabled"},"type":{"type":"string","description":"Attribute type.","x-example":"boolean"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"default":{"type":"boolean","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":false,"x-nullable":true}},"required":["key","type","status","error","required"]},"attributeEmail":{"description":"AttributeEmail","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"userEmail"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"email"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"default@example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeEnum":{"description":"AttributeEnum","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"status"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"elements":{"type":"array","description":"Array of elements in enumerated type.","items":{"type":"string"},"x-example":"element"},"format":{"type":"string","description":"String format.","x-example":"enum"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"element","x-nullable":true}},"required":["key","type","status","error","required","elements","format"]},"attributeIp":{"description":"AttributeIP","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"ipAddress"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"ip"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"192.0.2.0","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeUrl":{"description":"AttributeURL","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"githubUrl"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"String format.","x-example":"url"},"default":{"type":"string","description":"Default value for attribute when not provided. Cannot be set when attribute is required.","x-example":"http:\/\/example.com","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeDatetime":{"description":"AttributeDatetime","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"birthDay"},"type":{"type":"string","description":"Attribute type.","x-example":"datetime"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"format":{"type":"string","description":"ISO 8601 format.","x-example":"datetime"},"default":{"type":"string","description":"Default value for attribute when not provided. Only null is optional","x-example":"2020-10-15T06:38:00.000+00:00","x-nullable":true}},"required":["key","type","status","error","required","format"]},"attributeRelationship":{"description":"AttributeRelationship","type":"object","properties":{"key":{"type":"string","description":"Attribute Key.","x-example":"fullName"},"type":{"type":"string","description":"Attribute type.","x-example":"string"},"status":{"type":"string","description":"Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an attribute.","x-example":"string"},"required":{"type":"boolean","description":"Is attribute required?","x-example":true},"array":{"type":"boolean","description":"Is attribute an array?","x-example":false,"x-nullable":true},"relatedCollection":{"type":"string","description":"The ID of the related collection.","x-example":"collection"},"relationType":{"type":"string","description":"The type of the relationship.","x-example":"oneToOne|oneToMany|manyToOne|manyToMany"},"twoWay":{"type":"boolean","description":"Is the relationship two-way?","x-example":false},"twoWayKey":{"type":"string","description":"The key of the two-way relationship.","x-example":"string"},"onDelete":{"type":"string","description":"How deleting the parent document will propagate to child documents.","x-example":"restrict|cascade|setNull"},"side":{"type":"string","description":"Whether this is the parent or child side of the relationship","x-example":"parent|child"}},"required":["key","type","status","error","required","relatedCollection","relationType","twoWay","twoWayKey","onDelete","side"]},"index":{"description":"Index","type":"object","properties":{"key":{"type":"string","description":"Index Key.","x-example":"index1"},"type":{"type":"string","description":"Index type.","x-example":"primary"},"status":{"type":"string","description":"Index status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`","x-example":"available"},"error":{"type":"string","description":"Error message. Displays error generated on failure of creating or deleting an index.","x-example":"string"},"attributes":{"type":"array","description":"Index attributes.","items":{"type":"string"},"x-example":[]},"orders":{"type":"array","description":"Index orders.","items":{"type":"string"},"x-example":[],"x-nullable":true}},"required":["key","type","status","error","attributes"]},"document":{"description":"Document","type":"object","properties":{"$id":{"type":"string","description":"Document ID.","x-example":"5e5ea5c16897e"},"$collectionId":{"type":"string","description":"Collection ID.","x-example":"5e5ea5c15117e"},"$databaseId":{"type":"string","description":"Database ID.","x-example":"5e5ea5c15117e"},"$createdAt":{"type":"string","description":"Document creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Document update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Document permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]}},"additionalProperties":true,"required":["$id","$collectionId","$databaseId","$createdAt","$updatedAt","$permissions"]},"log":{"description":"Log","type":"object","properties":{"event":{"type":"string","description":"Event name.","x-example":"account.sessions.create"},"userId":{"type":"string","description":"User ID.","x-example":"610fc2f985ee0"},"userEmail":{"type":"string","description":"User Email.","x-example":"john@appwrite.io"},"userName":{"type":"string","description":"User Name.","x-example":"John Doe"},"mode":{"type":"string","description":"API mode when event triggered.","x-example":"admin"},"ip":{"type":"string","description":"IP session in use when the session was created.","x-example":"127.0.0.1"},"time":{"type":"string","description":"Log creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["event","userId","userEmail","userName","mode","ip","time","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName"]},"user":{"description":"User","type":"object","properties":{"$id":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"User creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"User update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"User name.","x-example":"John Doe"},"password":{"type":"string","description":"Hashed user password.","x-example":"$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L\/4LdgrVRXxE","x-nullable":true},"hash":{"type":"string","description":"Password hashing algorithm.","x-example":"argon2","x-nullable":true},"hashOptions":{"type":"object","description":"Password hashing algorithm configuration.","x-example":{},"items":{"x-oneOf":[{"$ref":"#\/definitions\/algoArgon2"},{"$ref":"#\/definitions\/algoScrypt"},{"$ref":"#\/definitions\/algoScryptModified"},{"$ref":"#\/definitions\/algoBcrypt"},{"$ref":"#\/definitions\/algoPhpass"},{"$ref":"#\/definitions\/algoSha"},{"$ref":"#\/definitions\/algoMd5"}]},"x-nullable":true},"registration":{"type":"string","description":"User registration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"status":{"type":"boolean","description":"User status. Pass `true` for enabled and `false` for disabled.","x-example":true},"labels":{"type":"array","description":"Labels for the user.","items":{"type":"string"},"x-example":["vip"]},"passwordUpdate":{"type":"string","description":"Password update time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"email":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"phone":{"type":"string","description":"User phone number in E.164 format.","x-example":"+4930901820"},"emailVerification":{"type":"boolean","description":"Email verification status.","x-example":true},"phoneVerification":{"type":"boolean","description":"Phone verification status.","x-example":true},"prefs":{"type":"object","description":"User preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}},"accessedAt":{"type":"string","description":"Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","$updatedAt","name","registration","status","labels","passwordUpdate","email","phone","emailVerification","phoneVerification","prefs","accessedAt"]},"algoMd5":{"description":"AlgoMD5","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"md5"}},"required":["type"]},"algoSha":{"description":"AlgoSHA","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"sha"}},"required":["type"]},"algoPhpass":{"description":"AlgoPHPass","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"phpass"}},"required":["type"]},"algoBcrypt":{"description":"AlgoBcrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"bcrypt"}},"required":["type"]},"algoScrypt":{"description":"AlgoScrypt","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scrypt"},"costCpu":{"type":"integer","description":"CPU complexity of computed hash.","x-example":8,"format":"int32"},"costMemory":{"type":"integer","description":"Memory complexity of computed hash.","x-example":14,"format":"int32"},"costParallel":{"type":"integer","description":"Parallelization of computed hash.","x-example":1,"format":"int32"},"length":{"type":"integer","description":"Length used to compute hash.","x-example":64,"format":"int32"}},"required":["type","costCpu","costMemory","costParallel","length"]},"algoScryptModified":{"description":"AlgoScryptModified","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"scryptMod"},"salt":{"type":"string","description":"Salt used to compute hash.","x-example":"UxLMreBr6tYyjQ=="},"saltSeparator":{"type":"string","description":"Separator used to compute hash.","x-example":"Bw=="},"signerKey":{"type":"string","description":"Key used to compute hash.","x-example":"XyEKE9RcTDeLEsL\/RjwPDBv\/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ=="}},"required":["type","salt","saltSeparator","signerKey"]},"algoArgon2":{"description":"AlgoArgon2","type":"object","properties":{"type":{"type":"string","description":"Algo type.","x-example":"argon2"},"memoryCost":{"type":"integer","description":"Memory used to compute hash.","x-example":65536,"format":"int32"},"timeCost":{"type":"integer","description":"Amount of time consumed to compute hash","x-example":4,"format":"int32"},"threads":{"type":"integer","description":"Number of threads used to compute hash.","x-example":3,"format":"int32"}},"required":["type","memoryCost","timeCost","threads"]},"preferences":{"description":"Preferences","type":"object","additionalProperties":true},"session":{"description":"Session","type":"object","properties":{"$id":{"type":"string","description":"Session ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Session creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"expire":{"type":"string","description":"Session expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"provider":{"type":"string","description":"Session Provider.","x-example":"email"},"providerUid":{"type":"string","description":"Session Provider User ID.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Session Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Session Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"ip":{"type":"string","description":"IP in use when the session was created.","x-example":"127.0.0.1"},"osCode":{"type":"string","description":"Operating system code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/os.json).","x-example":"Mac"},"osName":{"type":"string","description":"Operating system name.","x-example":"Mac"},"osVersion":{"type":"string","description":"Operating system version.","x-example":"Mac"},"clientType":{"type":"string","description":"Client type.","x-example":"browser"},"clientCode":{"type":"string","description":"Client code name. View list of [available options](https:\/\/github.com\/appwrite\/appwrite\/blob\/master\/docs\/lists\/clients.json).","x-example":"CM"},"clientName":{"type":"string","description":"Client name.","x-example":"Chrome Mobile iOS"},"clientVersion":{"type":"string","description":"Client version.","x-example":"84.0"},"clientEngine":{"type":"string","description":"Client engine name.","x-example":"WebKit"},"clientEngineVersion":{"type":"string","description":"Client engine name.","x-example":"605.1.15"},"deviceName":{"type":"string","description":"Device name.","x-example":"smartphone"},"deviceBrand":{"type":"string","description":"Device brand name.","x-example":"Google"},"deviceModel":{"type":"string","description":"Device model name.","x-example":"Nexus 5"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"},"current":{"type":"boolean","description":"Returns true if this the current user session.","x-example":true}},"required":["$id","$createdAt","userId","expire","provider","providerUid","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken","ip","osCode","osName","osVersion","clientType","clientCode","clientName","clientVersion","clientEngine","clientEngineVersion","deviceName","deviceBrand","deviceModel","countryCode","countryName","current"]},"identity":{"description":"Identity","type":"object","properties":{"$id":{"type":"string","description":"Identity ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Identity creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Identity update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5bb8c16897e"},"provider":{"type":"string","description":"Identity Provider.","x-example":"email"},"providerUid":{"type":"string","description":"ID of the User in the Identity Provider.","x-example":"5e5bb8c16897e"},"providerEmail":{"type":"string","description":"Email of the User in the Identity Provider.","x-example":"user@example.com"},"providerAccessToken":{"type":"string","description":"Identity Provider Access Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"},"providerAccessTokenExpiry":{"type":"string","description":"The date of when the access token expires in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"providerRefreshToken":{"type":"string","description":"Identity Provider Refresh Token.","x-example":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"}},"required":["$id","$createdAt","$updatedAt","userId","provider","providerUid","providerEmail","providerAccessToken","providerAccessTokenExpiry","providerRefreshToken"]},"token":{"description":"Token","type":"object","properties":{"$id":{"type":"string","description":"Token ID.","x-example":"bb8ea5c16897e"},"$createdAt":{"type":"string","description":"Token creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c168bb8"},"secret":{"type":"string","description":"Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"expire":{"type":"string","description":"Token expiration date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"}},"required":["$id","$createdAt","userId","secret","expire"]},"locale":{"description":"Locale","type":"object","properties":{"ip":{"type":"string","description":"User IP address.","x-example":"127.0.0.1"},"countryCode":{"type":"string","description":"Country code in [ISO 3166-1](http:\/\/en.wikipedia.org\/wiki\/ISO_3166-1) two-character format","x-example":"US"},"country":{"type":"string","description":"Country name. This field support localization.","x-example":"United States"},"continentCode":{"type":"string","description":"Continent code. A two character continent code \"AF\" for Africa, \"AN\" for Antarctica, \"AS\" for Asia, \"EU\" for Europe, \"NA\" for North America, \"OC\" for Oceania, and \"SA\" for South America.","x-example":"NA"},"continent":{"type":"string","description":"Continent name. This field support localization.","x-example":"North America"},"eu":{"type":"boolean","description":"True if country is part of the European Union.","x-example":false},"currency":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format","x-example":"USD"}},"required":["ip","countryCode","country","continentCode","continent","eu","currency"]},"localeCode":{"description":"LocaleCode","type":"object","properties":{"code":{"type":"string","description":"Locale codes in [ISO 639-1](https:\/\/en.wikipedia.org\/wiki\/List_of_ISO_639-1_codes)","x-example":"en-us"},"name":{"type":"string","description":"Locale name","x-example":"US"}},"required":["code","name"]},"file":{"description":"File","type":"object","properties":{"$id":{"type":"string","description":"File ID.","x-example":"5e5ea5c16897e"},"bucketId":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"File creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"File update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"File permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"name":{"type":"string","description":"File name.","x-example":"Pink.png"},"signature":{"type":"string","description":"File MD5 signature.","x-example":"5d529fd02b544198ae075bd57c1762bb"},"mimeType":{"type":"string","description":"File mime type.","x-example":"image\/png"},"sizeOriginal":{"type":"integer","description":"File original size in bytes.","x-example":17890,"format":"int32"},"chunksTotal":{"type":"integer","description":"Total number of chunks available","x-example":17890,"format":"int32"},"chunksUploaded":{"type":"integer","description":"Total number of chunks uploaded","x-example":17890,"format":"int32"}},"required":["$id","bucketId","$createdAt","$updatedAt","$permissions","name","signature","mimeType","sizeOriginal","chunksTotal","chunksUploaded"]},"bucket":{"description":"Bucket","type":"object","properties":{"$id":{"type":"string","description":"Bucket ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Bucket creation time in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Bucket update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Bucket permissions. [Learn more about permissions](\/docs\/permissions).","items":{"type":"string"},"x-example":["read(\"any\")"]},"fileSecurity":{"type":"boolean","description":"Whether file-level security is enabled. [Learn more about permissions](\/docs\/permissions).","x-example":true},"name":{"type":"string","description":"Bucket name.","x-example":"Documents"},"enabled":{"type":"boolean","description":"Bucket enabled.","x-example":false},"maximumFileSize":{"type":"integer","description":"Maximum file size supported.","x-example":100,"format":"int32"},"allowedFileExtensions":{"type":"array","description":"Allowed file extensions.","items":{"type":"string"},"x-example":["jpg","png"]},"compression":{"type":"string","description":"Compression algorithm choosen for compression. Will be one of none, [gzip](https:\/\/en.wikipedia.org\/wiki\/Gzip), or [zstd](https:\/\/en.wikipedia.org\/wiki\/Zstd).","x-example":"gzip"},"encryption":{"type":"boolean","description":"Bucket is encrypted.","x-example":false},"antivirus":{"type":"boolean","description":"Virus scanning is enabled.","x-example":false}},"required":["$id","$createdAt","$updatedAt","$permissions","fileSecurity","name","enabled","maximumFileSize","allowedFileExtensions","compression","encryption","antivirus"]},"team":{"description":"Team","type":"object","properties":{"$id":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Team creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Team update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"name":{"type":"string","description":"Team name.","x-example":"VIP"},"total":{"type":"integer","description":"Total number of team members.","x-example":7,"format":"int32"},"prefs":{"type":"object","description":"Team preferences as a key-value object","x-example":{"theme":"pink","timezone":"UTC"},"items":{"type":"object","$ref":"#\/definitions\/preferences"}}},"required":["$id","$createdAt","$updatedAt","name","total","prefs"]},"membership":{"description":"Membership","type":"object","properties":{"$id":{"type":"string","description":"Membership ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Membership creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Membership update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"userId":{"type":"string","description":"User ID.","x-example":"5e5ea5c16897e"},"userName":{"type":"string","description":"User name.","x-example":"John Doe"},"userEmail":{"type":"string","description":"User email address.","x-example":"john@appwrite.io"},"teamId":{"type":"string","description":"Team ID.","x-example":"5e5ea5c16897e"},"teamName":{"type":"string","description":"Team name.","x-example":"VIP"},"invited":{"type":"string","description":"Date, the user has been invited to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"joined":{"type":"string","description":"Date, the user has accepted the invitation to join the team in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"confirm":{"type":"boolean","description":"User confirmation status, true if the user has joined the team or false otherwise.","x-example":false},"roles":{"type":"array","description":"User list of roles","items":{"type":"string"},"x-example":["owner"]}},"required":["$id","$createdAt","$updatedAt","userId","userName","userEmail","teamId","teamName","invited","joined","confirm","roles"]},"function":{"description":"Function","type":"object","properties":{"$id":{"type":"string","description":"Function ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Function creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Function update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"execute":{"type":"array","description":"Execution permissions.","items":{"type":"string"},"x-example":"users"},"name":{"type":"string","description":"Function name.","x-example":"My Function"},"enabled":{"type":"boolean","description":"Function enabled.","x-example":false},"live":{"type":"boolean","description":"Is the function deployed with the latest configuration? This is set to false if you've changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration.","x-example":false},"logging":{"type":"boolean","description":"Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.","x-example":false},"runtime":{"type":"string","description":"Function execution runtime.","x-example":"python-3.8"},"deployment":{"type":"string","description":"Function's active deployment ID.","x-example":"5e5ea5c16897e"},"vars":{"type":"array","description":"Function variables.","items":{"type":"object","$ref":"#\/definitions\/variable"},"x-example":[]},"events":{"type":"array","description":"Function trigger events.","items":{"type":"string"},"x-example":"account.create"},"schedule":{"type":"string","description":"Function execution schedult in CRON format.","x-example":"5 4 * * *"},"timeout":{"type":"integer","description":"Function execution timeout in seconds.","x-example":300,"format":"int32"},"entrypoint":{"type":"string","description":"The entrypoint file used to execute the deployment.","x-example":"index.js"},"commands":{"type":"string","description":"The build command used to build the deployment.","x-example":"npm install"},"version":{"type":"string","description":"Version of Open Runtimes used for the function.","x-example":"v2"},"installationId":{"type":"string","description":"Function VCS (Version Control System) installation id.","x-example":"6m40at4ejk5h2u9s1hboo"},"providerRepositoryId":{"type":"string","description":"VCS (Version Control System) Repository ID","x-example":"appwrite"},"providerBranch":{"type":"string","description":"VCS (Version Control System) branch name","x-example":"main"},"providerRootDirectory":{"type":"string","description":"Path to function in VCS (Version Control System) repository","x-example":"functions\/helloWorld"},"providerSilentMode":{"type":"boolean","description":"Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests","x-example":false}},"required":["$id","$createdAt","$updatedAt","execute","name","enabled","live","logging","runtime","deployment","vars","events","schedule","timeout","entrypoint","commands","version","installationId","providerRepositoryId","providerBranch","providerRootDirectory","providerSilentMode"]},"runtime":{"description":"Runtime","type":"object","properties":{"$id":{"type":"string","description":"Runtime ID.","x-example":"python-3.8"},"name":{"type":"string","description":"Runtime Name.","x-example":"Python"},"version":{"type":"string","description":"Runtime version.","x-example":"3.8"},"base":{"type":"string","description":"Base Docker image used to build the runtime.","x-example":"python:3.8-alpine"},"image":{"type":"string","description":"Image name of Docker Hub.","x-example":"appwrite\\\/runtime-for-python:3.8"},"logo":{"type":"string","description":"Name of the logo image.","x-example":"python.png"},"supports":{"type":"array","description":"List of supported architectures.","items":{"type":"string"},"x-example":"amd64"}},"required":["$id","name","version","base","image","logo","supports"]},"deployment":{"description":"Deployment","type":"object","properties":{"$id":{"type":"string","description":"Deployment ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Deployment creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Deployment update date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"type":{"type":"string","description":"Type of deployment.","x-example":"vcs"},"resourceId":{"type":"string","description":"Resource ID.","x-example":"5e5ea6g16897e"},"resourceType":{"type":"string","description":"Resource type.","x-example":"functions"},"entrypoint":{"type":"string","description":"The entrypoint file to use to execute the deployment code.","x-example":"index.js"},"size":{"type":"integer","description":"The code size in bytes.","x-example":128,"format":"int32"},"buildId":{"type":"string","description":"The current build ID.","x-example":"5e5ea5c16897e"},"activate":{"type":"boolean","description":"Whether the deployment should be automatically activated.","x-example":true},"status":{"type":"string","description":"The deployment status. Possible values are \"processing\", \"building\", \"waiting\", \"ready\", and \"failed\".","x-example":"ready"},"buildLogs":{"type":"string","description":"The build logs.","x-example":"Compiling source files..."},"buildTime":{"type":"integer","description":"The current build time in seconds.","x-example":128,"format":"int32"},"providerRepositoryName":{"type":"string","description":"The name of the vcs provider repository","x-example":"database"},"providerRepositoryOwner":{"type":"string","description":"The name of the vcs provider repository owner","x-example":"utopia"},"providerRepositoryUrl":{"type":"string","description":"The url of the vcs provider repository","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function"},"providerBranch":{"type":"string","description":"The branch of the vcs repository","x-example":"0.7.x"},"providerCommitHash":{"type":"string","description":"The commit hash of the vcs commit","x-example":"7c3f25d"},"providerCommitAuthorUrl":{"type":"string","description":"The url of vcs commit author","x-example":"https:\/\/github.com\/vermakhushboo"},"providerCommitAuthor":{"type":"string","description":"The name of vcs commit author","x-example":"Khushboo Verma"},"providerCommitMessage":{"type":"string","description":"The commit message","x-example":"Update index.js"},"providerCommitUrl":{"type":"string","description":"The url of the vcs commit","x-example":"https:\/\/github.com\/vermakhushboo\/g4-node-function\/commit\/60c0416257a9cbcdd96b2d370c38d8f8d150ccfb"},"providerBranchUrl":{"type":"string","description":"The branch of the vcs repository","x-example":"https:\/\/github.com\/vermakhushboo\/appwrite\/tree\/0.7.x"}},"required":["$id","$createdAt","$updatedAt","type","resourceId","resourceType","entrypoint","size","buildId","activate","status","buildLogs","buildTime","providerRepositoryName","providerRepositoryOwner","providerRepositoryUrl","providerBranch","providerCommitHash","providerCommitAuthorUrl","providerCommitAuthor","providerCommitMessage","providerCommitUrl","providerBranchUrl"]},"execution":{"description":"Execution","type":"object","properties":{"$id":{"type":"string","description":"Execution ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Execution creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Execution upate date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$permissions":{"type":"array","description":"Execution roles.","items":{"type":"string"},"x-example":["any"]},"functionId":{"type":"string","description":"Function ID.","x-example":"5e5ea6g16897e"},"trigger":{"type":"string","description":"The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.","x-example":"http"},"status":{"type":"string","description":"The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.","x-example":"processing"},"requestMethod":{"type":"string","description":"HTTP request method type.","x-example":"GET"},"requestPath":{"type":"string","description":"HTTP request path and query.","x-example":"\/articles?id=5"},"requestHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"responseStatusCode":{"type":"integer","description":"HTTP response status code.","x-example":200,"format":"int32"},"responseBody":{"type":"string","description":"HTTP response body. This will return empty unless execution is created as synchronous.","x-example":"Developers are awesome."},"responseHeaders":{"type":"array","description":"HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.","items":{"type":"object","$ref":"#\/definitions\/headers"},"x-example":[{"Content-Type":"application\/json"}]},"logs":{"type":"string","description":"Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"errors":{"type":"string","description":"Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.","x-example":""},"duration":{"type":"number","description":"Function execution duration in seconds.","x-example":0.4,"format":"double"}},"required":["$id","$createdAt","$updatedAt","$permissions","functionId","trigger","status","requestMethod","requestPath","requestHeaders","responseStatusCode","responseBody","responseHeaders","logs","errors","duration"]},"variable":{"description":"Variable","type":"object","properties":{"$id":{"type":"string","description":"Variable ID.","x-example":"5e5ea5c16897e"},"$createdAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"$updatedAt":{"type":"string","description":"Variable creation date in ISO 8601 format.","x-example":"2020-10-15T06:38:00.000+00:00"},"key":{"type":"string","description":"Variable key.","x-example":"API_KEY"},"value":{"type":"string","description":"Variable value.","x-example":"myPa$$word1"},"resourceType":{"type":"string","description":"Service to which the variable belongs. Possible values are \"project\", \"function\"","x-example":"function"},"resourceId":{"type":"string","description":"ID of resource to which the variable belongs. If resourceType is \"project\", it is empty. If resourceType is \"function\", it is ID of the function.","x-example":"myAwesomeFunction"}},"required":["$id","$createdAt","$updatedAt","key","value","resourceType","resourceId"]},"country":{"description":"Country","type":"object","properties":{"name":{"type":"string","description":"Country name.","x-example":"United States"},"code":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"}},"required":["name","code"]},"continent":{"description":"Continent","type":"object","properties":{"name":{"type":"string","description":"Continent name.","x-example":"Europe"},"code":{"type":"string","description":"Continent two letter code.","x-example":"EU"}},"required":["name","code"]},"language":{"description":"Language","type":"object","properties":{"name":{"type":"string","description":"Language name.","x-example":"Italian"},"code":{"type":"string","description":"Language two-character ISO 639-1 codes.","x-example":"it"},"nativeName":{"type":"string","description":"Language native name.","x-example":"Italiano"}},"required":["name","code","nativeName"]},"currency":{"description":"Currency","type":"object","properties":{"symbol":{"type":"string","description":"Currency symbol.","x-example":"$"},"name":{"type":"string","description":"Currency name.","x-example":"US dollar"},"symbolNative":{"type":"string","description":"Currency native symbol.","x-example":"$"},"decimalDigits":{"type":"integer","description":"Number of decimal digits.","x-example":2,"format":"int32"},"rounding":{"type":"number","description":"Currency digit rounding.","x-example":0,"format":"double"},"code":{"type":"string","description":"Currency code in [ISO 4217-1](http:\/\/en.wikipedia.org\/wiki\/ISO_4217) three-character format.","x-example":"USD"},"namePlural":{"type":"string","description":"Currency plural name","x-example":"US dollars"}},"required":["symbol","name","symbolNative","decimalDigits","rounding","code","namePlural"]},"phone":{"description":"Phone","type":"object","properties":{"code":{"type":"string","description":"Phone code.","x-example":"+1"},"countryCode":{"type":"string","description":"Country two-character ISO 3166-1 alpha code.","x-example":"US"},"countryName":{"type":"string","description":"Country name.","x-example":"United States"}},"required":["code","countryCode","countryName"]},"healthAntivirus":{"description":"Health Antivirus","type":"object","properties":{"version":{"type":"string","description":"Antivirus version.","x-example":"1.0.0"},"status":{"type":"string","description":"Antivirus status. Possible values can are: `disabled`, `offline`, `online`","x-example":"online"}},"required":["version","status"]},"healthQueue":{"description":"Health Queue","type":"object","properties":{"size":{"type":"integer","description":"Amount of actions in the queue.","x-example":8,"format":"int32"}},"required":["size"]},"healthStatus":{"description":"Health Status","type":"object","properties":{"name":{"type":"string","description":"Name of the service.","x-example":"database"},"ping":{"type":"integer","description":"Duration in milliseconds how long the health check took.","x-example":128,"format":"int32"},"status":{"type":"string","description":"Service status. Possible values can are: `pass`, `fail`","x-example":"pass"}},"required":["name","ping","status"]},"healthTime":{"description":"Health Time","type":"object","properties":{"remoteTime":{"type":"integer","description":"Current unix timestamp on trustful remote server.","x-example":1639490751,"format":"int32"},"localTime":{"type":"integer","description":"Current unix timestamp of local server where Appwrite runs.","x-example":1639490844,"format":"int32"},"diff":{"type":"integer","description":"Difference of unix remote and local timestamps in milliseconds.","x-example":93,"format":"int32"}},"required":["remoteTime","localTime","diff"]},"headers":{"description":"Headers","type":"object","properties":{"name":{"type":"string","description":"Header name.","x-example":"Content-Type"},"value":{"type":"string","description":"Header value.","x-example":"application\/json"}},"required":["name","value"]}},"externalDocs":{"description":"Full API docs, specs and tutorials","url":"https:\/\/appwrite.io\/docs"}} \ No newline at end of file diff --git a/app/config/variables.php b/app/config/variables.php index c04ba339e5..b39eb9c41d 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -61,6 +61,15 @@ return [ 'question' => 'Enter your Appwrite hostname', 'filter' => '' ], + [ + 'name' => '_APP_DOMAIN_FUNCTIONS', + 'description' => 'A domain to use for function preview URLs. Setting to empty turns off function preview URLs.', + 'introduction' => '', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ], [ 'name' => '_APP_DOMAIN_TARGET', 'description' => 'A DNS A record hostname to serve as a CNAME target for your Appwrite custom domains. You can use the same value as used for the Appwrite \'_APP_DOMAIN\' variable. The default value is \'localhost\'.', @@ -105,15 +114,6 @@ return [ 'question' => '', 'filter' => '' ], - [ - 'name' => '_APP_CONSOLE_ROOT_SESSION', - 'description' => 'Domain policy for the Appwrite console session cookie. By default, set to \'disabled\', meaning the session cookie will be set to the domain of the Appwrite console (e.g. cloud.appwrite.io). When set to \'enabled\', the session cookie will be set to the registerable domain of the Appwrite server (e.g. appwrite.io).', - 'introduction' => '', - 'default' => 'disabled', - 'required' => false, - 'question' => '', - 'filter' => '' - ], [ 'name' => '_APP_SYSTEM_EMAIL_NAME', 'description' => 'This is the sender name value that will appear on email messages sent to developers from the Appwrite console. The default value is: \'Appwrite\'. You can use url encoded strings for spaces and special chars.', @@ -152,7 +152,7 @@ return [ ], [ 'name' => '_APP_USAGE_STATS', - 'description' => 'This variable allows you to disable the collection and displaying of usage stats. This value is set to \'enabled\' by default, to disable the usage stats set the value to \'disabled\'. When disabled, it\'s recommended to turn off the Worker Usage container for better resource usage.', + 'description' => 'This variable allows you to disable the collection and displaying of usage stats. This value is set to \'enabled\' by default, to disable the usage stats set the value to \'disabled\'. When disabled, it\'s recommended to turn off the Worker Usage container to reduce resource usage.', 'introduction' => '0.7.0', 'default' => 'enabled', 'required' => false, @@ -161,7 +161,7 @@ return [ ], [ 'name' => '_APP_LOGGING_PROVIDER', - 'description' => 'This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, to enable the logger set the value to one of \'sentry\', \'raygun\', \'appSignal\', \'logOwl\'', + 'description' => 'This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, set the value to one of \'sentry\', \'raygun\', \'appSignal\', \'logOwl\' to enable the logger.', 'introduction' => '0.12.0', 'default' => '', 'required' => false, @@ -213,15 +213,6 @@ return [ 'question' => '', 'filter' => '' ], - [ - 'name' => '_APP_CONSOLE_INVITES', - 'description' => 'This option allows you to disable the invitation of new users to the Appwrite console. When enabled, console users are allowed to invite new users to a project. By default this option is enabled.', - 'introduction' => '1.2.0', - 'default' => 'enabled', - 'required' => false, - 'question' => '', - 'filter' => '' - ], ], ], [ @@ -324,33 +315,54 @@ return [ 'question' => '', 'filter' => 'password' ], + ], + ], + [ + 'category' => 'InfluxDB', + 'description' => 'Appwrite uses an InfluxDB server for managing time-series data and server stats. The InfluxDB env vars are used to allow Appwrite server to connect to the InfluxDB container.', + 'variables' => [ [ - 'name' => '_APP_CONNECTIONS_MAX', - 'description' => 'MariaDB server maximum connections.', - 'introduction' => 'TBD', - 'default' => 251, + 'name' => '_APP_INFLUXDB_HOST', + 'description' => 'InfluxDB server host name address. Default value is: \'influxdb\'.', + 'introduction' => '', + 'default' => 'influxdb', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_INFLUXDB_PORT', + 'description' => 'InfluxDB server TCP port. Default value is: \'8086\'.', + 'introduction' => '', + 'default' => '8086', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + ], + ], + [ + 'category' => 'StatsD', + 'description' => 'Appwrite uses a StatsD server for aggregating and sending stats data over a fast UDP connection. The StatsD env vars are used to allow Appwrite server to connect to the StatsD container.', + 'variables' => [ + [ + 'name' => '_APP_STATSD_HOST', + 'description' => 'StatsD server host name address. Default value is: \'telegraf\'.', + 'introduction' => '', + 'default' => 'telegraf', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_STATSD_PORT', + 'description' => 'StatsD server TCP port. Default value is: \'8125\'.', + 'introduction' => '', + 'default' => '8125', 'required' => false, 'question' => '', 'filter' => '' ], -// [ -// 'name' => '_APP_CONNECTIONS_DB_PROJECT', -// 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.', -// 'introduction' => 'TBD', -// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', -// 'required' => true, -// 'question' => '', -// 'filter' => '' -// ], -// [ -// 'name' => '_APP_CONNECTIONS_DB_CONSOLE', -// 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.', -// 'introduction' => 'TBD', -// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', -// 'required' => true, -// 'question' => '', -// 'filter' => '' -// ] ], ], [ @@ -477,17 +489,9 @@ return [ 'question' => '', 'filter' => '' ], - [ - 'name' => '_APP_CONNECTIONS_STORAGE', - 'description' => 'A DSN representing the storage device to connect to. The DSN takes the following format ://:@:/?region=. For example, for S3: \'s3://access_key:access_secret@host:port/bucket?region=us-east-1\'. To use the local filesystem, you can leave this variable empty. Available devices are local, s3, dospaces, linode, backblaze and wasabi.', - 'introduction' => '1.1.0', - 'default' => '', - 'required' => false, - 'question' => '', - ], [ 'name' => '_APP_STORAGE_DEVICE', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Select default storage device. The default value is \'local\'. List of supported adapters are \'local\', \'s3\', \'dospaces\', \'backblaze\', \'linode\' and \'wasabi\'.', 'introduction' => '0.13.0', 'default' => 'local', 'required' => false, @@ -495,7 +499,7 @@ return [ ], [ 'name' => '_APP_STORAGE_S3_ACCESS_KEY', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'AWS S3 storage access key. Required when the storage adapter is set to S3. You can get your access key from your AWS console', 'introduction' => '0.13.0', 'default' => '', 'required' => false, @@ -503,7 +507,7 @@ return [ ], [ 'name' => '_APP_STORAGE_S3_SECRET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'AWS S3 storage secret key. Required when the storage adapter is set to S3. You can get your secret key from your AWS console.', 'introduction' => '0.13.0', 'default' => '', 'required' => false, @@ -511,7 +515,7 @@ return [ ], [ 'name' => '_APP_STORAGE_S3_REGION', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'AWS S3 storage region. Required when storage adapter is set to S3. You can find your region info for your bucket from AWS console.', 'introduction' => '0.13.0', 'default' => 'us-east-1', 'required' => false, @@ -519,7 +523,7 @@ return [ ], [ 'name' => '_APP_STORAGE_S3_BUCKET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'AWS S3 storage bucket. Required when storage adapter is set to S3. You can create buckets in your AWS console.', 'introduction' => '0.13.0', 'default' => '', 'required' => false, @@ -527,7 +531,7 @@ return [ ], [ 'name' => '_APP_STORAGE_DO_SPACES_ACCESS_KEY', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'DigitalOcean spaces access key. Required when the storage adapter is set to DOSpaces. You can get your access key from your DigitalOcean console.', 'introduction' => '0.13.0', 'default' => '', 'required' => false, @@ -535,7 +539,7 @@ return [ ], [ 'name' => '_APP_STORAGE_DO_SPACES_SECRET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'DigitalOcean spaces secret key. Required when the storage adapter is set to DOSpaces. You can get your secret key from your DigitalOcean console.', 'introduction' => '0.13.0', 'default' => '', 'required' => false, @@ -543,7 +547,7 @@ return [ ], [ 'name' => '_APP_STORAGE_DO_SPACES_REGION', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'DigitalOcean spaces region. Required when storage adapter is set to DOSpaces. You can find your region info for your space from DigitalOcean console.', 'introduction' => '0.13.0', 'default' => 'us-east-1', 'required' => false, @@ -551,7 +555,7 @@ return [ ], [ 'name' => '_APP_STORAGE_DO_SPACES_BUCKET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'DigitalOcean spaces bucket. Required when storage adapter is set to DOSpaces. You can create spaces in your DigitalOcean console.', 'introduction' => '0.13.0', 'default' => '', 'required' => false, @@ -559,7 +563,7 @@ return [ ], [ 'name' => '_APP_STORAGE_BACKBLAZE_ACCESS_KEY', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Backblaze access key. Required when the storage adapter is set to Backblaze. Your Backblaze keyID will be your access key. You can get your keyID from your Backblaze console.', 'introduction' => '0.14.2', 'default' => '', 'required' => false, @@ -567,7 +571,7 @@ return [ ], [ 'name' => '_APP_STORAGE_BACKBLAZE_SECRET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Backblaze secret key. Required when the storage adapter is set to Backblaze. Your Backblaze applicationKey will be your secret key. You can get your applicationKey from your Backblaze console.', 'introduction' => '0.14.2', 'default' => '', 'required' => false, @@ -575,7 +579,7 @@ return [ ], [ 'name' => '_APP_STORAGE_BACKBLAZE_REGION', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Backblaze region. Required when storage adapter is set to Backblaze. You can find your region info from your Backblaze console.', 'introduction' => '0.14.2', 'default' => 'us-west-004', 'required' => false, @@ -583,7 +587,7 @@ return [ ], [ 'name' => '_APP_STORAGE_BACKBLAZE_BUCKET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Backblaze bucket. Required when storage adapter is set to Backblaze. You can create your bucket from your Backblaze console.', 'introduction' => '0.14.2', 'default' => '', 'required' => false, @@ -591,7 +595,7 @@ return [ ], [ 'name' => '_APP_STORAGE_LINODE_ACCESS_KEY', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Linode object storage access key. Required when the storage adapter is set to Linode. You can get your access key from your Linode console.', 'introduction' => '0.14.2', 'default' => '', 'required' => false, @@ -599,7 +603,7 @@ return [ ], [ 'name' => '_APP_STORAGE_LINODE_SECRET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Linode object storage secret key. Required when the storage adapter is set to Linode. You can get your secret key from your Linode console.', 'introduction' => '0.14.2', 'default' => '', 'required' => false, @@ -607,7 +611,7 @@ return [ ], [ 'name' => '_APP_STORAGE_LINODE_REGION', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Linode object storage region. Required when storage adapter is set to Linode. You can find your region info from your Linode console.', 'introduction' => '0.14.2', 'default' => 'eu-central-1', 'required' => false, @@ -615,7 +619,7 @@ return [ ], [ 'name' => '_APP_STORAGE_LINODE_BUCKET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Linode object storage bucket. Required when storage adapter is set to Linode. You can create buckets in your Linode console.', 'introduction' => '0.14.2', 'default' => '', 'required' => false, @@ -623,7 +627,7 @@ return [ ], [ 'name' => '_APP_STORAGE_WASABI_ACCESS_KEY', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Wasabi access key. Required when the storage adapter is set to Wasabi. You can get your access key from your Wasabi console.', 'introduction' => '0.14.2', 'default' => '', 'required' => false, @@ -631,7 +635,7 @@ return [ ], [ 'name' => '_APP_STORAGE_WASABI_SECRET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Wasabi secret key. Required when the storage adapter is set to Wasabi. You can get your secret key from your Wasabi console.', 'introduction' => '0.14.2', 'default' => '', 'required' => false, @@ -639,7 +643,7 @@ return [ ], [ 'name' => '_APP_STORAGE_WASABI_REGION', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Wasabi region. Required when storage adapter is set to Wasabi. You can find your region info from your Wasabi console.', 'introduction' => '0.14.2', 'default' => 'eu-central-1', 'required' => false, @@ -647,7 +651,7 @@ return [ ], [ 'name' => '_APP_STORAGE_WASABI_BUCKET', - 'description' => 'Deprecated since 1.2.0. Use _APP_CONNECTIONS_STORAGE instead.', + 'description' => 'Wasabi bucket. Required when storage adapter is set to Wasabi. You can create buckets in your Wasabi console.', 'introduction' => '0.14.2', 'default' => '', 'required' => false, @@ -814,7 +818,7 @@ return [ ], [ 'name' => '_APP_FUNCTIONS_RUNTIMES_NETWORK', - 'description' => 'The docker network used for communication between the executor and runtimes. Change this if you have altered the default network names.', + 'description' => 'The docker network used for communication between the executor and runtimes.', 'introduction' => '1.2.0', 'default' => 'runtimes', 'required' => false, @@ -850,6 +854,66 @@ return [ ], ], ], + [ + 'category' => 'VCS (Version Control System)', + 'description' => '', + 'variables' => [ + [ + 'name' => '_APP_VCS_GITHUB_APP_NAME', + 'description' => 'Name of your GitHub app. This value should be set to your GitHub application\'s URL.', + 'introduction' => '1.4.0', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_VCS_GITHUB_PRIVATE_KEY', + 'description' => 'GitHub app RSA private key. You can generate private keys from GitHub application settings.', + 'introduction' => '1.4.0', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_VCS_GITHUB_APP_ID', + 'description' => 'GitHub application ID. You can find it in your GitHub application details.', + 'introduction' => '1.4.0', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_VCS_GITHUB_CLIENT_ID', + 'description' => 'GitHub client ID. You can find it in your GitHub application details.', + 'introduction' => '1.4.0', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_VCS_GITHUB_CLIENT_SECRET', + 'description' => 'GitHub client secret. You can generate secrets in your GitHub application settings.', + 'introduction' => '1.4.0', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_VCS_GITHUB_WEBHOOK_SECRET', + 'description' => 'GitHub webhook secret. You can configure it in your GitHub application settings under webhook section.', + 'introduction' => '1.4.0', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + ], + ], [ 'category' => 'Maintenance', 'description' => '', @@ -952,4 +1016,43 @@ return [ ], ], ], + [ + 'category' => 'Migrations', + 'description' => '', + 'variables' => [ + [ + 'name' => '_APP_MIGRATIONS_FIREBASE_CLIENT_ID', + 'description' => 'Google OAuth client ID. You can find it in your GCP application settings.', + 'introduction' => '1.4.0', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', + 'description' => 'Google OAuth client secret. You can generate secrets in your GCP application settings.', + 'introduction' => '1.4.0', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ] + ] + ], + [ + 'category' => 'Assistant', + 'description' => '', + 'variables' => [ + [ + 'name' => '_APP_ASSISTANT_OPENAI_API_KEY', + 'description' => 'OpenAI API key. You can find it in your OpenAI application settings.', + 'introduction' => '1.4.0', + 'default' => '', + 'required' => false, + 'question' => '', + 'filter' => '' + ] + ] + ] ]; diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 9fc4c46931..c6df38c3ca 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -17,6 +17,7 @@ use Appwrite\OpenSSL\OpenSSL; use Appwrite\Template\Template; use Appwrite\URL\URL as URLParser; use Appwrite\Utopia\Database\Validator\CustomId; +use Appwrite\Utopia\Database\Validator\Queries\Identities; use Utopia\Database\Validator\Queries; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; @@ -48,101 +49,6 @@ use Appwrite\Auth\Validator\PersonalData; $oauthDefaultSuccess = '/auth/oauth2/success'; $oauthDefaultFailure = '/auth/oauth2/failure'; -App::post('/v1/account/invite') - ->desc('Create account using an invite code') - ->groups(['api', 'account', 'auth']) - ->label('event', 'users.[userId].create') - ->label('scope', 'public') - ->label('auth.type', 'emailPassword') - ->label('audits.event', 'user.create') - ->label('audits.resource', 'user/{response.$id}') - ->label('audits.userId', '{response.$id}') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'account') - ->label('sdk.method', 'createWithInviteCode') - ->label('sdk.description', '/docs/references/account/create.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ACCOUNT) - ->label('abuse-limit', 10) - ->param('userId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string `ID.unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('email', '', new Email(), 'User email.') - ->param('password', '', new Password(), 'User password. Must be at least 8 chars.') - ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) - ->param('code', '', new Text(128), 'An invite code to restrict user signups on the Appwrite console. Users with an invite code will be able to create accounts irrespective of email and IP whitelists.', true) - ->inject('request') - ->inject('response') - ->inject('project') - ->inject('dbForProject') - ->inject('events') - ->action(function (string $userId, string $email, string $password, string $name, string $code, Request $request, Response $response, Document $project, Database $dbForProject, Event $events) { - - if ($project->getId() !== 'console') { - throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN); - } - - $email = \strtolower($email); - - $whitelistCodes = (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_CODES', null)) : []; - - if (empty($whitelistCodes)) { - throw new Exception(Exception::GENERAL_CODES_DISABLED); - } - - if (!empty($whitelistCodes) && !\in_array($code, $whitelistCodes)) { - throw new Exception(Exception::USER_INVALID_CODE); - } - - $limit = $project->getAttribute('auths', [])['limit'] ?? 0; - - if ($limit !== 0) { - $total = $dbForProject->count('users', max: APP_LIMIT_USERS); - - if ($total >= $limit) { - throw new Exception(Exception::USER_COUNT_EXCEEDED); - } - } - - try { - $userId = $userId == 'unique()' ? ID::unique() : $userId; - $user = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([ - '$id' => $userId, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($userId)), - Permission::delete(Role::user($userId)), - ], - 'email' => $email, - 'emailVerification' => false, - 'status' => true, - 'password' => Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS), - 'hash' => Auth::DEFAULT_ALGO, - 'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS, - 'passwordUpdate' => DateTime::now(), - 'registration' => DateTime::now(), - 'reset' => false, - 'name' => $name, - 'prefs' => new \stdClass(), - 'sessions' => null, - 'tokens' => null, - 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]) - ]))); - } catch (Duplicate $th) { - throw new Exception(Exception::USER_ALREADY_EXISTS); - } - - Authorization::unsetRole(Role::guests()->toString()); - Authorization::setRole(Role::user($user->getId())->toString()); - Authorization::setRole(Role::users()->toString()); - - $events->setParam('userId', $user->getId()); - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($user, Response::MODEL_ACCOUNT); - }); - App::post('/v1/account') ->desc('Create Account') ->groups(['api', 'account', 'auth']) @@ -152,6 +58,7 @@ App::post('/v1/account') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'create') @@ -195,6 +102,14 @@ App::post('/v1/account') } } + // Makes sure this email is not already used in another identity + $identityWithMatchingEmail = $dbForProject->findOne('identities', [ + Query::equal('providerEmail', [$email]), + ]); + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } + if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) { $personalDataValidator = new PersonalData($userId, $email, $name, null); if (!$personalDataValidator->isValid($password)) { @@ -229,10 +144,10 @@ App::post('/v1/account') 'tokens' => null, 'memberships' => null, 'search' => implode(' ', [$userId, $email, $name]), - 'accessedAt' => DateTime::now(), // Add this here to make sure it's returned in the response + 'accessedAt' => DateTime::now(), ]); Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); - } catch (Duplicate $th) { + } catch (Duplicate) { throw new Exception(Exception::USER_ALREADY_EXISTS); } @@ -257,6 +172,8 @@ App::post('/v1/account/sessions/email') ->label('audits.event', 'session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') + ->label('usage.metric', 'sessions.{scope}.requests.create') + ->label('usage.params', ['provider:email']) ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createEmailSession') @@ -381,8 +298,8 @@ App::get('/v1/account/sessions/oauth2/:provider') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('providers'), fn($node) => (!$node['mock'])))) . '.') - ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. 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']) - ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. 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']) + ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s 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']) + ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s 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']) ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) ->inject('request') ->inject('response') @@ -440,7 +357,7 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') - ->param('code', '', new Text(2048, 0), 'OAuth2 code.', true) + ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) ->param('state', '', new Text(2048), 'Login state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) ->param('error_description', '', new Text(2048, 0), 'Human-readable text providing additional information about the error returned from the OAuth2 provider.', true) @@ -473,7 +390,7 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') - ->param('code', '', new Text(2048, 0), 'OAuth2 code.', true) + ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) ->param('state', '', new Text(2048), 'Login state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) ->param('error_description', '', new Text(2048, 0), 'Human-readable text providing additional information about the error returned from the OAuth2 provider.', true) @@ -509,8 +426,10 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') ->label('docs', false) + ->label('usage.metric', 'sessions.{scope}.requests.create') + ->label('usage.params', ['provider:{request.provider}']) ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.') - ->param('code', '', new Text(2048, 0), 'OAuth2 code.', true) + ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) ->param('state', '', new Text(2048), 'OAuth2 state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) ->param('error_description', '', new Text(2048, 0), 'Human-readable text providing additional information about the error returned from the OAuth2 provider.', true) @@ -622,6 +541,22 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $failureRedirect(Exception::USER_MISSING_ID); } + $name = $oauth2->getUserName($accessToken); + $email = $oauth2->getUserEmail($accessToken); + + // Check if this identity is connected to a different user + if (!$user->isEmpty()) { + $userId = $user->getId(); + + $identitiesWithMatchingEmail = $dbForProject->find('identities', [ + Query::equal('providerEmail', [$email]), + Query::notEqual('userId', $userId), + ]); + if (!empty($identitiesWithMatchingEmail)) { + throw new Exception(Exception::USER_ALREADY_EXISTS); + } + } + $sessions = $user->getAttribute('sessions', []); $authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $current = Auth::sessionVerify($sessions, Auth::$secret, $authDuration); @@ -645,9 +580,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } if ($user === false || $user->isEmpty()) { // No user logged in or with OAuth2 provider ID, create new one or connect with account with same email - $name = $oauth2->getUserName($accessToken); - $email = $oauth2->getUserEmail($accessToken); - if (empty($email)) { throw new Exception(Exception::USER_UNAUTHORIZED, 'OAuth provider failed to return email.'); } @@ -664,7 +596,19 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $user->setAttributes($userWithEmail->getArrayCopy()); } - if ($user === false || $user->isEmpty()) { // Last option -> create the user, generate random password + // If user is not found, check if there is an identity with the same provider user ID + if ($user === false || $user->isEmpty()) { + $identity = $dbForProject->findOne('identities', [ + Query::equal('provider', [$provider]), + Query::equal('providerUid', [$oauth2ID]), + ]); + + if ($identity !== false && !$identity->isEmpty()) { + $user = $dbForProject->getDocument('users', $identity->getAttribute('userId')); + } + } + + if ($user === false || $user->isEmpty()) { // Last option -> create the user $limit = $project->getAttribute('auths', [])['limit'] ?? 0; if ($limit !== 0) { @@ -675,11 +619,16 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } } - $passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0; + // Makes sure this email is not already used in another identity + $identityWithMatchingEmail = $dbForProject->findOne('identities', [ + Query::equal('providerEmail', [$email]), + ]); + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } try { $userId = ID::unique(); - $password = Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); $user->setAttributes([ '$id' => $userId, '$permissions' => [ @@ -690,8 +639,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'email' => $email, 'emailVerification' => true, 'status' => true, // Email should already be authenticated by OAuth2 provider - 'passwordHistory' => $passwordHistory > 0 ? [$password] : null, - 'password' => $password, + 'password' => null, 'hash' => Auth::DEFAULT_ALGO, 'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS, 'passwordUpdate' => null, @@ -702,19 +650,64 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]) + 'search' => implode(' ', [$userId, $email, $name]), + 'accessedAt' => DateTime::now(), ]); Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); - } catch (Duplicate $th) { + } catch (Duplicate) { $failureRedirect(Exception::USER_ALREADY_EXISTS); } } } + Authorization::setRole(Role::user($user->getId())->toString()); + Authorization::setRole(Role::users()->toString()); + if (false === $user->getAttribute('status')) { // Account is blocked $failureRedirect(Exception::USER_BLOCKED); // User is in status blocked } + $identity = $dbForProject->findOne('identities', [ + Query::equal('userInternalId', [$user->getInternalId()]), + Query::equal('provider', [$provider]), + Query::equal('providerUid', [$oauth2ID]), + ]); + if ($identity === false || $identity->isEmpty()) { + // Before creating the identity, check if the email is already associated with another user + $userId = $user->getId(); + + $identitiesWithMatchingEmail = $dbForProject->find('identities', [ + Query::equal('providerEmail', [$email]), + Query::notEqual('userId', $user->getId()), + ]); + if (!empty($identitiesWithMatchingEmail)) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } + + $dbForProject->createDocument('identities', new Document([ + '$id' => ID::unique(), + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($userId)), + Permission::delete(Role::user($userId)), + ], + 'userInternalId' => $user->getInternalId(), + 'userId' => $userId, + 'provider' => $provider, + 'providerUid' => $oauth2ID, + 'providerEmail' => $email, + 'providerAccessToken' => $accessToken, + 'providerRefreshToken' => $refreshToken, + 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry), + ])); + } else { + $identity + ->setAttribute('providerAccessToken', $accessToken) + ->setAttribute('providerRefreshToken', $refreshToken) + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry)); + $dbForProject->updateDocument('identities', $identity->getId(), $identity); + } + // Create session token, verify user account and update OAuth2 ID and Access Token $duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $detector = new Detector($request->getUserAgent('UNKNOWN')); @@ -794,6 +787,88 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ; }); +App::get('/v1/account/identities') + ->desc('List Identities') + ->groups(['api', 'account']) + ->label('scope', 'account') + ->label('usage.metric', 'users.{scope}.requests.read') + ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'listIdentities') + ->label('sdk.description', '/docs/references/account/list-identities.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_IDENTITY_LIST) + ->label('sdk.offline.model', '/account/identities') + ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Identities::ALLOWED_ATTRIBUTES), true) + ->inject('response') + ->inject('user') + ->inject('dbForProject') + ->action(function (array $queries, Response $response, Document $user, Database $dbForProject) { + + $queries = Query::parseQueries($queries); + + $queries[] = Query::equal('userInternalId', [$user->getInternalId()]); + + // Get cursor document if there was a cursor query + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); + $cursor = reset($cursor); + if ($cursor) { + /** @var Query $cursor */ + $identityId = $cursor->getValue(); + $cursorDocument = $dbForProject->getDocument('identities', $identityId); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Identity '{$identityId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + + $filterQueries = Query::groupByType($queries)['filters']; + + $results = $dbForProject->find('identities', $queries); + $total = $dbForProject->count('identities', $filterQueries, APP_LIMIT_COUNT); + + $response->dynamic(new Document([ + 'identities' => $results, + 'total' => $total, + ]), Response::MODEL_IDENTITY_LIST); + }); + +App::delete('/v1/account/identities/:identityId') + ->desc('Delete Identity') + ->groups(['api', 'account']) + ->label('scope', 'account') + ->label('event', 'users.[userId].identities.[identityId].delete') + ->label('audits.event', 'identity.delete') + ->label('audits.resource', 'identity/{request.$identityId}') + ->label('audits.userId', '{user.$id}') + ->label('usage.metric', 'identities.{scope}.requests.delete') + ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'deleteIdentity') + ->label('sdk.description', '/docs/references/account/delete-identity.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('identityId', '', new UID(), 'Identity ID.') + ->inject('response') + ->inject('dbForProject') + ->action(function (string $identityId, Response $response, Database $dbForProject) { + + $identity = $dbForProject->getDocument('identities', $identityId); + + if ($identity->isEmpty()) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + $dbForProject->deleteDocument('identities', $identityId); + + return $response->noContent(); + }); + App::post('/v1/account/sessions/magic-url') ->desc('Create Magic URL session') ->groups(['api', 'account']) @@ -846,6 +921,14 @@ App::post('/v1/account/sessions/magic-url') } } + // Makes sure this email is not already used in another identity + $identityWithMatchingEmail = $dbForProject->findOne('identities', [ + Query::equal('providerEmail', [$email]), + ]); + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } + $userId = $userId === 'unique()' ? ID::unique() : $userId; $user->setAttributes([ @@ -868,7 +951,8 @@ App::post('/v1/account/sessions/magic-url') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email]) + 'search' => implode(' ', [$userId, $email]), + 'accessedAt' => DateTime::now(), ]); Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); @@ -907,42 +991,84 @@ App::post('/v1/account/sessions/magic-url') $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $loginSecret, 'expire' => $expire, 'project' => $project->getId()]); $url = Template::unParseURL($url); - $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $project->getAttribute('name')); - $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $body = $locale->getText("emails.magicSession.body"); $subject = $locale->getText("emails.magicSession.subject"); - - $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; $customTemplate = $project->getAttribute('templates', [])['email.magicSession-' . $locale->default] ?? []; - if ($smtpEnabled && !empty($customTemplate)) { - $body = $customTemplate['message'] ?? $body; - $subject = $customTemplate['subject'] ?? $subject; - $from = $customTemplate['senderName'] ?? $from; + + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); + $message->setParam('{{body}}', $body); + $body = $message->render(); + + $smtp = $project->getAttribute('smtp', []); + $smtpEnabled = $smtp['enabled'] ?? false; + + $senderEmail = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); + $senderName = App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'); + $replyTo = ""; + + if ($smtpEnabled) { + if (!empty($smtp['senderEmail'])) { + $senderEmail = $smtp['senderEmail']; + } + if (!empty($smtp['senderName'])) { + $senderName = $smtp['senderName']; + } + if (!empty($smtp['replyTo'])) { + $replyTo = $smtp['replyTo']; + } + + $mails + ->setSmtpHost($smtp['host'] ?? '') + ->setSmtpPort($smtp['port'] ?? '') + ->setSmtpUsername($smtp['username'] ?? '') + ->setSmtpPassword($smtp['password'] ?? '') + ->setSmtpSecure($smtp['secure'] ?? ''); + + if (!empty($customTemplate)) { + if (!empty($customTemplate['senderEmail'])) { + $senderEmail = $customTemplate['senderEmail']; + } + if (!empty($customTemplate['senderName'])) { + $senderName = $customTemplate['senderName']; + } + if (!empty($customTemplate['replyTo'])) { + $replyTo = $customTemplate['replyTo']; + } + + $body = $customTemplate['message'] ?? ''; + $subject = $customTemplate['subject'] ?? $subject; + } + + $mails + ->setSmtpReplyTo($replyTo) + ->setSmtpSenderEmail($senderEmail) + ->setSmtpSenderName($senderName); } - $body - ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.magicSession.hello")) - ->setParam('{{name}}', '') - ->setParam('{{body}}', $locale->getText("emails.magicSession.body")) - ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText("emails.magicSession.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.magicSession.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.magicSession.signature")) - ->setParam('{{project}}', $project->getAttribute('name')) - ->setParam('{{direction}}', $locale->getText('settings.direction')) - ->setParam('{{bg-body}}', '#f7f7f7') - ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{text-content}}', '#000000'); - - $body = $body->render(); + $emailVariables = [ + 'subject' => $subject, + 'hello' => $locale->getText("emails.magicSession.hello"), + 'body' => $body, + 'footer' => $locale->getText("emails.magicSession.footer"), + 'thanks' => $locale->getText("emails.magicSession.thanks"), + 'signature' => $locale->getText("emails.magicSession.signature"), + 'direction' => $locale->getText('settings.direction'), + 'bg-body' => '#f7f7f7', + 'bg-content' => '#ffffff', + 'text-content' => '#000000', + /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ + 'user' => '', + 'team' => '', + 'project' => $project->getAttribute('name'), + 'redirect' => $url + ]; $mails ->setSubject($subject) ->setBody($body) - ->setFrom($from) - ->setRecipient($user->getAttribute('email')) - ->trigger() - ; + ->setVariables($emailVariables) + ->setRecipient($email) + ->trigger(); $events->setPayload( $response->output( @@ -968,6 +1094,8 @@ App::put('/v1/account/sessions/magic-url') ->label('audits.event', 'session.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') + ->label('usage.metric', 'sessions.{scope}.requests.create') + ->label('usage.params', ['provider:magic-url']) ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateMagicURLSession') @@ -1057,8 +1185,7 @@ App::put('/v1/account/sessions/magic-url') $events ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()) - ; + ->setParam('sessionId', $session->getId()); if (!Config::getParam('domainVerification')) { $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); @@ -1069,16 +1196,14 @@ App::put('/v1/account/sessions/magic-url') $response ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ->setStatusCode(Response::STATUS_CODE_CREATED) - ; + ->setStatusCode(Response::STATUS_CODE_CREATED); $countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) ->setAttribute('countryName', $countryName) - ->setAttribute('expire', $expire) - ; + ->setAttribute('expire', $expire); $response->dynamic($session, Response::MODEL_SESSION); }); @@ -1155,7 +1280,8 @@ App::post('/v1/account/sessions/phone') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $phone]) + 'search' => implode(' ', [$userId, $phone]), + 'accessedAt' => DateTime::now(), ]); Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); @@ -1342,6 +1468,8 @@ App::post('/v1/account/sessions/anonymous') ->label('audits.event', 'session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') + ->label('usage.metric', 'sessions.{scope}.requests.create') + ->label('usage.params', ['provider:anonymous']) ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createAnonymousSession') @@ -1404,6 +1532,7 @@ App::post('/v1/account/sessions/anonymous') 'tokens' => null, 'memberships' => null, 'search' => $userId, + 'accessedAt' => DateTime::now(), ]); Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); @@ -1517,6 +1646,7 @@ App::get('/v1/account') ->desc('Get Account') ->groups(['api', 'account']) ->label('scope', 'account') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'get') @@ -1537,6 +1667,7 @@ App::get('/v1/account/prefs') ->desc('Get Account Preferences') ->groups(['api', 'account']) ->label('scope', 'account') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'getPrefs') @@ -1559,6 +1690,7 @@ App::get('/v1/account/sessions') ->desc('List Sessions') ->groups(['api', 'account']) ->label('scope', 'account') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'listSessions') @@ -1597,6 +1729,7 @@ App::get('/v1/account/logs') ->desc('List Logs') ->groups(['api', 'account']) ->label('scope', 'account') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'listLogs') @@ -1657,6 +1790,7 @@ App::get('/v1/account/sessions/:sessionId') ->desc('Get Session') ->groups(['api', 'account']) ->label('scope', 'account') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'getSession') @@ -1704,6 +1838,7 @@ App::patch('/v1/account/name') ->label('scope', 'account') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateName') @@ -1738,6 +1873,7 @@ App::patch('/v1/account/password') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePassword') @@ -1803,6 +1939,7 @@ App::patch('/v1/account/email') ->label('scope', 'account') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateEmail') @@ -1832,6 +1969,15 @@ App::patch('/v1/account/email') $email = \strtolower($email); + // Makes sure this email is not already used in another identity + $identityWithMatchingEmail = $dbForProject->findOne('identities', [ + Query::equal('providerEmail', [$email]), + Query::notEqual('userId', $user->getId()), + ]); + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } + $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) // After this user needs to confirm mail again @@ -1863,6 +2009,7 @@ App::patch('/v1/account/phone') ->label('scope', 'account') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhone') @@ -1921,6 +2068,7 @@ App::patch('/v1/account/prefs') ->label('scope', 'account') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePrefs') @@ -1954,6 +2102,7 @@ App::patch('/v1/account/status') ->label('scope', 'account') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateStatus') @@ -1997,6 +2146,7 @@ App::delete('/v1/account/sessions/:sessionId') ->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('audits.event', 'session.delete') ->label('audits.resource', 'user/{user.$id}') + ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'deleteSession') @@ -2073,6 +2223,7 @@ App::patch('/v1/account/sessions/:sessionId') ->label('audits.event', 'session.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') + ->label('usage.metric', 'sessions.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateSession') @@ -2157,6 +2308,7 @@ App::delete('/v1/account/sessions') ->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('audits.event', 'session.delete') ->label('audits.resource', 'user/{user.$id}') + ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'deleteSessions') @@ -2218,6 +2370,7 @@ App::post('/v1/account/recovery') ->label('audits.event', 'recovery.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createRecovery') @@ -2293,44 +2446,86 @@ App::post('/v1/account/recovery') $url = Template::unParseURL($url); $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); - $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); - $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $body = $locale->getText("emails.recovery.body"); $subject = $locale->getText("emails.recovery.subject"); - - $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; $customTemplate = $project->getAttribute('templates', [])['email.recovery-' . $locale->default] ?? []; - if ($smtpEnabled && !empty($customTemplate)) { - $body = $customTemplate['message'] ?? $body; - $subject = $customTemplate['subject'] ?? $subject; - $from = $customTemplate['senderName'] ?? $from; + + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); + $message->setParam('{{body}}', $body); + $body = $message->render(); + + $smtp = $project->getAttribute('smtp', []); + $smtpEnabled = $smtp['enabled'] ?? false; + + $senderEmail = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); + $senderName = App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'); + $replyTo = ""; + + if ($smtpEnabled) { + if (!empty($smtp['senderEmail'])) { + $senderEmail = $smtp['senderEmail']; + } + if (!empty($smtp['senderName'])) { + $senderName = $smtp['senderName']; + } + if (!empty($smtp['replyTo'])) { + $replyTo = $smtp['replyTo']; + } + + $mails + ->setSmtpHost($smtp['host'] ?? '') + ->setSmtpPort($smtp['port'] ?? '') + ->setSmtpUsername($smtp['username'] ?? '') + ->setSmtpPassword($smtp['password'] ?? '') + ->setSmtpSecure($smtp['secure'] ?? ''); + + if (!empty($customTemplate)) { + if (!empty($customTemplate['senderEmail'])) { + $senderEmail = $customTemplate['senderEmail']; + } + if (!empty($customTemplate['senderName'])) { + $senderName = $customTemplate['senderName']; + } + if (!empty($customTemplate['replyTo'])) { + $replyTo = $customTemplate['replyTo']; + } + + $body = $customTemplate['message'] ?? ''; + $subject = $customTemplate['subject'] ?? $subject; + } + + $mails + ->setSmtpReplyTo($replyTo) + ->setSmtpSenderEmail($senderEmail) + ->setSmtpSenderName($senderName); } - $body - ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.recovery.hello")) - ->setParam('{{name}}', $profile->getAttribute('name')) - ->setParam('{{body}}', $locale->getText("emails.recovery.body")) - ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText("emails.recovery.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.recovery.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.recovery.signature")) - ->setParam('{{project}}', $projectName) - ->setParam('{{direction}}', $locale->getText('settings.direction')) - ->setParam('{{bg-body}}', '#f7f7f7') - ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{text-content}}', '#000000'); - - $body = $body->render(); + $emailVariables = [ + 'subject' => $subject, + 'hello' => $locale->getText("emails.recovery.hello"), + 'body' => $body, + 'footer' => $locale->getText("emails.recovery.footer"), + 'thanks' => $locale->getText("emails.recovery.thanks"), + 'signature' => $locale->getText("emails.recovery.signature"), + 'direction' => $locale->getText('settings.direction'), + 'bg-body' => '#f7f7f7', + 'bg-content' => '#ffffff', + 'text-content' => '#000000', + /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ + 'user' => $profile->getAttribute('name'), + 'team' => '', + 'project' => $projectName, + 'redirect' => $url + ]; $mails ->setRecipient($profile->getAttribute('email', '')) ->setName($profile->getAttribute('name')) ->setBody($body) - ->setFrom($from) + ->setVariables($emailVariables) ->setSubject($subject) ->trigger(); - ; $events ->setParam('userId', $profile->getId()) @@ -2358,6 +2553,7 @@ App::put('/v1/account/recovery') ->label('audits.event', 'recovery.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateRecovery') @@ -2444,6 +2640,7 @@ App::post('/v1/account/verification') ->label('event', 'users.[userId].verification.[tokenId].create') ->label('audits.event', 'verification.create') ->label('audits.resource', 'user/{response.userId}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createVerification') @@ -2501,43 +2698,85 @@ App::post('/v1/account/verification') $url = Template::unParseURL($url); $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); - $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); - $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $body = $locale->getText("emails.verification.body"); $subject = $locale->getText("emails.verification.subject"); - - $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; $customTemplate = $project->getAttribute('templates', [])['email.verification-' . $locale->default] ?? []; - if ($smtpEnabled && !empty($customTemplate)) { - $body = $customTemplate['message'] ?? $body; - $subject = $customTemplate['subject'] ?? $subject; - $from = $customTemplate['senderName'] ?? $from; + + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); + $message->setParam('{{body}}', $body); + $body = $message->render(); + + $smtp = $project->getAttribute('smtp', []); + $smtpEnabled = $smtp['enabled'] ?? false; + + $senderEmail = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); + $senderName = App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'); + $replyTo = ""; + + if ($smtpEnabled) { + if (!empty($smtp['senderEmail'])) { + $senderEmail = $smtp['senderEmail']; + } + if (!empty($smtp['senderName'])) { + $senderName = $smtp['senderName']; + } + if (!empty($smtp['replyTo'])) { + $replyTo = $smtp['replyTo']; + } + + $mails + ->setSmtpHost($smtp['host'] ?? '') + ->setSmtpPort($smtp['port'] ?? '') + ->setSmtpUsername($smtp['username'] ?? '') + ->setSmtpPassword($smtp['password'] ?? '') + ->setSmtpSecure($smtp['secure'] ?? ''); + + if (!empty($customTemplate)) { + if (!empty($customTemplate['senderEmail'])) { + $senderEmail = $customTemplate['senderEmail']; + } + if (!empty($customTemplate['senderName'])) { + $senderName = $customTemplate['senderName']; + } + if (!empty($customTemplate['replyTo'])) { + $replyTo = $customTemplate['replyTo']; + } + + $body = $customTemplate['message'] ?? ''; + $subject = $customTemplate['subject'] ?? $subject; + } + + $mails + ->setSmtpReplyTo($replyTo) + ->setSmtpSenderEmail($senderEmail) + ->setSmtpSenderName($senderName); } - $body - ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.verification.hello")) - ->setParam('{{name}}', $user->getAttribute('name')) - ->setParam('{{body}}', $locale->getText("emails.verification.body")) - ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText("emails.verification.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.verification.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.verification.signature")) - ->setParam('{{project}}', $projectName) - ->setParam('{{direction}}', $locale->getText('settings.direction')) - ->setParam('{{bg-body}}', '#f7f7f7') - ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{text-content}}', '#000000'); - - $body = $body->render(); + $emailVariables = [ + 'subject' => $subject, + 'hello' => $locale->getText("emails.verification.hello"), + 'body' => $body, + 'footer' => $locale->getText("emails.verification.footer"), + 'thanks' => $locale->getText("emails.verification.thanks"), + 'signature' => $locale->getText("emails.verification.signature"), + 'direction' => $locale->getText('settings.direction'), + 'bg-body' => '#f7f7f7', + 'bg-content' => '#ffffff', + 'text-content' => '#000000', + /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ + 'user' => $user->getAttribute('name'), + 'team' => '', + 'project' => $projectName, + 'redirect' => $url + ]; $mails ->setSubject($subject) ->setBody($body) - ->setFrom($from) + ->setVariables($emailVariables) ->setRecipient($user->getAttribute('email')) ->setName($user->getAttribute('name') ?? '') - ->trigger() - ; + ->trigger(); $events ->setParam('userId', $user->getId()) @@ -2545,8 +2784,7 @@ App::post('/v1/account/verification') ->setPayload($response->output( $verification->setAttribute('secret', $verificationSecret), Response::MODEL_TOKEN - )) - ; + )); // Hide secret for clients $verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $verificationSecret : ''); @@ -2563,6 +2801,7 @@ App::put('/v1/account/verification') ->label('event', 'users.[userId].verification.[tokenId].update') ->label('audits.event', 'verification.update') ->label('audits.resource', 'user/{response.userId}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateVerification') @@ -2623,6 +2862,7 @@ App::post('/v1/account/verification/phone') ->label('event', 'users.[userId].verification.[tokenId].create') ->label('audits.event', 'verification.create') ->label('audits.resource', 'user/{response.userId}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'createPhoneVerification') @@ -2718,6 +2958,7 @@ App::put('/v1/account/verification/phone') ->label('event', 'users.[userId].verification.[tokenId].update') ->label('audits.event', 'verification.update') ->label('audits.resource', 'user/{response.userId}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePhoneVerification') diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 0be2e0d849..3b93348643 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -1,11 +1,8 @@ isKnown()) { + throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED); + } + + $fetch = @\file_get_contents($url); if (!$fetch) { throw new Exception(Exception::AVATAR_IMAGE_NOT_FOUND); @@ -326,6 +333,12 @@ App::get('/v1/avatars/favicon') throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); } + $domain = new Domain(\parse_url($url, PHP_URL_HOST)); + + if (!$domain->isKnown()) { + throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED); + } + $curl = \curl_init(); \curl_setopt_array($curl, [ @@ -399,6 +412,12 @@ App::get('/v1/avatars/favicon') $outputExt = 'ico'; } + $domain = new Domain(\parse_url($outputHref, PHP_URL_HOST)); + + if (!$domain->isKnown()) { + throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED); + } + if ('ico' == $outputExt) { // Skip crop, Imagick isn\'t supporting icon files $data = @\file_get_contents($outputHref, false); @@ -545,8 +564,6 @@ App::get('/v1/avatars/initials') $image->setImageFormat("png"); $image->compositeImage($punch, Imagick::COMPOSITE_COPYOPACITY, 0, 0); - //$image->setImageCompressionQuality(9 - round(($quality / 100) * 9)); - $response ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->setContentType('image/png') diff --git a/app/controllers/api/console.php b/app/controllers/api/console.php index f2ea83af58..1bd62a1d4c 100644 --- a/app/controllers/api/console.php +++ b/app/controllers/api/console.php @@ -29,23 +29,37 @@ App::get('/v1/console/variables') ->label('sdk.response.model', Response::MODEL_CONSOLE_VARIABLES) ->inject('response') ->action(function (Response $response) { + $isDomainEnabled = !empty(App::getEnv('_APP_DOMAIN', '')) + && !empty(App::getEnv('_APP_DOMAIN_TARGET', '')) + && App::getEnv('_APP_DOMAIN', '') !== 'localhost' + && App::getEnv('_APP_DOMAIN_TARGET', '') !== 'localhost'; + + $isVcsEnabled = !empty(App::getEnv('_APP_VCS_GITHUB_APP_NAME', '')) + && !empty(App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY', '')) + && !empty(App::getEnv('_APP_VCS_GITHUB_APP_ID', '')) + && !empty(App::getEnv('_APP_VCS_GITHUB_CLIENT_ID', '')) + && !empty(App::getEnv('_APP_VCS_GITHUB_CLIENT_SECRET', '')); + + $isAssistantEnabled = !empty(App::getEnv('_APP_ASSISTANT_OPENAI_API_KEY', '')); $variables = new Document([ '_APP_DOMAIN_TARGET' => App::getEnv('_APP_DOMAIN_TARGET'), '_APP_STORAGE_LIMIT' => +App::getEnv('_APP_STORAGE_LIMIT'), '_APP_FUNCTIONS_SIZE_LIMIT' => +App::getEnv('_APP_FUNCTIONS_SIZE_LIMIT'), '_APP_USAGE_STATS' => App::getEnv('_APP_USAGE_STATS'), + '_APP_VCS_ENABLED' => $isVcsEnabled, + '_APP_DOMAIN_ENABLED' => $isDomainEnabled, + '_APP_ASSISTANT_ENABLED' => $isAssistantEnabled ]); $response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES); }); - App::post('/v1/console/assistant') ->desc('Ask Query') ->groups(['api', 'assistant']) - ->label('scope', 'public') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION]) + ->label('scope', 'assistant.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'assistant') ->label('sdk.method', 'chat') ->label('sdk.description', '/docs/references/assistant/chat.md') @@ -53,12 +67,12 @@ App::post('/v1/console/assistant') ->label('sdk.response.type', Response::CONTENT_TYPE_TEXT) ->label('abuse-limit', 15) ->label('abuse-key', 'userId:{userId}') - ->param('query', '', new Text(2000), 'Query') + ->param('prompt', '', new Text(2000), 'Prompt. A string containing questions asked to the AI assistant.') ->inject('response') - ->action(function (string $query, Response $response) { + ->action(function (string $prompt, Response $response) { $ch = curl_init('http://appwrite-assistant:3003/'); $responseHeaders = []; - $query = json_encode(['prompt' => $query]); + $query = json_encode(['prompt' => $prompt]); $headers = ['accept: text/event-stream']; $handleEvent = function ($ch, $data) use ($response) { $response->chunk($data); diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 2a1884e6b2..bf66e9fd8e 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -26,6 +26,7 @@ use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Limit as LimitException; use Utopia\Database\Exception\Restricted as RestrictedException; use Utopia\Database\Exception\Structure as StructureException; +use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -196,16 +197,14 @@ function createAttribute(string $databaseId, string $collectionId, Document $att ->setType(DATABASE_TYPE_CREATE_ATTRIBUTE) ->setDatabase($db) ->setCollection($collection) - ->setDocument($attribute) - ; + ->setDocument($attribute); $events ->setContext('collection', $collection) ->setContext('database', $db) ->setParam('databaseId', $databaseId) ->setParam('collectionId', $collection->getId()) - ->setParam('attributeId', $attribute->getId()) - ; + ->setParam('attributeId', $attribute->getId()); $response->setStatusCode(Response::STATUS_CODE_CREATED); @@ -358,7 +357,7 @@ function updateAttribute( ); } - $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key, $attribute); + $attribute = $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key, $attribute); $dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collection->getId()); $events @@ -378,6 +377,7 @@ App::post('/v1/databases') ->label('scope', 'databases.write') ->label('audits.event', 'database.create') ->label('audits.resource', 'database/{response.$id}') + ->label('usage.metric', 'databases.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'create') @@ -387,7 +387,7 @@ App::post('/v1/databases') ->label('sdk.response.model', Response::MODEL_DATABASE) // Model for database needs to be created ->param('databaseId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Database name. Max length: 128 chars.') - ->param('enabled', true, new Boolean(), 'Is database enabled?', true) + ->param('enabled', true, new Boolean(), 'Is the database enabled? When set to \'disabled\', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.', true) ->inject('response') ->inject('dbForProject') ->inject('events') @@ -451,6 +451,7 @@ App::get('/v1/databases') ->desc('List Databases') ->groups(['api', 'database']) ->label('scope', 'databases.read') + ->label('usage.metric', 'databases.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'list') @@ -471,7 +472,9 @@ App::get('/v1/databases') } // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { $databaseId = $cursor->getValue(); @@ -496,6 +499,7 @@ App::get('/v1/databases/:databaseId') ->desc('Get Database') ->groups(['api', 'database']) ->label('scope', 'databases.read') + ->label('usage.metric', 'databases.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'get') @@ -610,6 +614,7 @@ App::put('/v1/databases/:databaseId') ->label('event', 'databases.[databaseId].update') ->label('audits.event', 'database.update') ->label('audits.resource', 'database/{response.$id}') + ->label('usage.metric', 'databases.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'update') @@ -619,7 +624,7 @@ App::put('/v1/databases/:databaseId') ->label('sdk.response.model', Response::MODEL_DATABASE) ->param('databaseId', '', new UID(), 'Database ID.') ->param('name', null, new Text(128), 'Database name. Max length: 128 chars.') - ->param('enabled', true, new Boolean(), 'Is database enabled?', true) + ->param('enabled', true, new Boolean(), 'Is database enabled? When set to \'disabled\', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.', true) ->inject('response') ->inject('dbForProject') ->inject('events') @@ -654,6 +659,7 @@ App::delete('/v1/databases/:databaseId') ->label('event', 'databases.[databaseId].delete') ->label('audits.event', 'database.delete') ->label('audits.resource', 'database/{request.databaseId}') + ->label('usage.metric', 'databases.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'delete') @@ -682,25 +688,24 @@ App::delete('/v1/databases/:databaseId') $deletes ->setType(DELETE_TYPE_DOCUMENT) - ->setDocument($database) - ; + ->setDocument($database); $events ->setParam('databaseId', $database->getId()) - ->setPayload($response->output($database, Response::MODEL_DATABASE)) - ; + ->setPayload($response->output($database, Response::MODEL_DATABASE)); $response->noContent(); }); App::post('/v1/databases/:databaseId/collections') - ->alias('/v1/database/collections', ['databaseId' => 'default']) ->desc('Create Collection') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].create') ->label('scope', 'collections.write') ->label('audits.event', 'collection.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{response.$id}') + ->label('usage.metric', 'collections.{scope}.requests.create') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createCollection') @@ -713,7 +718,7 @@ App::post('/v1/databases/:databaseId/collections') ->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.') ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true) ->param('documentSecurity', false, new Boolean(true), 'Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](/docs/permissions).', true) - ->param('enabled', true, new Boolean(), 'Is collection enabled?', true) + ->param('enabled', true, new Boolean(), 'Is collection enabled? When set to \'disabled\', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') @@ -722,7 +727,7 @@ App::post('/v1/databases/:databaseId/collections') $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } @@ -766,6 +771,8 @@ App::get('/v1/databases/:databaseId/collections') ->desc('List Collections') ->groups(['api', 'database']) ->label('scope', 'collections.read') + ->label('usage.metric', 'collections.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'listCollections') @@ -783,7 +790,7 @@ App::get('/v1/databases/:databaseId/collections') $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } @@ -794,7 +801,9 @@ App::get('/v1/databases/:databaseId/collections') } // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -821,6 +830,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId') ->desc('Get Collection') ->groups(['api', 'database']) ->label('scope', 'collections.read') + ->label('usage.metric', 'collections.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'getCollection') @@ -837,7 +848,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId') $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } @@ -855,6 +866,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') ->desc('List Collection Logs') ->groups(['api', 'database']) ->label('scope', 'collections.read') + ->label('usage.metric', 'collections.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'listCollectionLogs') @@ -952,6 +965,8 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->label('event', 'databases.[databaseId].collections.[collectionId].update') ->label('audits.event', 'collection.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateCollection') @@ -964,7 +979,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->param('name', null, new Text(128), 'Collection name. Max length: 128 chars.') ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true) ->param('documentSecurity', false, new Boolean(true), 'Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](/docs/permissions).', true) - ->param('enabled', true, new Boolean(), 'Is collection enabled?', true) + ->param('enabled', true, new Boolean(), 'Is collection enabled? When set to \'disabled\', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.', true) ->inject('response') ->inject('dbForProject') ->inject('mode') @@ -973,7 +988,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } @@ -1020,6 +1035,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->label('event', 'databases.[databaseId].collections.[collectionId].delete') ->label('audits.event', 'collection.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.delete') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'deleteCollection') @@ -1037,7 +1054,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); } @@ -1074,6 +1091,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createStringAttribute') @@ -1088,11 +1107,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Text(0, 0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) + ->param('encrypt', false, new Boolean(), 'Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.', true) ->inject('response') ->inject('dbForProject') ->inject('database') ->inject('events') - ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { // Ensure attribute default is within required size $validator = new Text($size, 0); @@ -1100,6 +1120,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription()); } + $filters = []; + + if ($encrypt) { + $filters[] = 'encrypt'; + } + $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_STRING, @@ -1107,6 +1133,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string 'required' => $required, 'default' => $default, 'array' => $array, + 'filters' => $filters, ]), $response, $dbForProject, $database, $events); $response @@ -1122,6 +1149,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createEmailAttribute') @@ -1164,6 +1193,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createEnumAttribute') @@ -1222,6 +1253,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createIpAttribute') @@ -1264,6 +1297,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createUrlAttribute') @@ -1306,6 +1341,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createIntegerAttribute') @@ -1377,6 +1414,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createFloatAttribute') @@ -1451,6 +1490,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createBooleanAttribute') @@ -1492,6 +1533,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createDatetimeAttribute') @@ -1511,6 +1554,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) { + $filters[] = 'datetime'; + $attribute = createAttribute($databaseId, $collectionId, new Document([ 'key' => $key, 'type' => Database::VAR_DATETIME, @@ -1518,7 +1563,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti 'required' => $required, 'default' => $default, 'array' => $array, - 'filters' => ['datetime'] + 'filters' => $filters, ]), $response, $dbForProject, $database, $events); $response @@ -1534,6 +1579,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati ->label('scope', 'collections.write') ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.namespace', 'databases') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.method', 'createRelationshipAttribute') @@ -1611,6 +1658,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') ->desc('List Attributes') ->groups(['api', 'database']) ->label('scope', 'collections.read') + ->label('usage.metric', 'collections.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'listAttributes') @@ -1639,11 +1688,18 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') $queries = Query::parseQueries($queries); - \array_push($queries, Query::equal('collectionId', [$collectionId]), Query::equal('databaseId', [$databaseId])); + \array_push( + $queries, + Query::equal('collectionId', [$collectionId]), + Query::equal('databaseId', [$databaseId]) + ); // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); - $cursor = reset($cursor); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); + + $cursor = \reset($cursor); if ($cursor) { $attributeId = $cursor->getValue(); @@ -1653,17 +1709,22 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') Query::equal('key', [$attributeId]), Query::limit(1), ])); + if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Attribute '{$attributeId}' for the 'cursor' value not found."); } + $cursor->setValue($cursorDocument[0]); } - $filterQueries = Query::groupByType($queries)['filters']; + $filters = Query::groupByType($queries)['filters']; + + $attributes = $dbForProject->find('attributes', $queries); + $total = $dbForProject->count('attributes', $filters, APP_LIMIT_COUNT); $response->dynamic(new Document([ - 'total' => $dbForProject->count('attributes', $filterQueries, APP_LIMIT_COUNT), - 'attributes' => $dbForProject->find('attributes', $queries), + 'attributes' => $attributes, + 'total' => $total, ]), Response::MODEL_ATTRIBUTE_LIST); }); @@ -1672,6 +1733,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') ->desc('Get Attribute') ->groups(['api', 'database']) ->label('scope', 'collections.read') + ->label('usage.metric', 'collections.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'getAttribute') @@ -1749,6 +1812,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateStringAttribute') @@ -1764,6 +1829,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin ->inject('dbForProject') ->inject('events') ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) { + $attribute = updateAttribute( databaseId: $databaseId, collectionId: $collectionId, @@ -1787,6 +1853,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/email ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateEmailAttribute') @@ -1826,6 +1894,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/enum/ ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateEnumAttribute') @@ -1867,6 +1937,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/ip/:k ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateIpAttribute') @@ -1906,6 +1978,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/url/: ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateUrlAttribute') @@ -1945,6 +2019,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/integ ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateIntegerAttribute') @@ -1994,6 +2070,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/float ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateFloatAttribute') @@ -2043,6 +2121,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/boole ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateBooleanAttribute') @@ -2081,6 +2161,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/datet ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'documents.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateDatetimeAttribute') @@ -2119,6 +2201,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/ ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'documents.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateRelationshipAttribute') @@ -2173,6 +2257,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete') ->label('audits.event', 'attribute.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'deleteAttribute') @@ -2282,6 +2368,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->label('scope', 'collections.write') ->label('audits.event', 'index.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'createIndex') @@ -2437,6 +2525,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') ->desc('List Indexes') ->groups(['api', 'database']) ->label('scope', 'collections.read') + ->label('usage.metric', 'collections.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'listIndexes') @@ -2467,7 +2557,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') \array_push($queries, Query::equal('collectionId', [$collectionId]), Query::equal('databaseId', [$databaseId])); // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { @@ -2498,6 +2590,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->desc('Get Index') ->groups(['api', 'database']) ->label('scope', 'collections.read') + ->label('usage.metric', 'collections.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'getIndex') @@ -2540,6 +2634,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].delete') ->label('audits.event', 'index.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'collections.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'deleteIndex') @@ -2603,7 +2699,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create') ->label('scope', 'documents.write') ->label('audits.event', 'document.create') - ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}') + ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') + ->label('usage.metric', 'documents.{scope}.requests.create') + ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}') ->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT * 2) ->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT) @@ -2640,16 +2738,17 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception(Exception::COLLECTION_NOT_FOUND); - } + if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { + throw new Exception(Exception::COLLECTION_NOT_FOUND); } $allowedPermissions = [ @@ -2672,8 +2771,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') } // Users can only manage their own roles, API keys and Admin users can manage any - $roles = Authorization::getRoles(); - if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { + if (!$isAPIKey && !$isPrivilegedUser) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -2686,7 +2784,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $permission->getDimension() ))->toString(); if (!Authorization::isRole($role)) { - throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')'); + throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', Authorization::getRoles()) . ')'); } } } @@ -2839,6 +2937,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') ->desc('List Documents') ->groups(['api', 'database']) ->label('scope', 'documents.read') + ->label('usage.metric', 'documents.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'listDocuments') @@ -2854,40 +2954,30 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - if (!$collection->getAttribute('documentSecurity', false)) { - $validator = new Authorization(Database::PERMISSION_READ); - if (!$validator->isValid($collection->getRead())) { - $collection = new Document(); - } - } - } - - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { + if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } - // Validate queries - $queriesValidator = new Documents($collection->getAttribute('attributes'), $collection->getAttribute('indexes')); - $validQueries = $queriesValidator->isValid($queries); - if (!$validQueries) { - throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $queriesValidator->getDescription()); - } - $queries = Query::parseQueries($queries); // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); - $cursor = reset($cursor); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); + + $cursor = \reset($cursor); + if ($cursor) { $documentId = $cursor->getValue(); @@ -2900,13 +2990,19 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $cursor->setValue($cursorDocument); } - $filterQueries = Query::groupByType($queries)['filters']; + $filters = Query::groupByType($queries)['filters']; - $documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries); - $total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT); + try { + $documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries); + $total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filters, APP_LIMIT_COUNT); + } catch (AuthorizationException) { + throw new Exception(Exception::USER_UNAUTHORIZED); + } catch (QueryException $e) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $e->getMessage()); + } // Add $collectionId and $databaseId for all documents - $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database): bool { + $processDocument = (function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database): bool { if ($document->isEmpty()) { return false; } @@ -2951,12 +3047,11 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') } return true; - }; + }); - // The linter is forcing this indentation - foreach ($documents as $document) { - $processDocument($collection, $document); - } + foreach ($documents as $document) { + $processDocument($collection, $document); + } $response->dynamic(new Document([ 'total' => $total, @@ -2969,6 +3064,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->desc('Get Document') ->groups(['api', 'database']) ->label('scope', 'documents.read') + ->label('usage.metric', 'documents.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'getDocument') @@ -2986,31 +3083,30 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception(Exception::COLLECTION_NOT_FOUND); - } - } - - // Validate queries - $queriesValidator = new DocumentQueriesValidator($collection->getAttribute('attributes')); - $validQueries = $queriesValidator->isValid($queries); - if (!$validQueries) { - throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $queriesValidator->getDescription()); + if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { + throw new Exception(Exception::COLLECTION_NOT_FOUND); } $queries = Query::parseQueries($queries); - $document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries); + try { + $document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries); + } catch (AuthorizationException) { + throw new Exception(Exception::USER_UNAUTHORIZED); + } catch (QueryException $e) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $e->getMessage()); + } if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3063,6 +3159,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->desc('List Document Logs') ->groups(['api', 'database']) ->label('scope', 'documents.read') + ->label('usage.metric', 'documents.{scope}.requests.read') + ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'listDocumentLogs') @@ -3165,6 +3263,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->label('scope', 'documents.write') ->label('audits.event', 'document.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}') + ->label('usage.metric', 'documents.{scope}.requests.update') + ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}') ->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT * 2) ->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT) @@ -3197,16 +3297,17 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception(Exception::COLLECTION_NOT_FOUND); - } + if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { + throw new Exception(Exception::COLLECTION_NOT_FOUND); } // Read permission should not be required for update @@ -3226,7 +3327,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum // Users can only manage their own roles, API keys and Admin users can manage any $roles = Authorization::getRoles(); - if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) { + if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) { foreach (Database::PERMISSIONS as $type) { foreach ($permissions as $permission) { $permission = Permission::parse($permission); @@ -3249,29 +3350,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $permissions = $document->getPermissions() ?? []; } - $data = \array_merge($document->getArrayCopy(), $data); // Merge existing data with new data - $data['$collection'] = $collection->getId(); // Make sure user doesn't switch collectionID - $data['$createdAt'] = $document->getCreatedAt(); // Make sure user doesn't switch createdAt - $data['$id'] = $document->getId(); // Make sure user doesn't switch document unique ID + $data['$id'] = $documentId; $data['$permissions'] = $permissions; $newDocument = new Document($data); - $checkPermissions = function (Document $collection, Document $document, Document $old, string $permission) use (&$checkPermissions, $dbForProject, $database) { - $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validator = new Authorization($permission); - - $valid = $validator->isValid($collection->getPermissionsByType($permission)); - if (!$documentSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } - - if ($permission === Database::PERMISSION_UPDATE) { - $valid = $valid || $validator->isValid($old->getPermissionsByType($permission)); - if ($documentSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } - } - + $setCollection = (function (Document $collection, Document $document) use (&$setCollection, $dbForProject, $database) { $relationships = \array_filter( $collection->getAttribute('attributes', []), fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP @@ -3298,6 +3381,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ); foreach ($relations as &$relation) { + // If the relation is an array it can be either update or create a child document. if ( \is_array($relation) && \array_values($relation) !== $relation @@ -3311,21 +3395,20 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId() )); + $relation->removeAttribute('$collectionId'); + $relation->removeAttribute('$databaseId'); + // Attribute $collection is required for Utopia. + $relation->setAttribute( + '$collection', + 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId() + ); if ($oldDocument->isEmpty()) { - $type = Database::PERMISSION_CREATE; - if (isset($relation['$id']) && $relation['$id'] === 'unique()') { $relation['$id'] = ID::unique(); } - } else { - $relation->removeAttribute('$collectionId'); - $relation->removeAttribute('$databaseId'); - $relation->setAttribute('$collection', $relatedCollection->getId()); - $type = Database::PERMISSION_UPDATE; } - - $checkPermissions($relatedCollection, $relation, $oldDocument, $type); + $setCollection($relatedCollection, $relation); } } @@ -3335,26 +3418,26 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $document->setAttribute($relationship->getAttribute('key'), \reset($relations)); } } - }; + }); - $checkPermissions($collection, $newDocument, $document, Database::PERMISSION_UPDATE); + $setCollection($collection, $newDocument); - try { - $document = $dbForProject->withRequestTimestamp( - $requestTimestamp, - fn() => $dbForProject->updateDocument( - 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), - $document->getId(), - $newDocument - ) - ); - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (DuplicateException) { - throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); - } + try { + $document = $dbForProject->withRequestTimestamp( + $requestTimestamp, + fn() => $dbForProject->updateDocument( + 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), + $document->getId(), + $newDocument + ) + ); + } catch (AuthorizationException) { + throw new Exception(Exception::USER_UNAUTHORIZED); + } catch (DuplicateException) { + throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); + } catch (StructureException $exception) { + throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); + } // Add $collectionId and $databaseId for all documents $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { @@ -3409,6 +3492,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->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}') + ->label('usage.metric', 'documents.{scope}.requests.delete') + ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}') ->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT) ->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT) @@ -3430,19 +3515,19 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->inject('deletes') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events, Delete $deletes, string $mode) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); - if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::DATABASE_NOT_FOUND); } $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception(Exception::COLLECTION_NOT_FOUND); - } + if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { + throw new Exception(Exception::COLLECTION_NOT_FOUND); } // Read permission should not be required for delete @@ -3452,68 +3537,18 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu throw new Exception(Exception::DOCUMENT_NOT_FOUND); } - $checkPermissions = function (Document $collection, Document $document) use (&$checkPermissions, $dbForProject, $database) { - $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validator = new Authorization(Database::PERMISSION_DELETE); - - $valid = $validator->isValid($collection->getDelete()); - if (!$documentSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } - - $valid = $valid || $validator->isValid($document->getDelete()); - if ($documentSecurity && !$valid) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } - - $relationships = \array_filter( - $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP - ); - - foreach ($relationships as $relationship) { - $related = $document->getAttribute($relationship->getAttribute('key')); - - if (empty($related)) { - continue; - } - if (!\is_array($related)) { - $related = [$related]; - } - - $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) - ); - - foreach ($related as $relation) { - if ( - $relation instanceof Document - && $relationship->getAttribute('onDelete') === Database::RELATION_MUTATE_CASCADE - ) { - $checkPermissions($relatedCollection, $relation); - } - } - } - }; - - $checkPermissions($collection, $document); - - Authorization::skip(fn() => $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) { + $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) { try { $dbForProject->deleteDocument( 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId ); + } catch (AuthorizationException) { + throw new Exception(Exception::USER_UNAUTHORIZED); } catch (RestrictedException) { throw new Exception(Exception::DOCUMENT_DELETE_RESTRICTED); } - })); - - $dbForProject->deleteCachedDocument( - 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), - $documentId - ); + }); // Add $collectionId and $databaseId for all documents $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { @@ -3567,7 +3602,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu App::get('/v1/databases/usage') ->desc('Get usage stats for the database') - ->groups(['api', 'database', 'usage']) + ->groups(['api', 'database']) ->label('scope', 'collections.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'databases') @@ -3580,62 +3615,112 @@ App::get('/v1/databases/usage') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { - $periods = Config::getParam('usage', []); - $stats = $usage = []; - $days = $periods[$range]; - $metrics = [ - METRIC_DATABASES, - METRIC_COLLECTIONS, - METRIC_DOCUMENTS, - ]; - - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { - foreach ($metrics as $metric) { - $limit = $days['limit']; - $period = $days['period']; - $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), - Query::equal('metric', [$metric]), - Query::limit($limit), - Query::orderDesc('time'), - ]); - $stats[$metric] = []; - foreach ($results as $result) { - $stats[$metric][$result->getAttribute('time')] = [ - 'value' => $result->getAttribute('value'), - ]; - } - } - }); - - $format = match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }; - - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], ]; + + $metrics = [ + 'databases.$all.count.total', + 'documents.$all.count.total', + 'collections.$all.count.total', + 'databases.$all.requests.create', + 'databases.$all.requests.read', + 'databases.$all.requests.update', + 'databases.$all.requests.delete', + 'collections.$all.requests.create', + 'collections.$all.requests.read', + 'collections.$all.requests.update', + 'collections.$all.requests.delete', + 'documents.$all.requests.create', + 'documents.$all.requests.read', + 'documents.$all.requests.update', + 'documents.$all.requests.delete' + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + // Added 3'rd level to Index [period, metric, time] because of order by. + $stats[$metric] = array_reverse($stats[$metric]); + } + }); + + $usage = new Document([ + 'range' => $range, + 'databasesCount' => $stats['databases.$all.count.total'] ?? [], + 'documentsCount' => $stats['documents.$all.count.total'] ?? [], + 'collectionsCount' => $stats['collections.$all.count.total'] ?? [], + 'documentsCreate' => $stats['documents.$all.requests.create'] ?? [], + 'documentsRead' => $stats['documents.$all.requests.read'] ?? [], + 'documentsUpdate' => $stats['documents.$all.requests.update'] ?? [], + 'documentsDelete' => $stats['documents.$all.requests.delete'] ?? [], + 'collectionsCreate' => $stats['collections.$all.requests.create'] ?? [], + 'collectionsRead' => $stats['collections.$all.requests.read'] ?? [], + 'collectionsUpdate' => $stats['collections.$all.requests.update'] ?? [], + 'collectionsDelete' => $stats['collections.$all.requests.delete'] ?? [], + 'databasesCreate' => $stats['databases.$all.requests.create'] ?? [], + 'databasesRead' => $stats['databases.$all.requests.read'] ?? [], + 'databasesUpdate' => $stats['databases.$all.requests.update'] ?? [], + 'databasesDelete' => $stats['databases.$all.requests.delete'] ?? [], + ]); } - } - $response->dynamic(new Document([ - 'range' => $range, - 'databasesTotal' => $usage[$metrics[0]], - 'collectionsTotal' => $usage[$metrics[1]], - 'documentsTotal' => $usage[$metrics[2]], - ]), Response::MODEL_USAGE_DATABASES); + + $response->dynamic($usage, Response::MODEL_USAGE_DATABASES); }); App::get('/v1/databases/:databaseId/usage') ->desc('Get usage stats for the database') - ->groups(['api', 'database', 'usage']) + ->groups(['api', 'database']) ->label('scope', 'collections.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'databases') @@ -3649,68 +3734,103 @@ App::get('/v1/databases/:databaseId/usage') ->inject('dbForProject') ->action(function (string $databaseId, string $range, Response $response, Database $dbForProject) { - $database = $dbForProject->getDocument('databases', $databaseId); - - if ($database->isEmpty()) { - throw new Exception(Exception::DATABASE_NOT_FOUND); - } - - $periods = Config::getParam('usage', []); - $stats = $usage = []; - $days = $periods[$range]; - $metrics = [ - str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS), - str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS), - ]; - - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { - foreach ($metrics as $metric) { - $limit = $days['limit']; - $period = $days['period']; - $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), - Query::equal('metric', [$metric]), - Query::limit($limit), - Query::orderDesc('time'), - ]); - $stats[$metric] = []; - foreach ($results as $result) { - $stats[$metric][$result->getAttribute('time')] = [ - 'value' => $result->getAttribute('value'), - ]; - } - } - }); - - $format = match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }; - - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], ]; - } - } - $response->dynamic(new Document([ - 'range' => $range, - 'collectionsTotal' => $usage[$metrics[0]], - 'documentsTotal' => $usage[$metrics[1]], - ]), Response::MODEL_USAGE_DATABASE); + $metrics = [ + 'collections.' . $databaseId . '.count.total', + 'collections.' . $databaseId . '.requests.create', + 'collections.' . $databaseId . '.requests.read', + 'collections.' . $databaseId . '.requests.update', + 'collections.' . $databaseId . '.requests.delete', + 'documents.' . $databaseId . '.count.total', + 'documents.' . $databaseId . '.requests.create', + 'documents.' . $databaseId . '.requests.read', + 'documents.' . $databaseId . '.requests.update', + 'documents.' . $databaseId . '.requests.delete' + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + // TODO@kodumbeats explore performance if query is ordered by time ASC + $stats[$metric] = array_reverse($stats[$metric]); + } + }); + + $usage = new Document([ + 'range' => $range, + 'collectionsCount' => $stats["collections.{$databaseId}.count.total"] ?? [], + 'collectionsCreate' => $stats["collections.{$databaseId}.requests.create"] ?? [], + 'collectionsRead' => $stats["collections.{$databaseId}.requests.read"] ?? [], + 'collectionsUpdate' => $stats["collections.{$databaseId}.requests.update"] ?? [], + 'collectionsDelete' => $stats["collections.{$databaseId}.requests.delete"] ?? [], + 'documentsCount' => $stats["documents.{$databaseId}.count.total"] ?? [], + 'documentsCreate' => $stats["documents.{$databaseId}.requests.create"] ?? [], + 'documentsRead' => $stats["documents.{$databaseId}.requests.read"] ?? [], + 'documentsUpdate' => $stats["documents.{$databaseId}.requests.update"] ?? [], + 'documentsDelete' => $stats["documents.{$databaseId}.requests.delete"] ?? [], + ]); + } + + $response->dynamic($usage, Response::MODEL_USAGE_DATABASE); }); App::get('/v1/databases/:databaseId/collections/:collectionId/usage') ->alias('/v1/database/:collectionId/usage', ['databaseId' => 'default']) ->desc('Get usage stats for a collection') - ->groups(['api', 'database', 'usage']) + ->groups(['api', 'database']) ->label('scope', 'collections.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'databases') @@ -3733,52 +3853,84 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') throw new Exception(Exception::COLLECTION_NOT_FOUND); } - $periods = Config::getParam('usage', []); - $stats = $usage = []; - $days = $periods[$range]; - $metrics = [ - str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collectionDocument->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS), - ]; - - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { - foreach ($metrics as $metric) { - $limit = $days['limit']; - $period = $days['period']; - $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), - Query::equal('metric', [$metric]), - Query::limit($limit), - Query::orderDesc('time'), - ]); - $stats[$metric] = []; - foreach ($results as $result) { - $stats[$metric][$result->getAttribute('time')] = [ - 'value' => $result->getAttribute('value'), - ]; - } - } - }); - - $format = match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }; - - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], ]; - } - } - $response->dynamic(new Document([ - 'range' => $range, - 'documentsTotal' => $usage[$metrics[0]], - ]), Response::MODEL_USAGE_COLLECTION); + $metrics = [ + "documents.{$databaseId}/{$collectionId}.count.total", + "documents.{$databaseId}/{$collectionId}.requests.create", + "documents.{$databaseId}/{$collectionId}.requests.read", + "documents.{$databaseId}/{$collectionId}.requests.update", + "documents.{$databaseId}/{$collectionId}.requests.delete", + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + $stats[$metric] = array_reverse($stats[$metric]); + } + }); + + $usage = new Document([ + 'range' => $range, + 'documentsCount' => $stats["documents.{$databaseId}/{$collectionId}.count.total"] ?? [], + 'documentsCreate' => $stats["documents.{$databaseId}/{$collectionId}.requests.create"] ?? [], + 'documentsRead' => $stats["documents.{$databaseId}/{$collectionId}.requests.read"] ?? [], + 'documentsUpdate' => $stats["documents.{$databaseId}/{$collectionId}.requests.update"] ?? [], + 'documentsDelete' => $stats["documents.{$databaseId}/{$collectionId}.requests.delete" ?? []] + ]); + } + + $response->dynamic($usage, Response::MODEL_USAGE_COLLECTION); }); diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 81500f1d27..a286b4f567 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -8,8 +8,12 @@ use Appwrite\Event\Event; use Appwrite\Event\Func; use Appwrite\Event\Usage; use Appwrite\Event\Validator\Event as ValidatorEvent; +use Appwrite\Utopia\Response\Model\Rule; use Appwrite\Extend\Exception; use Appwrite\Utopia\Database\Validator\CustomId; +use Appwrite\Messaging\Adapter\Realtime; +use Utopia\Validator\Assoc; +use Appwrite\Usage\Stats; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -41,9 +45,79 @@ use Utopia\CLI\Console; use Utopia\Database\Validator\Roles; use Utopia\Validator\Boolean; use Utopia\Database\Exception\Duplicate as DuplicateException; +use MaxMind\Db\Reader; +use Utopia\VCS\Adapter\Git\GitHub; include_once __DIR__ . '/../shared/api.php'; +$redeployVcs = function (Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Document $template, GitHub $github) { + $deploymentId = ID::unique(); + $entrypoint = $function->getAttribute('entrypoint', ''); + $providerInstallationId = $installation->getAttribute('providerInstallationId', ''); + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + $owner = $github->getOwnerName($providerInstallationId); + $providerRepositoryId = $function->getAttribute('providerRepositoryId', ''); + $repositoryName = $github->getRepositoryName($providerRepositoryId); + $providerBranch = $function->getAttribute('providerBranch', 'main'); + $authorUrl = "https://github.com/$owner"; + $repositoryUrl = "https://github.com/$owner/$repositoryName"; + $branchUrl = "https://github.com/$owner/$repositoryName/tree/$providerBranch"; + + $commitDetails = []; + if ($template->isEmpty()) { + try { + $commitDetails = $github->getLatestCommit($owner, $repositoryName, $providerBranch); + } catch (\Throwable $error) { + Console::warning('Failed to get latest commit details'); + Console::warning($error->getMessage()); + Console::warning($error->getTraceAsString()); + } + } + + $deployment = $dbForProject->createDocument('deployments', new Document([ + '$id' => $deploymentId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'resourceId' => $function->getId(), + 'resourceType' => 'functions', + 'entrypoint' => $entrypoint, + 'commands' => $function->getAttribute('commands', ''), + 'type' => 'vcs', + 'installationId' => $installation->getId(), + 'installationInternalId' => $installation->getInternalId(), + 'providerRepositoryId' => $providerRepositoryId, + 'repositoryId' => $function->getAttribute('repositoryId', ''), + 'repositoryInternalId' => $function->getAttribute('repositoryInternalId', ''), + 'providerBranchUrl' => $branchUrl, + 'providerRepositoryName' => $repositoryName, + 'providerRepositoryOwner' => $owner, + 'providerRepositoryUrl' => $repositoryUrl, + 'providerCommitHash' => $commitDetails['commitHash'] ?? '', + 'providerCommitAuthorUrl' => $authorUrl, + 'providerCommitAuthor' => $commitDetails['commitAuthor'] ?? '', + 'providerCommitMessage' => $commitDetails['commitMessage'] ?? '', + 'providerCommitUrl' => $commitDetails['commitUrl'] ?? '', + 'providerBranch' => $providerBranch, + 'providerRootDirectory' => $function->getAttribute('providerRootDirectory', ''), + 'search' => implode(' ', [$deploymentId, $entrypoint]), + 'activate' => true, + ])); + + $buildEvent = new Build(); + $buildEvent + ->setType(BUILD_TYPE_DEPLOYMENT) + ->setResource($function) + ->setDeployment($deployment) + ->setTemplate($template) + ->setProject($project) + ->trigger(); +}; + App::post('/v1/functions') ->groups(['api', 'functions']) ->desc('Create Function') @@ -60,25 +134,65 @@ App::post('/v1/functions') ->label('sdk.response.model', Response::MODEL_FUNCTION) ->param('functionId', '', new CustomId(), 'Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Function name. Max length: 128 chars.') - ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) ->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.') + ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true) ->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.', true) - ->param('enabled', true, new Boolean(), 'Is function enabled?', true) + ->param('enabled', true, new Boolean(), 'Is function enabled? When set to \'disabled\', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.', true) + ->param('logging', true, new Boolean(), 'Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.', true) + ->param('entrypoint', '', new Text(1028, 0), 'Entrypoint File. This path is relative to the "providerRootDirectory".', true) + ->param('commands', '', new Text(8192, 0), 'Build Commands.', true) + ->param('installationId', '', new Text(128, 0), 'Appwrite Installation ID for VCS (Version Control System) deployment.', true) + ->param('providerRepositoryId', '', new Text(128, 0), 'Repository ID of the repo linked to the function.', true) + ->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function.', true) + ->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.', true) + ->param('providerRootDirectory', '', new Text(128, 0), 'Path to function code in the linked repo.', true) + ->param('templateRepository', '', new Text(128, 0), 'Repository name of the template.', true) + ->param('templateOwner', '', new Text(128, 0), 'The name of the owner of the template.', true) + ->param('templateRootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.', true) + ->param('templateBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function template.', true) + ->inject('request') ->inject('response') ->inject('dbForProject') ->inject('project') ->inject('user') ->inject('events') ->inject('dbForConsole') - ->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance, Database $dbForConsole) { - + ->inject('gitHub') + ->action(function (string $functionId, string $name, string $runtime, array $execute, array $events, string $schedule, int $timeout, bool $enabled, bool $logging, string $entrypoint, string $commands, string $installationId, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $templateRepository, string $templateOwner, string $templateRootDirectory, string $templateBranch, Request $request, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance, Database $dbForConsole, GitHub $github) use ($redeployVcs) { $functionId = ($functionId == 'unique()') ? ID::unique() : $functionId; + + // build from template + $template = new Document([]); + if ( + !empty($templateRepository) + && !empty($templateOwner) + && !empty($templateRootDirectory) + && !empty($templateBranch) + ) { + $template->setAttribute('repositoryName', $templateRepository) + ->setAttribute('ownerName', $templateOwner) + ->setAttribute('rootDirectory', $templateRootDirectory) + ->setAttribute('branch', $templateBranch); + } + + $installation = $dbForConsole->getDocument('installations', $installationId); + + if (!empty($installationId) && $installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + if (!empty($providerRepositoryId) && (empty($installationId) || empty($providerBranch))) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'When connecting to VCS (Version Control System), you need to provide "installationId" and "providerBranch".'); + } + $function = $dbForProject->createDocument('functions', new Document([ '$id' => $functionId, 'execute' => $execute, 'enabled' => $enabled, + 'live' => true, + 'logging' => $logging, 'name' => $name, 'runtime' => $runtime, 'deploymentInternalId' => '', @@ -86,12 +200,24 @@ App::post('/v1/functions') 'events' => $events, 'schedule' => $schedule, 'scheduleInternalId' => '', + 'scheduleId' => '', 'timeout' => $timeout, - 'search' => implode(' ', [$functionId, $name, $runtime]) + 'entrypoint' => $entrypoint, + 'commands' => $commands, + 'search' => implode(' ', [$functionId, $name, $runtime]), + 'version' => 'v3', + 'installationId' => $installation->getId(), + 'installationInternalId' => $installation->getInternalId(), + 'providerRepositoryId' => $providerRepositoryId, + 'repositoryId' => '', + 'repositoryInternalId' => '', + 'providerBranch' => $providerBranch, + 'providerRootDirectory' => $providerRootDirectory, + 'providerSilentMode' => $providerSilentMode, ])); $schedule = Authorization::skip( - fn() => $dbForConsole->createDocument('schedules', new Document([ + fn () => $dbForConsole->createDocument('schedules', new Document([ 'region' => App::getEnv('_APP_REGION', 'default'), // Todo replace with projects region 'resourceType' => 'function', 'resourceId' => $function->getId(), @@ -105,7 +231,99 @@ App::post('/v1/functions') $function->setAttribute('scheduleId', $schedule->getId()); $function->setAttribute('scheduleInternalId', $schedule->getInternalId()); - $dbForProject->updateDocument('functions', $function->getId(), $function); + + // Git connect logic + if (!empty($providerRepositoryId)) { + $repository = $dbForConsole->createDocument('repositories', new Document([ + '$id' => ID::unique(), + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'installationId' => $installation->getId(), + 'installationInternalId' => $installation->getInternalId(), + 'projectId' => $project->getId(), + 'projectInternalId' => $project->getInternalId(), + 'providerRepositoryId' => $providerRepositoryId, + 'resourceId' => $function->getId(), + 'resourceInternalId' => $function->getInternalId(), + 'resourceType' => 'function', + 'providerPullRequestIds' => [] + ])); + + $function->setAttribute('repositoryId', $repository->getId()); + $function->setAttribute('repositoryInternalId', $repository->getInternalId()); + } + + $function = $dbForProject->updateDocument('functions', $function->getId(), $function); + + // Redeploy vcs logic + if (!empty($providerRepositoryId)) { + $redeployVcs($request, $function, $project, $installation, $dbForProject, $template, $github); + } + + $functionsDomain = App::getEnv('_APP_DOMAIN_FUNCTIONS', ''); + if (!empty($functionsDomain)) { + $ruleId = ID::unique(); + $routeSubdomain = ID::unique(); + $domain = "{$routeSubdomain}.{$functionsDomain}"; + + $rule = Authorization::skip( + fn () => $dbForConsole->createDocument('rules', new Document([ + '$id' => $ruleId, + 'projectId' => $project->getId(), + 'projectInternalId' => $project->getInternalId(), + 'domain' => $domain, + 'resourceType' => 'function', + 'resourceId' => $function->getId(), + 'resourceInternalId' => $function->getInternalId(), + 'status' => 'verified', + 'certificateId' => '', + ])) + ); + + /** Trigger Webhook */ + $ruleModel = new Rule(); + $ruleCreate = new Event(Event::WEBHOOK_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME); + $ruleCreate + ->setProject($project) + ->setEvent('rules.[ruleId].create') + ->setParam('ruleId', $rule->getId()) + ->setPayload($rule->getArrayCopy(array_keys($ruleModel->getRules()))) + ->trigger(); + + /** Trigger Functions */ + $ruleCreate + ->setClass(Event::FUNCTIONS_CLASS_NAME) + ->setQueue(Event::FUNCTIONS_QUEUE_NAME) + ->trigger(); + + /** Trigger realtime event */ + $allEvents = Event::generateEvents('rules.[ruleId].create', [ + 'ruleId' => $rule->getId(), + ]); + $target = Realtime::fromPayload( + // Pass first, most verbose event pattern + event: $allEvents[0], + payload: $rule, + project: $project + ); + Realtime::send( + projectId: 'console', + payload: $rule->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'] + ); + Realtime::send( + projectId: $project->getId(), + payload: $rule->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'] + ); + } $eventsInstance->setParam('functionId', $function->getId()); @@ -138,7 +356,9 @@ App::get('/v1/functions') } // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -233,66 +453,92 @@ App::get('/v1/functions/:functionId/usage') throw new Exception(Exception::FUNCTION_NOT_FOUND); } - $periods = Config::getParam('usage', []); - $stats = $usage = []; - $days = $periods[$range]; - $metrics = [ - str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $function->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS), - str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $function->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), - str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS), - str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE), - str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), - str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), - str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), - ]; - - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { - foreach ($metrics as $metric) { - $limit = $days['limit']; - $period = $days['period']; - $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), - Query::equal('metric', [$metric]), - Query::limit($limit), - Query::orderDesc('time'), - ]); - $stats[$metric] = []; - foreach ($results as $result) { - $stats[$metric][$result->getAttribute('time')] = [ - 'value' => $result->getAttribute('value'), - ]; - } - } - }); - - $format = match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }; - - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], ]; - } - } - $response->dynamic(new Document([ - 'range' => $range, - 'deploymentsTotal' => $usage[$metrics[0]], - 'deploymentsStorage' => $usage[$metrics[1]], - 'buildsTotal' => $usage[$metrics[2]], - 'buildsStorage' => $usage[$metrics[3]], - 'buildsTime' => $usage[$metrics[4]], - 'executionsTotal' => $usage[$metrics[5]], - 'executionsTime' => $usage[$metrics[6]], - ]), Response::MODEL_USAGE_FUNCTION); + $metrics = [ + "executions.$functionId.compute.total", + "executions.$functionId.compute.success", + "executions.$functionId.compute.failure", + "executions.$functionId.compute.time", + "builds.$functionId.compute.total", + "builds.$functionId.compute.success", + "builds.$functionId.compute.failure", + "builds.$functionId.compute.time", + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + $stats[$metric] = array_reverse($stats[$metric]); + } + }); + + $usage = new Document([ + 'range' => $range, + 'executionsTotal' => $stats["executions.$functionId.compute.total"] ?? [], + 'executionsFailure' => $stats["executions.$functionId.compute.failure"] ?? [], + 'executionsSuccesse' => $stats["executions.$functionId.compute.success"] ?? [], + 'executionsTime' => $stats["executions.$functionId.compute.time"] ?? [], + 'buildsTotal' => $stats["builds.$functionId.compute.total"] ?? [], + 'buildsFailure' => $stats["builds.$functionId.compute.failure"] ?? [], + 'buildsSuccess' => $stats["builds.$functionId.compute.success"] ?? [], + 'buildsTime' => $stats["builds.$functionId.compute.time" ?? []] + ]); + } + + $response->dynamic($usage, Response::MODEL_USAGE_FUNCTION); }); App::get('/v1/functions/usage') @@ -310,67 +556,92 @@ App::get('/v1/functions/usage') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { - $periods = Config::getParam('usage', []); - $stats = $usage = []; - $days = $periods[$range]; - $metrics = [ - METRIC_FUNCTIONS, - METRIC_DEPLOYMENTS, - METRIC_DEPLOYMENTS_STORAGE, - METRIC_BUILDS, - METRIC_BUILDS_STORAGE, - METRIC_BUILDS_COMPUTE, - METRIC_EXECUTIONS, - METRIC_EXECUTIONS_COMPUTE, - ]; - - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { - foreach ($metrics as $metric) { - $limit = $days['limit']; - $period = $days['period']; - $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), - Query::equal('metric', [$metric]), - Query::limit($limit), - Query::orderDesc('time'), - ]); - $stats[$metric] = []; - foreach ($results as $result) { - $stats[$metric][$result->getAttribute('time')] = [ - 'value' => $result->getAttribute('value'), - ]; - } - } - }); - - $format = match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }; - - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], ]; + + $metrics = [ + 'executions.$all.compute.total', + 'executions.$all.compute.failure', + 'executions.$all.compute.success', + 'executions.$all.compute.time', + 'builds.$all.compute.total', + 'builds.$all.compute.failure', + 'builds.$all.compute.success', + 'builds.$all.compute.time', + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + $stats[$metric] = array_reverse($stats[$metric]); + } + }); + + $usage = new Document([ + 'range' => $range, + 'executionsTotal' => $stats[$metrics[0]] ?? [], + 'executionsFailure' => $stats[$metrics[1]] ?? [], + 'executionsSuccess' => $stats[$metrics[2]] ?? [], + 'executionsTime' => $stats[$metrics[3]] ?? [], + 'buildsTotal' => $stats[$metrics[4]] ?? [], + 'buildsFailure' => $stats[$metrics[5]] ?? [], + 'buildsSuccess' => $stats[$metrics[6]] ?? [], + 'buildsTime' => $stats[$metrics[7]] ?? [], + ]); } - } - $response->dynamic(new Document([ - 'range' => $range, - 'functionsTotal' => $usage[$metrics[0]], - 'deploymentsTotal' => $usage[$metrics[1]], - 'deploymentsStorage' => $usage[$metrics[2]], - 'buildsTotal' => $usage[$metrics[3]], - 'buildsStorage' => $usage[$metrics[4]], - 'buildsTime' => $usage[$metrics[5]], - 'executionsTotal' => $usage[$metrics[6]], - 'executionsTime' => $usage[$metrics[7]], - ]), Response::MODEL_USAGE_FUNCTIONS); + + $response->dynamic($usage, Response::MODEL_USAGE_FUNCTIONS); }); App::put('/v1/functions/:functionId') @@ -389,18 +660,29 @@ App::put('/v1/functions/:functionId') ->label('sdk.response.model', Response::MODEL_FUNCTION) ->param('functionId', '', new UID(), 'Function ID.') ->param('name', '', new Text(128), 'Function name. Max length: 128 chars.') - ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) + ->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.') + ->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true) ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true) ->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true) - ->param('enabled', true, new Boolean(), 'Is function enabled?', true) + ->param('enabled', true, new Boolean(), 'Is function enabled? When set to \'disabled\', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.', true) + ->param('logging', true, new Boolean(), 'Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.', true) + ->param('entrypoint', '', new Text(1028, 0), 'Entrypoint File. This path is relative to the "providerRootDirectory".', true) + ->param('commands', '', new Text(8192, 0), 'Build Commands.', true) + ->param('installationId', '', new Text(128, 0), 'Appwrite Installation ID for VCS (Version Controle System) deployment.', true) + ->param('providerRepositoryId', '', new Text(128, 0), 'Repository ID of the repo linked to the function', true) + ->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function', true) + ->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.', true) + ->param('providerRootDirectory', '', new Text(128, 0), 'Path to function code in the linked repo.', true) + ->inject('request') ->inject('response') ->inject('dbForProject') ->inject('project') - ->inject('user') ->inject('events') ->inject('dbForConsole') - ->action(function (string $functionId, string $name, array $execute, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance, Database $dbForConsole) { + ->inject('gitHub') + ->action(function (string $functionId, string $name, string $runtime, array $execute, array $events, string $schedule, int $timeout, bool $enabled, bool $logging, string $entrypoint, string $commands, string $installationId, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, Request $request, Response $response, Database $dbForProject, Document $project, Event $eventsInstance, Database $dbForConsole, GitHub $github) use ($redeployVcs) { + // TODO: If only branch changes, re-deploy $function = $dbForProject->getDocument('functions', $functionId); @@ -408,18 +690,122 @@ App::put('/v1/functions/:functionId') throw new Exception(Exception::FUNCTION_NOT_FOUND); } + $installation = $dbForConsole->getDocument('installations', $installationId); + + if (!empty($installationId) && $installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + if (!empty($providerRepositoryId) && (empty($installationId) || empty($providerBranch))) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'When connecting to VCS (Version Control System), you need to provide "installationId" and "providerBranch".'); + } + + if ($function->isEmpty()) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } + $enabled ??= $function->getAttribute('enabled', true); + $repositoryId = $function->getAttribute('repositoryId', ''); + $repositoryInternalId = $function->getAttribute('repositoryInternalId', ''); + + if (empty($entrypoint)) { + $entrypoint = $function->getAttribute('entrypoint', ''); + } + + $isConnected = !empty($function->getAttribute('providerRepositoryId', '')); + + // Git disconnect logic + if ($isConnected && empty($providerRepositoryId)) { + $repositories = $dbForConsole->find('repositories', [ + Query::equal('projectInternalId', [$project->getInternalId()]), + Query::equal('resourceInternalId', [$function->getInternalId()]), + Query::equal('resourceType', ['function']), + Query::limit(100), + ]); + + foreach ($repositories as $repository) { + $dbForConsole->deleteDocument('repositories', $repository->getId()); + } + + $providerRepositoryId = ''; + $installationId = ''; + $providerBranch = ''; + $providerRootDirectory = ''; + $providerSilentMode = true; + $repositoryId = ''; + $repositoryInternalId = ''; + } + + // Git connect logic + if (!$isConnected && !empty($providerRepositoryId)) { + $teamId = $project->getAttribute('teamId', ''); + + $repository = $dbForConsole->createDocument('repositories', new Document([ + '$id' => ID::unique(), + '$permissions' => [ + Permission::read(Role::team(ID::custom($teamId))), + Permission::update(Role::team(ID::custom($teamId), 'owner')), + Permission::update(Role::team(ID::custom($teamId), 'developer')), + Permission::delete(Role::team(ID::custom($teamId), 'owner')), + Permission::delete(Role::team(ID::custom($teamId), 'developer')), + ], + 'installationId' => $installation->getId(), + 'installationInternalId' => $installation->getInternalId(), + 'projectId' => $project->getId(), + 'projectInternalId' => $project->getInternalId(), + 'providerRepositoryId' => $providerRepositoryId, + 'resourceId' => $function->getId(), + 'resourceInternalId' => $function->getInternalId(), + 'resourceType' => 'function', + 'providerPullRequestIds' => [] + ])); + + $repositoryId = $repository->getId(); + $repositoryInternalId = $repository->getInternalId(); + } + + $live = true; + + if ( + $function->getAttribute('name') !== $name || + $function->getAttribute('entrypoint') !== $entrypoint || + $function->getAttribute('commands') !== $commands || + $function->getAttribute('providerRootDirectory') !== $providerRootDirectory || + $function->getAttribute('runtime') !== $runtime + ) { + $live = false; + } + $function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [ 'execute' => $execute, 'name' => $name, + 'runtime' => $runtime, 'events' => $events, 'schedule' => $schedule, 'timeout' => $timeout, 'enabled' => $enabled, - 'search' => implode(' ', [$functionId, $name, $function->getAttribute('runtime')]), + 'live' => $live, + 'logging' => $logging, + 'entrypoint' => $entrypoint, + 'commands' => $commands, + 'installationId' => $installation->getId(), + 'installationInternalId' => $installation->getInternalId(), + 'providerRepositoryId' => $providerRepositoryId, + 'repositoryId' => $repositoryId, + 'repositoryInternalId' => $repositoryInternalId, + 'providerBranch' => $providerBranch, + 'providerRootDirectory' => $providerRootDirectory, + 'providerSilentMode' => $providerSilentMode, + 'search' => implode(' ', [$functionId, $name, $runtime]), ]))); + // Redeploy logic + if (!$isConnected && !empty($providerRepositoryId)) { + $redeployVcs($request, $function, $project, $installation, $dbForProject, new Document(), $github); + } + + // Inform scheduler if function is still active $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) @@ -432,6 +818,93 @@ App::put('/v1/functions/:functionId') $response->dynamic($function, Response::MODEL_FUNCTION); }); +App::get('/v1/functions/:functionId/deployments/:deploymentId/download') + ->groups(['api', 'functions']) + ->desc('Download Deployment') + ->label('scope', 'functions.read') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'functions') + ->label('sdk.method', 'downloadDeployment') + ->label('sdk.description', '/docs/references/functions/download-deployment.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', '*/*') + ->label('sdk.methodType', 'location') + ->param('functionId', '', new UID(), 'Function ID.') + ->param('deploymentId', '', new UID(), 'Deployment ID.') + ->inject('response') + ->inject('request') + ->inject('dbForProject') + ->inject('deviceFunctions') + ->action(function (string $functionId, string $deploymentId, Response $response, Request $request, Database $dbForProject, Device $deviceFunctions) { + + $function = $dbForProject->getDocument('functions', $functionId); + if ($function->isEmpty()) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } + + $deployment = $dbForProject->getDocument('deployments', $deploymentId); + if ($deployment->isEmpty()) { + throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); + } + + if ($deployment->getAttribute('resourceId') !== $function->getId()) { + throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); + } + + $path = $deployment->getAttribute('path', ''); + if (!$deviceFunctions->exists($path)) { + throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); + } + + $response + ->setContentType('application/gzip') + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('X-Peak', \memory_get_peak_usage()) + ->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '.tar.gz"') + ; + + $size = $deviceFunctions->getFileSize($path); + $rangeHeader = $request->getHeader('range'); + + if (!empty($rangeHeader)) { + $start = $request->getRangeStart(); + $end = $request->getRangeEnd(); + $unit = $request->getRangeUnit(); + + if ($end === null) { + $end = min(($start + MAX_OUTPUT_CHUNK_SIZE - 1), ($size - 1)); + } + + if ($unit !== 'bytes' || $start >= $end || $end >= $size) { + throw new Exception(Exception::STORAGE_INVALID_RANGE); + } + + $response + ->addHeader('Accept-Ranges', 'bytes') + ->addHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $size) + ->addHeader('Content-Length', $end - $start + 1) + ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); + + $response->send($deviceFunctions->read($path, $start, ($end - $start + 1))); + } + + if ($size > APP_STORAGE_READ_BUFFER) { + $response->addHeader('Content-Length', $deviceFunctions->getFileSize($path)); + for ($i = 0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) { + $response->chunk( + $deviceFunctions->read( + $path, + ($i * MAX_OUTPUT_CHUNK_SIZE), + min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE)) + ), + (($i + 1) * MAX_OUTPUT_CHUNK_SIZE) >= $size + ); + } + } else { + $response->send($deviceFunctions->read($path)); + } + }); + App::patch('/v1/functions/:functionId/deployments/:deploymentId') ->groups(['api', 'functions']) ->desc('Update Function Deployment') @@ -480,6 +953,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') 'deployment' => $deployment->getId(), ]))); + // Inform scheduler if function is still active $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) @@ -526,6 +1000,7 @@ App::delete('/v1/functions/:functionId') throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove function from DB'); } + // Inform scheduler to no longer run function $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) @@ -558,7 +1033,8 @@ App::post('/v1/functions/:functionId/deployments') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DEPLOYMENT) ->param('functionId', '', new UID(), 'Function ID.') - ->param('entrypoint', '', new Text('1028'), 'Entrypoint File.') + ->param('entrypoint', null, new Text(1028), 'Entrypoint File.', true) + ->param('commands', null, new Text(8192, 0), 'Build Commands.', true) ->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', skipValidation: true) ->param('activate', false, new Boolean(true), 'Automatically activate the deployment when it is finished building.') ->inject('request') @@ -568,8 +1044,8 @@ App::post('/v1/functions/:functionId/deployments') ->inject('project') ->inject('deviceFunctions') ->inject('deviceLocal') - ->inject('dbForConsole') - ->action(function (string $functionId, string $entrypoint, mixed $code, bool $activate, Request $request, Response $response, Database $dbForProject, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal, Database $dbForConsole) { + ->action(function (string $functionId, ?string $entrypoint, ?string $commands, mixed $code, mixed $activate, Request $request, Response $response, Database $dbForProject, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal) { + $activate = filter_var($activate, FILTER_VALIDATE_BOOLEAN); $function = $dbForProject->getDocument('functions', $functionId); @@ -577,6 +1053,20 @@ App::post('/v1/functions/:functionId/deployments') throw new Exception(Exception::FUNCTION_NOT_FOUND); } + if ($entrypoint === null) { + $entrypoint = $function->getAttribute('entrypoint', ''); + } + + if ($commands === null) { + $commands = $function->getAttribute('entrypoint', ''); + } + + $commands = $function->getAttribute('commands', ''); + + if (empty($entrypoint)) { + throw new Exception(Exception::FUNCTION_ENTRYPOINT_MISSING); + } + $file = $request->getFiles('code'); // GraphQL multipart spec adds files with index keys @@ -687,11 +1177,13 @@ App::post('/v1/functions/:functionId/deployments') 'resourceType' => 'functions', 'buildInternalId' => '', 'entrypoint' => $entrypoint, + 'commands' => $commands, 'path' => $path, 'size' => $fileSize, 'search' => implode(' ', [$deploymentId, $entrypoint]), 'activate' => $activate, 'metadata' => $metadata, + 'type' => 'manual' ])); } else { $deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment->setAttribute('size', $fileSize)->setAttribute('metadata', $metadata)); @@ -719,6 +1211,7 @@ App::post('/v1/functions/:functionId/deployments') 'resourceType' => 'functions', 'buildInternalId' => '', 'entrypoint' => $entrypoint, + 'commands' => $commands, 'path' => $path, 'size' => $fileSize, 'chunksTotal' => $chunks, @@ -726,6 +1219,7 @@ App::post('/v1/functions/:functionId/deployments') 'search' => implode(' ', [$deploymentId, $entrypoint]), 'activate' => $activate, 'metadata' => $metadata, + 'type' => 'manual' ])); } else { $deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment->setAttribute('chunksUploaded', $chunksUploaded)->setAttribute('metadata', $metadata)); @@ -778,7 +1272,9 @@ App::get('/v1/functions/:functionId/deployments') $queries[] = Query::equal('resourceType', ['functions']); // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -800,9 +1296,9 @@ App::get('/v1/functions/:functionId/deployments') foreach ($results as $result) { $build = $dbForProject->getDocument('builds', $result->getAttribute('buildId', '')); $result->setAttribute('status', $build->getAttribute('status', 'processing')); - $result->setAttribute('buildStderr', $build->getAttribute('stderr', '')); - $result->setAttribute('buildStdout', $build->getAttribute('stdout', '')); + $result->setAttribute('buildLogs', $build->getAttribute('logs', '')); $result->setAttribute('buildTime', $build->getAttribute('duration', 0)); + $result->setAttribute('size', $result->getAttribute('size', 0) + $build->getAttribute('size', 0)); } $response->dynamic(new Document([ @@ -845,9 +1341,10 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId') } $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')); - $deployment->setAttribute('status', $build->getAttribute('status', 'processing')); - $deployment->setAttribute('buildStderr', $build->getAttribute('stderr', '')); - $deployment->setAttribute('buildStdout', $build->getAttribute('stdout', '')); + $deployment->setAttribute('status', $build->getAttribute('status', 'waiting')); + $deployment->setAttribute('buildLogs', $build->getAttribute('logs', '')); + $deployment->setAttribute('buildTime', $build->getAttribute('duration', 0)); + $deployment->setAttribute('size', $deployment->getAttribute('size', 0) + $build->getAttribute('size', 0)); $response->dynamic($deployment, Response::MODEL_DEPLOYMENT); }); @@ -888,9 +1385,13 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); } - if ($deviceFunctions->delete($deployment->getAttribute('path', ''))) { - if (!$dbForProject->deleteDocument('deployments', $deployment->getId())) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove deployment from DB'); + if (!$dbForProject->deleteDocument('deployments', $deployment->getId())) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove deployment from DB'); + } + + if (!empty($deployment->getAttribute('path', ''))) { + if (!($deviceFunctions->delete($deployment->getAttribute('path', '')))) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove deployment from storage'); } } @@ -928,19 +1429,23 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') ->param('functionId', '', new UID(), 'Function ID.') ->param('deploymentId', '', new UID(), 'Deployment ID.') ->param('buildId', '', new UID(), 'Build unique ID.') + ->inject('request') ->inject('response') ->inject('dbForProject') + ->inject('dbForConsole') ->inject('project') + ->inject('gitHub') ->inject('events') - ->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) { + ->action(function (string $functionId, string $deploymentId, string $buildId, Request $request, Response $response, Database $dbForProject, Database $dbForConsole, Document $project, GitHub $github, Event $events) use ($redeployVcs) { $function = $dbForProject->getDocument('functions', $functionId); - $deployment = $dbForProject->getDocument('deployments', $deploymentId); if ($function->isEmpty()) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } + $deployment = $dbForProject->getDocument('deployments', $deploymentId); + if ($deployment->isEmpty()) { throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); } @@ -951,23 +1456,30 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') throw new Exception(Exception::BUILD_NOT_FOUND); } - if ($build->getAttribute('status') !== 'failed') { - throw new Exception(Exception::BUILD_IN_PROGRESS, 'Build not failed'); - } + $deploymentId = ID::unique(); - $events - ->setParam('functionId', $function->getId()) - ->setParam('deploymentId', $deployment->getId()); + $deployment = $dbForProject->createDocument('deployments', $deployment->setAttributes([ + '$id' => $deploymentId, + 'buildId' => '', + 'buildInternalId' => '', + 'entrypoint' => $function->getAttribute('entrypoint'), + 'commands' => $function->getAttribute('commands', ''), + 'search' => implode(' ', [$deploymentId, $function->getAttribute('entrypoint')]), + ])); - // Retry the build $buildEvent = new Build(); + $buildEvent - ->setType(BUILD_TYPE_RETRY) + ->setType(BUILD_TYPE_DEPLOYMENT) ->setResource($function) ->setDeployment($deployment) ->setProject($project) ->trigger(); + $events + ->setParam('functionId', $function->getId()) + ->setParam('deploymentId', $deployment->getId()); + $response->noContent(); }); @@ -983,28 +1495,30 @@ App::post('/v1/functions/:functionId/executions') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_EXECUTION) - ->label('abuse-key', 'ip:{ip},userId:{userId}') - ->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT) - ->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT) ->param('functionId', '', new UID(), 'Function ID.') - ->param('data', '', new Text(8192), 'String of custom data to send to function.', true) + ->param('body', '', new Text(8192, 0), 'HTTP body of execution. Default value is empty string.', true) ->param('async', false, new Boolean(), '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) + ->param('headers', [], new Assoc(), 'HTTP headers of execution. Defaults to empty.', true) ->inject('response') ->inject('project') ->inject('dbForProject') ->inject('user') ->inject('events') + ->inject('usage') ->inject('mode') ->inject('queueForFunctions') - ->inject('queueForUsage') - ->action(function (string $functionId, string $data, bool $async, Response $response, Document $project, Database $dbForProject, Document $user, Event $events, string $mode, Func $queueForFunctions, Usage $queueForUsage) { + ->inject('geodb') + ->action(function (string $functionId, string $body, bool $async, string $path, string $method, array $headers, Response $response, Document $project, Database $dbForProject, Document $user, Event $events, Stats $usage, string $mode, Func $queueForFunctions, Reader $geodb) { $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty() || !$function->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); - } + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); } $runtimes = Config::getParam('runtimes', []); @@ -1041,25 +1555,6 @@ App::post('/v1/functions/:functionId/executions') throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription()); } - $executionId = ID::unique(); - - /** @var Document $execution */ - $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', new Document([ - '$id' => $executionId, - '$permissions' => !$user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [], - 'functionInternalId' => $function->getInternalId(), - 'functionId' => $function->getId(), - 'deploymentInternalId' => $deployment->getInternalId(), - 'deploymentId' => $deployment->getId(), - 'trigger' => 'http', // http / schedule / event - 'status' => $async ? 'waiting' : 'processing', // waiting / processing / completed / failed - 'statusCode' => 0, - 'response' => '', - 'stderr' => '', - 'duration' => 0.0, - 'search' => implode(' ', [$functionId, $executionId]), - ]))); - $jwt = ''; // initialize if (!$user->isEmpty()) { // If userId exists, generate a JWT for function $sessions = $user->getAttribute('sessions', []); @@ -1081,17 +1576,74 @@ App::post('/v1/functions/:functionId/executions') } } + $headers['x-appwrite-trigger'] = 'http'; + $headers['x-appwrite-user-id'] = $user->getId() ?? ''; + $headers['x-appwrite-user-jwt'] = $jwt ?? ''; + $headers['x-appwrite-country-code'] = ''; + $headers['x-appwrite-continent-code'] = ''; + $headers['x-appwrite-continent-eu'] = 'false'; + + $ip = $headers['x-real-ip'] ?? ''; + if (!empty($ip)) { + $record = $geodb->get($ip); + + if ($record) { + $eu = Config::getParam('locale-eu'); + + $headers['x-appwrite-country-code'] = $record['country']['iso_code'] ?? ''; + $headers['x-appwrite-continent-code'] = $record['continent']['code'] ?? ''; + $headers['x-appwrite-continent-eu'] = (\in_array($record['country']['iso_code'], $eu)) ? 'true' : 'false'; + } + } + + $headersFiltered = []; + foreach ($headers as $key => $value) { + if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_REQUEST)) { + $headersFiltered[] = ['name' => $key, 'value' => $value]; + } + } + + $executionId = ID::unique(); + + $execution = new Document([ + '$id' => $executionId, + '$permissions' => !$user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [], + 'functionInternalId' => $function->getInternalId(), + 'functionId' => $function->getId(), + 'deploymentInternalId' => $deployment->getInternalId(), + 'deploymentId' => $deployment->getId(), + 'trigger' => 'http', // http / schedule / event + 'status' => $async ? 'waiting' : 'processing', // waiting / processing / completed / failed + 'responseStatusCode' => 0, + 'responseHeaders' => [], + 'requestPath' => $path, + 'requestMethod' => $method, + 'requestHeaders' => $headersFiltered, + 'errors' => '', + 'logs' => '', + 'duration' => 0.0, + 'search' => implode(' ', [$functionId, $executionId]), + ]); + $events ->setParam('functionId', $function->getId()) ->setParam('executionId', $execution->getId()) ->setContext('function', $function); if ($async) { + if ($function->getAttribute('logging')) { + /** @var Document $execution */ + $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); + } + $queueForFunctions ->setType('http') ->setExecution($execution) ->setFunction($function) - ->setData($data) + ->setBody($body) + ->setHeaders($headers) + ->setPath($path) + ->setMethod($method) ->setJWT($jwt) ->setProject($project) ->setUser($user) @@ -1102,73 +1654,107 @@ App::post('/v1/functions/:functionId/executions') ->dynamic($execution, Response::MODEL_EXECUTION); } - $vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { + $durationStart = \microtime(true); + + $vars = []; + + // Shared vars + foreach ($project->getAttribute('variables', []) as $var) { + $vars[$var->getAttribute('key')] = $var->getAttribute('value', ''); + } + + // Function vars + $vars = \array_merge($vars, array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { $carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? ''; return $carry; - }, []); + }, [])); + // Appwrite vars $vars = \array_merge($vars, [ - 'APPWRITE_FUNCTION_ID' => $function->getId(), + 'APPWRITE_FUNCTION_ID' => $functionId, 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'), 'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(), 'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(), - 'APPWRITE_FUNCTION_TRIGGER' => 'http', 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '', 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '', - 'APPWRITE_FUNCTION_DATA' => $data ?? '', - 'APPWRITE_FUNCTION_USER_ID' => $user->getId() ?? '', - 'APPWRITE_FUNCTION_JWT' => $jwt ?? '', ]); /** Execute function */ $executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST')); try { + $command = $runtime['startCommand']; $executionResponse = $executor->createExecution( projectId: $project->getId(), deploymentId: $deployment->getId(), - payload: $data, + body: \strlen($body) > 0 ? $body : null, variables: $vars, timeout: $function->getAttribute('timeout', 0), image: $runtime['image'], - source: $build->getAttribute('outputPath', ''), + source: $build->getAttribute('path', ''), entrypoint: $deployment->getAttribute('entrypoint', ''), + version: $function->getAttribute('version'), + path: $path, + method: $method, + headers: $headers, + runtimeEntrypoint: 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $command . '"' ); + $headersFiltered = []; + foreach ($executionResponse['headers'] as $key => $value) { + if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) { + $headersFiltered[] = ['name' => $key, 'value' => $value]; + } + } + /** Update execution status */ - $execution->setAttribute('status', $executionResponse['status']); - $execution->setAttribute('statusCode', $executionResponse['statusCode']); - $execution->setAttribute('response', $executionResponse['response']); - $execution->setAttribute('stdout', $executionResponse['stdout']); - $execution->setAttribute('stderr', $executionResponse['stderr']); + $status = $executionResponse['statusCode'] >= 400 ? 'failed' : 'completed'; + $execution->setAttribute('status', $status); + $execution->setAttribute('responseStatusCode', $executionResponse['statusCode']); + $execution->setAttribute('responseHeaders', $headersFiltered); + $execution->setAttribute('logs', $executionResponse['logs']); + $execution->setAttribute('errors', $executionResponse['errors']); $execution->setAttribute('duration', $executionResponse['duration']); - /** - * Sync execution compute usage from - */ - $queueForUsage - ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($executionResponse['duration'] * 1000))// per project - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($executionResponse['duration'] * 1000))// per function - ; } catch (\Throwable $th) { - $interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt())); + $durationEnd = \microtime(true); + $execution - ->setAttribute('duration', (float)$interval->format('%s.%f')) + ->setAttribute('duration', $durationEnd - $durationStart) ->setAttribute('status', 'failed') - ->setAttribute('statusCode', $th->getCode()) - ->setAttribute('stderr', $th->getMessage()); + ->setAttribute('responseStatusCode', 500) + ->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode()); Console::error($th->getMessage()); } - Authorization::skip(fn () => $dbForProject->updateDocument('executions', $executionId, $execution)); + if ($function->getAttribute('logging')) { + /** @var Document $execution */ + $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); + } + + // TODO revise this later using route label + $usage + ->setParam('functionId', $function->getId()) + ->setParam('executions.{scope}.compute', 1) + ->setParam('executionStatus', $execution->getAttribute('status', '')) + ->setParam('executionTime', $execution->getAttribute('duration')); // ms + $roles = Authorization::getRoles(); $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); if (!$isPrivilegedUser && !$isAppUser) { - $execution->setAttribute('stdout', ''); - $execution->setAttribute('stderr', ''); + $execution->setAttribute('logs', ''); + $execution->setAttribute('errors', ''); } + $headers = []; + foreach (($executionResponse['headers'] ?? []) as $key => $value) { + $headers[] = ['name' => $key, 'value' => $value]; + } + + $execution->setAttribute('responseBody', $executionResponse['body'] ?? ''); + $execution->setAttribute('responseHeaders', $headers); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($execution, Response::MODEL_EXECUTION); @@ -1192,13 +1778,13 @@ App::get('/v1/functions/:functionId/executions') ->inject('dbForProject') ->inject('mode') ->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { - $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty() || !$function->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); - } + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); } $queries = Query::parseQueries($queries); @@ -1211,7 +1797,9 @@ App::get('/v1/functions/:functionId/executions') $queries[] = Query::equal('functionId', [$function->getId()]); // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -1235,8 +1823,8 @@ App::get('/v1/functions/:functionId/executions') $isAppUser = Auth::isAppUser($roles); if (!$isPrivilegedUser && !$isAppUser) { $results = array_map(function ($execution) { - $execution->setAttribute('stdout', ''); - $execution->setAttribute('stderr', ''); + $execution->setAttribute('logs', ''); + $execution->setAttribute('errors', ''); return $execution; }, $results); } @@ -1264,13 +1852,13 @@ App::get('/v1/functions/:functionId/executions/:executionId') ->inject('dbForProject') ->inject('mode') ->action(function (string $functionId, string $executionId, Response $response, Database $dbForProject, string $mode) { - $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty() || !$function->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); - } + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); } $execution = $dbForProject->getDocument('executions', $executionId); @@ -1287,8 +1875,8 @@ App::get('/v1/functions/:functionId/executions/:executionId') $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); if (!$isPrivilegedUser && !$isAppUser) { - $execution->setAttribute('stdout', ''); - $execution->setAttribute('stderr', ''); + $execution->setAttribute('logs', ''); + $execution->setAttribute('errors', ''); } $response->dynamic($execution, Response::MODEL_EXECUTION); @@ -1312,10 +1900,11 @@ App::post('/v1/functions/:functionId/variables') ->param('functionId', '', new UID(), 'Function unique ID.', false) ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false) ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false) + ->inject('project') ->inject('response') ->inject('dbForProject') ->inject('dbForConsole') - ->action(function (string $functionId, string $key, string $value, Response $response, Database $dbForProject, Database $dbForConsole) { + ->action(function (string $functionId, string $key, string $value, Document $project, Response $response, Database $dbForProject, Database $dbForConsole) { $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -1331,11 +1920,12 @@ App::post('/v1/functions/:functionId/variables') Permission::update(Role::any()), Permission::delete(Role::any()), ], - 'functionInternalId' => $function->getInternalId(), - 'functionId' => $function->getId(), + 'resourceInternalId' => $function->getInternalId(), + 'resourceId' => $function->getId(), + 'resourceType' => 'function', 'key' => $key, 'value' => $value, - 'search' => implode(' ', [$variableId, $function->getId(), $key]), + 'search' => implode(' ', [$variableId, $function->getId(), $key, 'function']), ]); try { @@ -1343,7 +1933,11 @@ App::post('/v1/functions/:functionId/variables') } catch (DuplicateException $th) { throw new Exception(Exception::VARIABLE_ALREADY_EXISTS); } + $dbForConsole->deleteCachedDocument('projects', $project->getId()); + $dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false)); + + // Inform scheduler to pull the latest changes $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) @@ -1353,13 +1947,6 @@ App::post('/v1/functions/:functionId/variables') $dbForProject->deleteCachedDocument('functions', $function->getId()); - $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); - $schedule - ->setAttribute('resourceUpdatedAt', DateTime::now()) - ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); - Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); - $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($variable, Response::MODEL_VARIABLE); @@ -1414,10 +2001,15 @@ App::get('/v1/functions/:functionId/variables/:variableId') throw new Exception(Exception::FUNCTION_NOT_FOUND); } - $variable = $dbForProject->findOne('variables', [ - Query::equal('$id', [$variableId]), - Query::equal('functionInternalId', [$function->getInternalId()]), - ]); + $variable = $dbForProject->getDocument('variables', $variableId); + if ( + $variable === false || + $variable->isEmpty() || + $variable->getAttribute('resourceInternalId') !== $function->getInternalId() || + $variable->getAttribute('resourceType') !== 'function' + ) { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } if ($variable === false || $variable->isEmpty()) { throw new Exception(Exception::VARIABLE_NOT_FOUND); @@ -1443,10 +2035,11 @@ App::put('/v1/functions/:functionId/variables/:variableId') ->param('variableId', '', new UID(), 'Variable unique ID.', false) ->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false) ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true) + ->inject('project') ->inject('response') ->inject('dbForProject') ->inject('dbForConsole') - ->action(function (string $functionId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject, Database $dbForConsole) { + ->action(function (string $functionId, string $variableId, string $key, ?string $value, Document $project, Response $response, Database $dbForProject, Database $dbForConsole) { $function = $dbForProject->getDocument('functions', $functionId); @@ -1454,10 +2047,10 @@ App::put('/v1/functions/:functionId/variables/:variableId') throw new Exception(Exception::FUNCTION_NOT_FOUND); } - $variable = $dbForProject->findOne('variables', [ - Query::equal('$id', [$variableId]), - Query::equal('functionInternalId', [$function->getInternalId()]), - ]); + $variable = $dbForProject->getDocument('variables', $variableId); + if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceInternalId') !== $function->getInternalId() || $variable->getAttribute('resourceType') !== 'function') { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } if ($variable === false || $variable->isEmpty()) { throw new Exception(Exception::VARIABLE_NOT_FOUND); @@ -1466,15 +2059,18 @@ App::put('/v1/functions/:functionId/variables/:variableId') $variable ->setAttribute('key', $key) ->setAttribute('value', $value ?? $variable->getAttribute('value')) - ->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key])) - ; + ->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key, 'function'])); try { $dbForProject->updateDocument('variables', $variable->getId(), $variable); } catch (DuplicateException $th) { throw new Exception(Exception::VARIABLE_ALREADY_EXISTS); } + $dbForConsole->deleteCachedDocument('projects', $project->getId()); + $dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false)); + + // Inform scheduler to pull the latest changes $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) @@ -1484,13 +2080,6 @@ App::put('/v1/functions/:functionId/variables/:variableId') $dbForProject->deleteCachedDocument('functions', $function->getId()); - $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); - $schedule - ->setAttribute('resourceUpdatedAt', DateTime::now()) - ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); - Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); - $response->dynamic($variable, Response::MODEL_VARIABLE); }); @@ -1508,20 +2097,21 @@ App::delete('/v1/functions/:functionId/variables/:variableId') ->label('sdk.response.model', Response::MODEL_NONE) ->param('functionId', '', new UID(), 'Function unique ID.', false) ->param('variableId', '', new UID(), 'Variable unique ID.', false) + ->inject('project') ->inject('response') ->inject('dbForProject') ->inject('dbForConsole') - ->action(function (string $functionId, string $variableId, Response $response, Database $dbForProject, Database $dbForConsole) { + ->action(function (string $functionId, string $variableId, Document $project, Response $response, Database $dbForProject, Database $dbForConsole) { $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } - $variable = $dbForProject->findOne('variables', [ - Query::equal('$id', [$variableId]), - Query::equal('functionInternalId', [$function->getInternalId()]), - ]); + $variable = $dbForProject->getDocument('variables', $variableId); + if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceInternalId') !== $function->getInternalId() || $variable->getAttribute('resourceType') !== 'function') { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } if ($variable === false || $variable->isEmpty()) { throw new Exception(Exception::VARIABLE_NOT_FOUND); @@ -1529,6 +2119,9 @@ App::delete('/v1/functions/:functionId/variables/:variableId') $dbForProject->deleteDocument('variables', $variable->getId()); + $dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false)); + + // Inform scheduler to pull the latest changes $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); $schedule ->setAttribute('resourceUpdatedAt', DateTime::now()) @@ -1538,12 +2131,5 @@ App::delete('/v1/functions/:functionId/variables/:variableId') $dbForProject->deleteCachedDocument('functions', $function->getId()); - $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); - $schedule - ->setAttribute('resourceUpdatedAt', DateTime::now()) - ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); - Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); - $response->noContent(); }); diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php new file mode 100644 index 0000000000..83888fff2c --- /dev/null +++ b/app/controllers/api/migrations.php @@ -0,0 +1,992 @@ +groups(['api', 'migrations']) + ->desc('Migrate Appwrite Data') + ->label('scope', 'migrations.write') + ->label('event', 'migrations.[migrationId].create') + ->label('audits.event', 'migration.create') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'createAppwriteMigration') + ->label('sdk.description', '/docs/references/migrations/migration-appwrite.md') + ->label('sdk.response.code', Response::STATUS_CODE_ACCEPTED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION) + ->param('resources', [], new ArrayList(new WhiteList(Appwrite::getSupportedResources())), 'List of resources to migrate') + ->param('endpoint', '', new URL(), "Source's Appwrite Endpoint") + ->param('projectId', '', new UID(), "Source's Project ID") + ->param('apiKey', '', new Text(512), "Source's API Key") + ->inject('response') + ->inject('dbForProject') + ->inject('project') + ->inject('user') + ->inject('events') + ->action(function (array $resources, string $endpoint, string $projectId, string $apiKey, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) { + $migration = $dbForProject->createDocument('migrations', new Document([ + '$id' => ID::unique(), + 'status' => 'pending', + 'stage' => 'init', + 'source' => Appwrite::getName(), + 'credentials' => [ + 'endpoint' => $endpoint, + 'projectId' => $projectId, + 'apiKey' => $apiKey, + ], + 'resources' => $resources, + 'statusCounters' => '{}', + 'resourceData' => '{}', + 'errors' => [], + ])); + + $events->setParam('migrationId', $migration->getId()); + + // Trigger Transfer + $event = new Migration(); + $event + ->setMigration($migration) + ->setProject($project) + ->setUser($user) + ->trigger(); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($migration, Response::MODEL_MIGRATION); + }); + +App::post('/v1/migrations/firebase/oauth') + ->groups(['api', 'migrations']) + ->desc('Migrate Firebase Data (OAuth)') + ->label('scope', 'migrations.write') + ->label('event', 'migrations.[migrationId].create') + ->label('audits.event', 'migration.create') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'createFirebaseOAuthMigration') + ->label('sdk.description', '/docs/references/migrations/migration-firebase.md') + ->label('sdk.response.code', Response::STATUS_CODE_ACCEPTED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION) + ->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate') + ->param('projectId', '', new Text(65536), 'Project ID of the Firebase Project') + ->inject('response') + ->inject('dbForProject') + ->inject('dbForConsole') + ->inject('project') + ->inject('user') + ->inject('events') + ->inject('request') + ->action(function (array $resources, string $projectId, Response $response, Database $dbForProject, Database $dbForConsole, Document $project, Document $user, Event $events, Request $request) { + $firebase = new OAuth2Firebase( + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + ); + + $identity = $dbForConsole->findOne('identities', [ + Query::equal('provider', ['firebase']), + Query::equal('userInternalId', [$user->getInternalId()]), + ]); + if ($identity === false || $identity->isEmpty()) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + $accessToken = $identity->getAttribute('providerAccessToken'); + $refreshToken = $identity->getAttribute('providerRefreshToken'); + $accessTokenExpiry = $identity->getAttribute('providerAccessTokenExpiry'); + + $isExpired = new \DateTime($accessTokenExpiry) < new \DateTime('now'); + if ($isExpired) { + $firebase->refreshTokens($refreshToken); + + $accessToken = $firebase->getAccessToken(''); + $refreshToken = $firebase->getRefreshToken(''); + + $verificationId = $firebase->getUserID($accessToken); + + if (empty($verificationId)) { + throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED, 'Another request is currently refreshing OAuth token. Please try again.'); + } + + $identity = $identity + ->setAttribute('providerAccessToken', $accessToken) + ->setAttribute('providerRefreshToken', $refreshToken) + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry(''))); + + $dbForConsole->updateDocument('identities', $identity->getId(), $identity); + } + + if ($identity->getAttribute('secrets')) { + $serviceAccount = $identity->getAttribute('secrets'); + } else { + $firebase->cleanupServiceAccounts($accessToken, $projectId); + $serviceAccount = $firebase->createServiceAccount($accessToken, $projectId); + $identity = $identity + ->setAttribute('secrets', json_encode($serviceAccount)); + + $dbForConsole->updateDocument('identities', $identity->getId(), $identity); + } + + $migration = $dbForProject->createDocument('migrations', new Document([ + '$id' => ID::unique(), + 'status' => 'pending', + 'stage' => 'init', + 'source' => Firebase::getName(), + 'credentials' => [ + 'serviceAccount' => json_encode($serviceAccount), + ], + 'resources' => $resources, + 'statusCounters' => '{}', + 'resourceData' => '{}', + 'errors' => [] + ])); + + $events->setParam('migrationId', $migration->getId()); + + // Trigger Transfer + $event = new Migration(); + $event + ->setMigration($migration) + ->setProject($project) + ->setUser($user) + ->trigger(); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($migration, Response::MODEL_MIGRATION); + }); + +App::post('/v1/migrations/firebase') + ->groups(['api', 'migrations']) + ->desc('Migrate Firebase Data (Service Account)') + ->label('scope', 'migrations.write') + ->label('event', 'migrations.[migrationId].create') + ->label('audits.event', 'migration.create') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'createFirebaseMigration') + ->label('sdk.description', '/docs/references/migrations/migration-firebase.md') + ->label('sdk.response.code', Response::STATUS_CODE_ACCEPTED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION) + ->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate') + ->param('serviceAccount', '', new Text(65536), 'JSON of the Firebase service account credentials') + ->inject('response') + ->inject('dbForProject') + ->inject('project') + ->inject('user') + ->inject('events') + ->action(function (array $resources, string $serviceAccount, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) { + $migration = $dbForProject->createDocument('migrations', new Document([ + '$id' => ID::unique(), + 'status' => 'pending', + 'stage' => 'init', + 'source' => Firebase::getName(), + 'credentials' => [ + 'serviceAccount' => $serviceAccount, + ], + 'resources' => $resources, + 'statusCounters' => '{}', + 'resourceData' => '{}', + 'errors' => [], + ])); + + $events->setParam('migrationId', $migration->getId()); + + // Trigger Transfer + $event = new Migration(); + $event + ->setMigration($migration) + ->setProject($project) + ->setUser($user) + ->trigger(); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($migration, Response::MODEL_MIGRATION); + }); + +App::post('/v1/migrations/supabase') + ->groups(['api', 'migrations']) + ->desc('Migrate Supabase Data') + ->label('scope', 'migrations.write') + ->label('event', 'migrations.[migrationId].create') + ->label('audits.event', 'migration.create') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'createSupabaseMigration') + ->label('sdk.description', '/docs/references/migrations/migration-supabase.md') + ->label('sdk.response.code', Response::STATUS_CODE_ACCEPTED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION) + ->param('resources', [], new ArrayList(new WhiteList(Supabase::getSupportedResources(), true)), 'List of resources to migrate') + ->param('endpoint', '', new URL(), 'Source\'s Supabase Endpoint') + ->param('apiKey', '', new Text(512), 'Source\'s API Key') + ->param('databaseHost', '', new Text(512), 'Source\'s Database Host') + ->param('username', '', new Text(512), 'Source\'s Database Username') + ->param('password', '', new Text(512), 'Source\'s Database Password') + ->param('port', 5432, new Integer(true), 'Source\'s Database Port', true) + ->inject('response') + ->inject('dbForProject') + ->inject('project') + ->inject('user') + ->inject('events') + ->action(function (array $resources, string $endpoint, string $apiKey, string $databaseHost, string $username, string $password, int $port, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) { + $migration = $dbForProject->createDocument('migrations', new Document([ + '$id' => ID::unique(), + 'status' => 'pending', + 'stage' => 'init', + 'source' => Supabase::getName(), + 'credentials' => [ + 'endpoint' => $endpoint, + 'apiKey' => $apiKey, + 'databaseHost' => $databaseHost, + 'username' => $username, + 'password' => $password, + 'port' => $port, + ], + 'resources' => $resources, + 'statusCounters' => '{}', + 'resourceData' => '{}', + 'errors' => [], + ])); + + $events->setParam('migrationId', $migration->getId()); + + // Trigger Transfer + $event = new Migration(); + $event + ->setMigration($migration) + ->setProject($project) + ->setUser($user) + ->trigger(); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($migration, Response::MODEL_MIGRATION); + }); + +App::post('/v1/migrations/nhost') + ->groups(['api', 'migrations']) + ->desc('Migrate NHost Data') + ->label('scope', 'migrations.write') + ->label('event', 'migrations.[migrationId].create') + ->label('audits.event', 'migration.create') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'createNHostMigration') + ->label('sdk.description', '/docs/references/migrations/migration-nhost.md') + ->label('sdk.response.code', Response::STATUS_CODE_ACCEPTED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION) + ->param('resources', [], new ArrayList(new WhiteList(NHost::getSupportedResources())), 'List of resources to migrate') + ->param('subdomain', '', new Text(512), 'Source\'s Subdomain') + ->param('region', '', new Text(512), 'Source\'s Region') + ->param('adminSecret', '', new Text(512), 'Source\'s Admin Secret') + ->param('database', '', new Text(512), 'Source\'s Database Name') + ->param('username', '', new Text(512), 'Source\'s Database Username') + ->param('password', '', new Text(512), 'Source\'s Database Password') + ->param('port', 5432, new Integer(true), 'Source\'s Database Port', true) + ->inject('response') + ->inject('dbForProject') + ->inject('project') + ->inject('user') + ->inject('events') + ->action(function (array $resources, string $subdomain, string $region, string $adminSecret, string $database, string $username, string $password, int $port, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) { + $migration = $dbForProject->createDocument('migrations', new Document([ + '$id' => ID::unique(), + 'status' => 'pending', + 'stage' => 'init', + 'source' => NHost::getName(), + 'credentials' => [ + 'subdomain' => $subdomain, + 'region' => $region, + 'adminSecret' => $adminSecret, + 'database' => $database, + 'username' => $username, + 'password' => $password, + 'port' => $port, + ], + 'resources' => $resources, + 'statusCounters' => '{}', + 'resourceData' => '{}', + 'errors' => [], + ])); + + $events->setParam('migrationId', $migration->getId()); + + // Trigger Transfer + $event = new Migration(); + $event + ->setMigration($migration) + ->setProject($project) + ->setUser($user) + ->trigger(); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($migration, Response::MODEL_MIGRATION); + }); + +App::get('/v1/migrations') + ->groups(['api', 'migrations']) + ->desc('List Migrations') + ->label('scope', 'migrations.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'list') + ->label('sdk.description', '/docs/references/migrations/list-migrations.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION_LIST) + ->param('queries', [], new Migrations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Migrations::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) + ->inject('response') + ->inject('dbForProject') + ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { + $queries = Query::parseQueries($queries); + + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + + // Get cursor document if there was a cursor query + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); + $cursor = reset($cursor); + if ($cursor) { + /** @var Query $cursor */ + $migrationId = $cursor->getValue(); + $cursorDocument = $dbForProject->getDocument('migrations', $migrationId); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Migration '{$migrationId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + + $filterQueries = Query::groupByType($queries)['filters']; + + $response->dynamic(new Document([ + 'migrations' => $dbForProject->find('migrations', $queries), + 'total' => $dbForProject->count('migrations', $filterQueries, APP_LIMIT_COUNT), + ]), Response::MODEL_MIGRATION_LIST); + }); + +App::get('/v1/migrations/:migrationId') + ->groups(['api', 'migrations']) + ->desc('Get Migration') + ->label('scope', 'migrations.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'get') + ->label('sdk.description', '/docs/references/migrations/get-migration.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION) + ->param('migrationId', '', new UID(), 'Migration unique ID.') + ->inject('response') + ->inject('dbForProject') + ->action(function (string $migrationId, Response $response, Database $dbForProject) { + $migration = $dbForProject->getDocument('migrations', $migrationId); + + if ($migration->isEmpty()) { + throw new Exception(Exception::MIGRATION_NOT_FOUND); + } + + $response->dynamic($migration, Response::MODEL_MIGRATION); + }); + +App::get('/v1/migrations/appwrite/report') + ->groups(['api', 'migrations']) + ->desc('Generate a report on Appwrite Data') + ->label('scope', 'migrations.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'getAppwriteReport') + ->label('sdk.description', '/docs/references/migrations/migration-appwrite-report.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION_REPORT) + ->param('resources', [], new ArrayList(new WhiteList(Appwrite::getSupportedResources())), 'List of resources to migrate') + ->param('endpoint', '', new URL(), "Source's Appwrite Endpoint") + ->param('projectID', '', new Text(512), "Source's Project ID") + ->param('key', '', new Text(512), "Source's API Key") + ->inject('response') + ->inject('dbForProject') + ->inject('project') + ->inject('user') + ->action(function (array $resources, string $endpoint, string $projectID, string $key, Response $response) { + try { + $appwrite = new Appwrite($projectID, $endpoint, $key); + + $response + ->setStatusCode(Response::STATUS_CODE_OK) + ->dynamic(new Document($appwrite->report($resources)), Response::MODEL_MIGRATION_REPORT); + } catch (\Throwable $e) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Source Error: ' . $e->getMessage()); + } + }); + +App::get('/v1/migrations/firebase/report') + ->groups(['api', 'migrations']) + ->desc('Generate a report on Firebase Data') + ->label('scope', 'migrations.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'getFirebaseReport') + ->label('sdk.description', '/docs/references/migrations/migration-firebase-report.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION_REPORT) + ->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate') + ->param('serviceAccount', '', new Text(65536), 'JSON of the Firebase service account credentials') + ->inject('response') + ->action(function (array $resources, string $serviceAccount, Response $response) { + try { + $firebase = new Firebase(json_decode($serviceAccount, true)); + + $response + ->setStatusCode(Response::STATUS_CODE_OK) + ->dynamic(new Document($firebase->report($resources)), Response::MODEL_MIGRATION_REPORT); + } catch (\Exception $e) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Source Error: ' . $e->getMessage()); + } + }); + +App::get('/v1/migrations/firebase/report/oauth') + ->groups(['api', 'migrations']) + ->desc('Generate a report on Firebase Data using OAuth') + ->label('scope', 'migrations.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'getFirebaseReportOAuth') + ->label('sdk.description', '/docs/references/migrations/migration-firebase-report.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION_REPORT) + ->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate') + ->param('projectId', '', new Text(65536), 'Project ID') + ->inject('response') + ->inject('request') + ->inject('user') + ->inject('dbForConsole') + ->action(function (array $resources, string $projectId, Response $response, Request $request, Document $user, Database $dbForConsole) { + $firebase = new OAuth2Firebase( + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + ); + + $identity = $dbForConsole->findOne('identities', [ + Query::equal('provider', ['firebase']), + Query::equal('userInternalId', [$user->getInternalId()]), + ]); + + if ($identity === false || $identity->isEmpty()) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + $accessToken = $identity->getAttribute('providerAccessToken'); + $refreshToken = $identity->getAttribute('providerRefreshToken'); + $accessTokenExpiry = $identity->getAttribute('providerAccessTokenExpiry'); + + if (empty($accessToken) || empty($refreshToken) || empty($accessTokenExpiry)) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + if (App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', '') === '' || App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', '') === '') { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + $isExpired = new \DateTime($accessTokenExpiry) < new \DateTime('now'); + if ($isExpired) { + $firebase->refreshTokens($refreshToken); + + $accessToken = $firebase->getAccessToken(''); + $refreshToken = $firebase->getRefreshToken(''); + + $verificationId = $firebase->getUserID($accessToken); + + if (empty($verificationId)) { + throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED, 'Another request is currently refreshing OAuth token. Please try again.'); + } + + $identity = $identity + ->setAttribute('providerAccessToken', $accessToken) + ->setAttribute('providerRefreshToken', $refreshToken) + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry(''))); + + $dbForConsole->updateDocument('identities', $identity->getId(), $identity); + } + + // Get Service Account + if ($identity->getAttribute('secrets')) { + $serviceAccount = $identity->getAttribute('secrets'); + } else { + $firebase->cleanupServiceAccounts($accessToken, $projectId); + $serviceAccount = $firebase->createServiceAccount($accessToken, $projectId); + $identity = $identity + ->setAttribute('secrets', json_encode($serviceAccount)); + + $dbForConsole->updateDocument('identities', $identity->getId(), $identity); + } + + $firebase = new Firebase($serviceAccount); + + try { + $report = $firebase->report($resources); + } catch (\Exception $e) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Source Error: ' . $e->getMessage()); + } + + $response + ->setStatusCode(Response::STATUS_CODE_OK) + ->dynamic(new Document($report), Response::MODEL_MIGRATION_REPORT); + }); + +App::get('/v1/migrations/firebase/connect') + ->desc('Authorize with firebase') + ->groups(['api', 'migrations']) + ->label('scope', 'migrations.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'createFirebaseAuth') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_MOVED_PERMANENTLY) + ->label('sdk.response.type', Response::CONTENT_TYPE_HTML) + ->label('sdk.methodType', 'webAuth') + ->label('sdk.hide', true) + ->param('redirect', '', fn ($clients) => new Host($clients), 'URL to redirect back to your Firebase authorization. Only console hostnames are allowed.', true, ['clients']) + ->param('projectId', '', new UID(), 'Project ID') + ->inject('response') + ->inject('request') + ->inject('user') + ->inject('dbForConsole') + ->action(function (string $redirect, string $projectId, Response $response, Request $request, Document $user, Database $dbForConsole) { + $state = \json_encode([ + 'projectId' => $projectId, + 'redirect' => $redirect, + ]); + + $prefs = $user->getAttribute('prefs', []); + $prefs['migrationState'] = $state; + $user->setAttribute('prefs', $prefs); + $dbForConsole->updateDocument('users', $user->getId(), $user); + + $oauth2 = new OAuth2Firebase( + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + ); + $url = $oauth2->getLoginURL(); + + $response + ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->addHeader('Pragma', 'no-cache') + ->redirect($url); + }); + +App::get('/v1/migrations/firebase/redirect') + ->desc('Capture and receive data on Firebase authorization') + ->groups(['api', 'migrations']) + ->label('scope', 'public') + ->label('error', __DIR__ . '/../../views/general/error.phtml') + ->param('code', '', new Text(2048), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) + ->inject('user') + ->inject('project') + ->inject('request') + ->inject('response') + ->inject('dbForConsole') + ->action(function (string $code, Document $user, Document $project, Request $request, Response $response, Database $dbForConsole) { + $state = $user['prefs']['migrationState'] ?? '{}'; + $prefs['migrationState'] = ''; + $user->setAttribute('prefs', $prefs); + $dbForConsole->updateDocument('users', $user->getId(), $user); + + if (empty($state)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Installation requests from organisation members for the Appwrite Google App are currently unsupported.'); + } + + $state = \json_decode($state, true); + $redirect = $state['redirect'] ?? ''; + $projectId = $state['projectId'] ?? ''; + + $project = $dbForConsole->getDocument('projects', $projectId); + + if (empty($redirect)) { + $redirect = $request->getProtocol() . '://' . $request->getHostname() . '/console/project-$projectId/settings/migrations'; + } + + if ($project->isEmpty()) { + $response + ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->addHeader('Pragma', 'no-cache') + ->redirect($redirect); + + return; + } + + // OAuth Authroization + if (!empty($code)) { + $oauth2 = new OAuth2Firebase( + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + ); + + $accessToken = $oauth2->getAccessToken($code); + $refreshToken = $oauth2->getRefreshToken($code); + $accessTokenExpiry = $oauth2->getAccessTokenExpiry($code); + $email = $oauth2->getUserEmail($accessToken); + $oauth2ID = $oauth2->getUserID($accessToken); + + if (empty($accessToken)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to get access token.'); + } + + if (empty($refreshToken)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to get refresh token.'); + } + + if (empty($accessTokenExpiry)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to get access token expiry.'); + } + + // Makes sure this email is not already used in another identity + $identity = $dbForConsole->findOne('identities', [ + Query::equal('providerEmail', [$email]), + ]); + + if ($identity !== false && !$identity->isEmpty()) { + if ($identity->getAttribute('userInternalId', '') !== $user->getInternalId()) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } + } + + if ($identity !== false && !$identity->isEmpty()) { + $identity = $identity + ->setAttribute('providerAccessToken', $accessToken) + ->setAttribute('providerRefreshToken', $refreshToken) + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry)); + + $dbForConsole->updateDocument('identities', $identity->getId(), $identity); + } else { + $identity = $dbForConsole->createDocument('identities', new Document([ + '$id' => ID::unique(), + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], + 'userInternalId' => $user->getInternalId(), + 'userId' => $user->getId(), + 'provider' => 'firebase', + 'providerUid' => $oauth2ID, + 'providerEmail' => $email, + 'providerAccessToken' => $accessToken, + 'providerRefreshToken' => $refreshToken, + 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry), + ])); + } + } else { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Missing OAuth2 code.'); + } + + $response + ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->addHeader('Pragma', 'no-cache') + ->redirect($redirect); + }); + +App::get('/v1/migrations/firebase/projects') + ->desc('List Firebase Projects') + ->groups(['api', 'migrations']) + ->label('scope', 'migrations.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'listFirebaseProjects') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION_FIREBASE_PROJECT_LIST) + ->inject('user') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->inject('request') + ->action(function (Document $user, Response $response, Document $project, Database $dbForConsole, Request $request) { + $firebase = new OAuth2Firebase( + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''), + App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''), + $request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect' + ); + + $identity = $dbForConsole->findOne('identities', [ + Query::equal('provider', ['firebase']), + Query::equal('userInternalId', [$user->getInternalId()]), + ]); + + if ($identity === false || $identity->isEmpty()) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + $accessToken = $identity->getAttribute('providerAccessToken'); + $refreshToken = $identity->getAttribute('providerRefreshToken'); + $accessTokenExpiry = $identity->getAttribute('providerAccessTokenExpiry'); + + if (empty($accessToken) || empty($refreshToken) || empty($accessTokenExpiry)) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + if (App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', '') === '' || App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', '') === '') { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + try { + $isExpired = new \DateTime($accessTokenExpiry) < new \DateTime('now'); + if ($isExpired) { + try { + $firebase->refreshTokens($refreshToken); + } catch (\Exception $e) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + $accessToken = $firebase->getAccessToken(''); + $refreshToken = $firebase->getRefreshToken(''); + + $verificationId = $firebase->getUserID($accessToken); + + if (empty($verificationId)) { + throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED, 'Another request is currently refreshing OAuth token. Please try again.'); + } + + $identity = $identity + ->setAttribute('providerAccessToken', $accessToken) + ->setAttribute('providerRefreshToken', $refreshToken) + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry(''))); + + $dbForConsole->updateDocument('identities', $identity->getId(), $identity); + } + + $projects = $firebase->getProjects($accessToken); + + $output = []; + foreach ($projects as $project) { + $output[] = [ + 'displayName' => $project['displayName'], + 'projectId' => $project['projectId'], + ]; + } + } catch (\Exception $e) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + $response->dynamic(new Document([ + 'projects' => $output, + 'total' => count($output), + ]), Response::MODEL_MIGRATION_FIREBASE_PROJECT_LIST); + }); + +App::get('/v1/migrations/firebase/deauthorize') + ->desc('Revoke Appwrite\'s authorization to access Firebase Projects') + ->groups(['api', 'migrations']) + ->label('scope', 'migrations.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'deleteFirebaseAuth') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->inject('user') + ->inject('response') + ->inject('dbForConsole') + ->action(function (Document $user, Response $response, Database $dbForConsole) { + $identity = $dbForConsole->findOne('identities', [ + Query::equal('provider', ['firebase']), + Query::equal('userInternalId', [$user->getInternalId()]), + ]); + + if ($identity === false || $identity->isEmpty()) { + throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN, 'Not authenticated with Firebase'); //TODO: Replace with USER_IDENTITY_NOT_FOUND + } + + $dbForConsole->deleteDocument('identities', $identity->getId()); + + $response->noContent(); + }); + +App::get('/v1/migrations/supabase/report') + ->groups(['api', 'migrations']) + ->desc('Generate a report on Supabase Data') + ->label('scope', 'migrations.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'getSupabaseReport') + ->label('sdk.description', '/docs/references/migrations/migration-supabase-report.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION_REPORT) + ->param('resources', [], new ArrayList(new WhiteList(Supabase::getSupportedResources(), true)), 'List of resources to migrate') + ->param('endpoint', '', new URL(), 'Source\'s Supabase Endpoint.') + ->param('apiKey', '', new Text(512), 'Source\'s API Key.') + ->param('databaseHost', '', new Text(512), 'Source\'s Database Host.') + ->param('username', '', new Text(512), 'Source\'s Database Username.') + ->param('password', '', new Text(512), 'Source\'s Database Password.') + ->param('port', 5432, new Integer(true), 'Source\'s Database Port.', true) + ->inject('response') + ->inject('dbForProject') + ->action(function (array $resources, string $endpoint, string $apiKey, string $databaseHost, string $username, string $password, int $port, Response $response) { + try { + $supabase = new Supabase($endpoint, $apiKey, $databaseHost, 'postgres', $username, $password, $port); + + $response + ->setStatusCode(Response::STATUS_CODE_OK) + ->dynamic(new Document($supabase->report($resources)), Response::MODEL_MIGRATION_REPORT); + } catch (\Exception $e) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Source Error: ' . $e->getMessage()); + } + }); + +App::get('/v1/migrations/nhost/report') + ->groups(['api', 'migrations']) + ->desc('Generate a report on NHost Data') + ->label('scope', 'migrations.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'getNHostReport') + ->label('sdk.description', '/docs/references/migrations/migration-nhost-report.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION_REPORT) + ->param('resources', [], new ArrayList(new WhiteList(NHost::getSupportedResources())), 'List of resources to migrate.') + ->param('subdomain', '', new Text(512), 'Source\'s Subdomain.') + ->param('region', '', new Text(512), 'Source\'s Region.') + ->param('adminSecret', '', new Text(512), 'Source\'s Admin Secret.') + ->param('database', '', new Text(512), 'Source\'s Database Name.') + ->param('username', '', new Text(512), 'Source\'s Database Username.') + ->param('password', '', new Text(512), 'Source\'s Database Password.') + ->param('port', 5432, new Integer(true), 'Source\'s Database Port.', true) + ->inject('response') + ->action(function (array $resources, string $subdomain, string $region, string $adminSecret, string $database, string $username, string $password, int $port, Response $response) { + try { + $nhost = new NHost($subdomain, $region, $adminSecret, $database, $username, $password, $port); + + $response + ->setStatusCode(Response::STATUS_CODE_OK) + ->dynamic(new Document($nhost->report($resources)), Response::MODEL_MIGRATION_REPORT); + } catch (\Exception $e) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Source Error: ' . $e->getMessage()); + } + }); + +App::patch('/v1/migrations/:migrationId') + ->groups(['api', 'migrations']) + ->desc('Retry Migration') + ->label('scope', 'migrations.write') + ->label('event', 'migrations.[migrationId].retry') + ->label('audits.event', 'migration.retry') + ->label('audits.resource', 'migrations/{request.migrationId}') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'retry') + ->label('sdk.description', '/docs/references/migrations/retry-migration.md') + ->label('sdk.response.code', Response::STATUS_CODE_ACCEPTED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MIGRATION) + ->param('migrationId', '', new UID(), 'Migration unique ID.') + ->inject('response') + ->inject('dbForProject') + ->inject('project') + ->inject('user') + ->inject('events') + ->action(function (string $migrationId, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventInstance) { + $migration = $dbForProject->getDocument('migrations', $migrationId); + + if ($migration->isEmpty()) { + throw new Exception(Exception::MIGRATION_NOT_FOUND); + } + + if ($migration->getAttribute('status') !== 'failed') { + throw new Exception(Exception::MIGRATION_IN_PROGRESS, 'Migration not failed yet'); + } + + $migration + ->setAttribute('status', 'pending') + ->setAttribute('dateUpdated', \time()); + + // Trigger Migration + $event = new Migration(); + $event + ->setMigration($migration) + ->setProject($project) + ->setUser($user) + ->trigger(); + + $response->noContent(); + }); + +App::delete('/v1/migrations/:migrationId') + ->groups(['api', 'migrations']) + ->desc('Delete Migration') + ->label('scope', 'migrations.write') + ->label('event', 'migrations.[migrationId].delete') + ->label('audits.event', 'migrationId.delete') + ->label('audits.resource', 'migrations/{request.migrationId}') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'migrations') + ->label('sdk.method', 'delete') + ->label('sdk.description', '/docs/references/functions/delete-migration.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('migrationId', '', new UID(), 'Migration ID.') + ->inject('response') + ->inject('dbForProject') + ->inject('events') + ->action(function (string $migrationId, Response $response, Database $dbForProject, Event $events) { + $migration = $dbForProject->getDocument('migrations', $migrationId); + + if ($migration->isEmpty()) { + throw new Exception(Exception::MIGRATION_NOT_FOUND); + } + + if (!$dbForProject->deleteDocument('migrations', $migration->getId())) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove migration from DB'); + } + + $events->setParam('migrationId', $migration->getId()); + + $response->noContent(); + }); diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index 0f05c6f497..0f0a296185 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -1,18 +1,24 @@ desc('Get usage stats for a project') - ->groups(['api', 'usage']) + ->groups(['api']) ->label('scope', 'projects.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'project') @@ -24,71 +30,282 @@ App::get('/v1/project/usage') ->inject('response') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { - - $periods = Config::getParam('usage', []); - $stats = $usage = []; - $days = $periods[$range]; - $metrics = [ - METRIC_NETWORK_REQUESTS, - METRIC_NETWORK_INBOUND, - METRIC_NETWORK_OUTBOUND, - METRIC_EXECUTIONS, - METRIC_DOCUMENTS, - METRIC_DATABASES, - METRIC_USERS, - METRIC_BUCKETS, - METRIC_FILES_STORAGE - ]; - - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { - foreach ($metrics as $metric) { - $limit = $days['limit']; - $period = $days['period']; - $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), - Query::equal('metric', [$metric]), - Query::limit($limit), - Query::orderDesc('time'), - ]); - - $stats[$metric] = []; - foreach ($results as $result) { - $stats[$metric][$result->getAttribute('time')] = [ - 'value' => $result->getAttribute('value'), - ]; - } - } - }); - - - $format = match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }; - - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], ]; - } - } + $metrics = [ + 'project.$all.network.requests', + 'project.$all.network.bandwidth', + 'project.$all.storage.size', + 'users.$all.count.total', + 'databases.$all.count.total', + 'documents.$all.count.total', + 'executions.$all.compute.total', + 'buckets.$all.count.total' + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + $stats[$metric] = array_reverse($stats[$metric]); + } + }); + + $usage = new Document([ + 'range' => $range, + 'requests' => $stats[$metrics[0]] ?? [], + 'network' => $stats[$metrics[1]] ?? [], + 'storage' => $stats[$metrics[2]] ?? [], + 'users' => $stats[$metrics[3]] ?? [], + 'databases' => $stats[$metrics[4]] ?? [], + 'documents' => $stats[$metrics[5]] ?? [], + 'executions' => $stats[$metrics[6]] ?? [], + 'buckets' => $stats[$metrics[7]] ?? [], + ]); + } + + $response->dynamic($usage, Response::MODEL_USAGE_PROJECT); + }); + +// Variables + +App::post('/v1/project/variables') + ->desc('Create Variable') + ->groups(['api']) + ->label('scope', 'projects.write') + ->label('audits.event', 'variable.create') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'project') + ->label('sdk.method', 'createVariable') + ->label('sdk.description', '/docs/references/project/create-variable.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_VARIABLE) + ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false) + ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false) + ->inject('project') + ->inject('response') + ->inject('dbForProject') + ->inject('dbForConsole') + ->action(function (string $key, string $value, Document $project, Response $response, Database $dbForProject, Database $dbForConsole) { + $variableId = ID::unique(); + + $variable = new Document([ + '$id' => $variableId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'resourceInternalId' => '', + 'resourceId' => '', + 'resourceType' => 'project', + 'key' => $key, + 'value' => $value, + 'search' => implode(' ', [$variableId, $key, 'project']), + ]); + + try { + $variable = $dbForProject->createDocument('variables', $variable); + } catch (DuplicateException $th) { + throw new Exception(Exception::VARIABLE_ALREADY_EXISTS); + } + $dbForConsole->deleteCachedDocument('projects', $project->getId()); + + $functions = $dbForProject->find('functions', [ + Query::limit(APP_LIMIT_SUBQUERY) + ]); + + foreach ($functions as $function) { + $dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false)); + } + + $dbForProject->deleteCachedDocument('projects', $project->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($variable, Response::MODEL_VARIABLE); + }); + +App::get('/v1/project/variables') + ->desc('List Variables') + ->groups(['api']) + ->label('scope', 'projects.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'project') + ->label('sdk.method', 'listVariables') + ->label('sdk.description', '/docs/references/project/list-variables.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_VARIABLE_LIST) + ->inject('response') + ->inject('dbForProject') + ->action(function (Response $response, Database $dbForProject) { + $variables = $dbForProject->find('variables', [ + Query::equal('resourceType', ['project']), + Query::limit(APP_LIMIT_SUBQUERY) + ]); $response->dynamic(new Document([ - 'range' => $range, - 'requestsTotal' => ($usage[$metrics[0]]), - 'network' => ($usage[$metrics[1]] + $usage[$metrics[2]]), - 'executionsTotal' => $usage[$metrics[3]], - 'documentsTotal' => $usage[$metrics[4]], - 'databasesTotal' => $usage[$metrics[5]], - 'usersTotal' => $usage[$metrics[6]], - 'bucketsTotal' => $usage[$metrics[7]], - 'filesStorage' => $usage[$metrics[8]], - ]), Response::MODEL_USAGE_PROJECT); + 'variables' => $variables, + 'total' => \count($variables), + ]), Response::MODEL_VARIABLE_LIST); + }); + +App::get('/v1/project/variables/:variableId') + ->desc('Get Variable') + ->groups(['api']) + ->label('scope', 'projects.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'project') + ->label('sdk.method', 'getVariable') + ->label('sdk.description', '/docs/references/project/get-variable.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_VARIABLE) + ->param('variableId', '', new UID(), 'Variable unique ID.', false) + ->inject('response') + ->inject('project') + ->inject('dbForProject') + ->action(function (string $variableId, Response $response, Document $project, Database $dbForProject) { + $variable = $dbForProject->getDocument('variables', $variableId); + if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceType') !== 'project') { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } + + $response->dynamic($variable, Response::MODEL_VARIABLE); + }); + +App::put('/v1/project/variables/:variableId') + ->desc('Update Variable') + ->groups(['api']) + ->label('scope', 'projects.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'project') + ->label('sdk.method', 'updateVariable') + ->label('sdk.description', '/docs/references/project/update-variable.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_VARIABLE) + ->param('variableId', '', new UID(), 'Variable unique ID.', false) + ->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false) + ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true) + ->inject('project') + ->inject('response') + ->inject('dbForProject') + ->inject('dbForConsole') + ->action(function (string $variableId, string $key, ?string $value, Document $project, Response $response, Database $dbForProject, Database $dbForConsole) { + $variable = $dbForProject->getDocument('variables', $variableId); + if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceType') !== 'project') { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } + + $variable + ->setAttribute('key', $key) + ->setAttribute('value', $value ?? $variable->getAttribute('value')) + ->setAttribute('search', implode(' ', [$variableId, $key, 'project'])); + + try { + $dbForProject->updateDocument('variables', $variable->getId(), $variable); + } catch (DuplicateException $th) { + throw new Exception(Exception::VARIABLE_ALREADY_EXISTS); + } + $dbForConsole->deleteCachedDocument('projects', $project->getId()); + + $functions = $dbForProject->find('functions', [ + Query::limit(APP_LIMIT_SUBQUERY) + ]); + + foreach ($functions as $function) { + $dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false)); + } + + $dbForProject->deleteCachedDocument('projects', $project->getId()); + + $response->dynamic($variable, Response::MODEL_VARIABLE); + }); + +App::delete('/v1/project/variables/:variableId') + ->desc('Delete Variable') + ->groups(['api']) + ->label('scope', 'projects.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'project') + ->label('sdk.method', 'deleteVariable') + ->label('sdk.description', '/docs/references/project/delete-variable.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('variableId', '', new UID(), 'Variable unique ID.', false) + ->inject('project') + ->inject('response') + ->inject('dbForProject') + ->action(function (string $variableId, Document $project, Response $response, Database $dbForProject) { + $variable = $dbForProject->getDocument('variables', $variableId); + if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceType') !== 'project') { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } + + $functions = $dbForProject->find('functions', [ + Query::limit(APP_LIMIT_SUBQUERY) + ]); + + foreach ($functions as $function) { + $dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false)); + } + + $dbForProject->deleteDocument('variables', $variable->getId()); + $dbForProject->deleteCachedDocument('projects', $project->getId()); + + $response->noContent(); }); diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index aa70e389d9..11a9f8c558 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1,19 +1,20 @@ groups(['projects']) @@ -64,7 +61,7 @@ App::post('/v1/projects') ->param('projectId', '', new ProjectId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can\'t start with a special char. Max length is 36 chars.') ->param('name', null, new Text(128), 'Project name. Max length: 128 chars.') ->param('teamId', '', new UID(), 'Team unique ID.') - ->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn($config) => !$config['disabled']))), 'Project Region.', true) + ->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn ($config) => !$config['disabled']))), 'Project Region.', true) ->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true) ->param('logo', '', new Text(1024), 'Project logo.', true) ->param('url', '', new URL(), 'Project URL.', true) @@ -99,6 +96,7 @@ App::post('/v1/projects') $backups['database_db_fra1_03'] = ['from' => '10:30', 'to' => '11:15']; $backups['database_db_fra1_04'] = ['from' => '13:30', 'to' => '14:15']; $backups['database_db_fra1_05'] = ['from' => '4:30', 'to' => '5:15']; + $backups['database_db_fra1_06'] = ['from' => '16:30', 'to' => '17:15']; $databases = Config::getParam('pools-database', []); @@ -122,7 +120,7 @@ App::post('/v1/projects') } } - if ($index = array_search('database_db_fra1_05', $databases)) { + if ($index = array_search('database_db_fra1_06', $databases)) { $database = $databases[$index]; } else { $database = $databases[array_rand($databases)]; @@ -161,7 +159,6 @@ App::post('/v1/projects') 'authProviders' => [], 'webhooks' => null, 'keys' => null, - 'domains' => null, 'auths' => $auths, 'search' => implode(' ', [$projectId, $name]), 'database' => $database @@ -245,7 +242,9 @@ App::get('/v1/projects') } // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -291,6 +290,120 @@ App::get('/v1/projects/:projectId') $response->dynamic($project, Response::MODEL_PROJECT); }); +App::get('/v1/projects/:projectId/usage') + ->desc('Get usage stats for a project') + ->groups(['api', 'projects', 'usage']) + ->label('scope', 'projects.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'projects') + ->label('sdk.method', 'getUsage') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_USAGE_PROJECT) + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true) + ->inject('response') + ->inject('dbForConsole') + ->inject('dbForProject') + ->inject('register') + ->action(function (string $projectId, string $range, Response $response, Database $dbForConsole, Database $dbForProject, Registry $register) { + + $project = $dbForConsole->getDocument('projects', $projectId); + + if ($project->isEmpty()) { + throw new Exception(Exception::PROJECT_NOT_FOUND); + } + + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], + ]; + + $dbForProject->setNamespace("_{$project->getInternalId()}"); + + $metrics = [ + 'project.$all.network.requests', + 'project.$all.network.bandwidth', + 'project.$all.storage.size', + 'users.$all.count.total', + 'databases.$all.count.total', + 'documents.$all.count.total', + 'executions.$all.compute.total', + 'buckets.$all.count.total' + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + $stats[$metric] = array_reverse($stats[$metric]); + } + }); + + $usage = new Document([ + 'range' => $range, + 'requests' => $stats[$metrics[0]] ?? [], + 'network' => $stats[$metrics[1]] ?? [], + 'storage' => $stats[$metrics[2]] ?? [], + 'users' => $stats[$metrics[3]] ?? [], + 'databases' => $stats[$metrics[4]] ?? [], + 'documents' => $stats[$metrics[5]] ?? [], + 'executions' => $stats[$metrics[6]] ?? [], + 'buckets' => $stats[$metrics[7]] ?? [], + ]); + } + + $response->dynamic($usage, Response::MODEL_USAGE_PROJECT); + }); + App::patch('/v1/projects/:projectId') ->desc('Update Project') ->groups(['api', 'projects']) @@ -323,17 +436,17 @@ App::patch('/v1/projects/:projectId') } $project = $dbForConsole->updateDocument('projects', $project->getId(), $project - ->setAttribute('name', $name) - ->setAttribute('description', $description) - ->setAttribute('logo', $logo) - ->setAttribute('url', $url) - ->setAttribute('legalName', $legalName) - ->setAttribute('legalCountry', $legalCountry) - ->setAttribute('legalState', $legalState) - ->setAttribute('legalCity', $legalCity) - ->setAttribute('legalAddress', $legalAddress) - ->setAttribute('legalTaxId', $legalTaxId) - ->setAttribute('search', implode(' ', [$projectId, $name]))); + ->setAttribute('name', $name) + ->setAttribute('description', $description) + ->setAttribute('logo', $logo) + ->setAttribute('url', $url) + ->setAttribute('legalName', $legalName) + ->setAttribute('legalCountry', $legalCountry) + ->setAttribute('legalState', $legalState) + ->setAttribute('legalCity', $legalCity) + ->setAttribute('legalAddress', $legalAddress) + ->setAttribute('legalTaxId', $legalTaxId) + ->setAttribute('search', implode(' ', [$projectId, $name]))); $response->dynamic($project, Response::MODEL_PROJECT); }); @@ -366,14 +479,14 @@ App::patch('/v1/projects/:projectId/team') } $project = $dbForConsole->updateDocument('projects', $project->getId(), $project - ->setAttribute('teamId', $teamId) - ->setAttribute('$permissions', [ - Permission::read(Role::team(ID::custom($teamId))), - Permission::update(Role::team(ID::custom($teamId), 'owner')), - Permission::update(Role::team(ID::custom($teamId), 'developer')), - Permission::delete(Role::team(ID::custom($teamId), 'owner')), - Permission::delete(Role::team(ID::custom($teamId), 'developer')), - ])); + ->setAttribute('teamId', $teamId) + ->setAttribute('$permissions', [ + Permission::read(Role::team(ID::custom($teamId))), + Permission::update(Role::team(ID::custom($teamId), 'owner')), + Permission::update(Role::team(ID::custom($teamId), 'developer')), + Permission::delete(Role::team(ID::custom($teamId), 'owner')), + Permission::delete(Role::team(ID::custom($teamId), 'developer')), + ])); $response->dynamic($project, Response::MODEL_PROJECT); }); @@ -389,7 +502,7 @@ App::patch('/v1/projects/:projectId/service') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])), true), 'Service name.') + ->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])), true), 'Service name.') ->param('status', null, new Boolean(), 'Service status.') ->inject('response') ->inject('dbForConsole') @@ -431,7 +544,7 @@ App::patch('/v1/projects/:projectId/service/all') throw new Exception(Exception::PROJECT_NOT_FOUND); } - $allServices = array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])); + $allServices = array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])); $services = []; foreach ($allServices as $service) { @@ -730,8 +843,7 @@ App::delete('/v1/projects/:projectId') $deletes ->setType(DELETE_TYPE_DOCUMENT) - ->setDocument($project) - ; + ->setDocument($project); if (!$dbForConsole->deleteDocument('projects', $projectId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove project from DB'); @@ -909,8 +1021,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->setAttribute('url', $url) ->setAttribute('security', $security) ->setAttribute('httpUser', $httpUser) - ->setAttribute('httpPass', $httpPass) - ; + ->setAttribute('httpPass', $httpPass); $dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook); $dbForConsole->deleteCachedDocument('projects', $project->getId()); @@ -1149,8 +1260,7 @@ App::put('/v1/projects/:projectId/keys/:keyId') $key ->setAttribute('name', $name) ->setAttribute('scopes', $scopes) - ->setAttribute('expire', $expire) - ; + ->setAttribute('expire', $expire); $dbForConsole->updateDocument('keys', $key->getId(), $key); @@ -1352,8 +1462,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId') ->setAttribute('name', $name) ->setAttribute('key', $key) ->setAttribute('store', $store) - ->setAttribute('hostname', $hostname) - ; + ->setAttribute('hostname', $hostname); $dbForConsole->updateDocument('platforms', $platform->getId(), $platform); @@ -1399,248 +1508,6 @@ App::delete('/v1/projects/:projectId/platforms/:platformId') $response->noContent(); }); -// Domains - -App::post('/v1/projects/:projectId/domains') - ->desc('Create Domain') - ->groups(['api', 'projects']) - ->label('scope', 'projects.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'projects') - ->label('sdk.method', 'createDomain') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_DOMAIN) - ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('domain', null, new DomainValidator(), 'Domain name.') - ->inject('response') - ->inject('dbForConsole') - ->action(function (string $projectId, string $domain, Response $response, Database $dbForConsole) { - - $project = $dbForConsole->getDocument('projects', $projectId); - - if ($project->isEmpty()) { - throw new Exception(Exception::PROJECT_NOT_FOUND); - } - - if ($domain === App::getEnv('_APP_DOMAIN', '') || $domain === App::getEnv('_APP_DOMAIN_TARGET', '')) { - throw new Exception(Exception::DOMAIN_FORBIDDEN); - } - - $document = $dbForConsole->findOne('domains', [ - Query::equal('domain', [$domain]) - ]); - - if ($document && !$document->isEmpty()) { - throw new Exception(Exception::DOMAIN_ALREADY_EXISTS); - } - - $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); - - if (!$target->isKnown() || $target->isTest()) { - throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target (' . $target->get() . '). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.'); - } - - $domain = new Domain($domain); - - $domain = new Document([ - '$id' => ID::unique(), - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - 'projectInternalId' => $project->getInternalId(), - 'projectId' => $project->getId(), - 'updated' => DateTime::now(), - 'domain' => $domain->get(), - 'tld' => $domain->getSuffix(), - 'registerable' => $domain->getRegisterable(), - 'verification' => false, - 'certificateId' => null, - ]); - - $domain = $dbForConsole->createDocument('domains', $domain); - - $dbForConsole->deleteCachedDocument('projects', $project->getId()); - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($domain, Response::MODEL_DOMAIN); - }); - -App::get('/v1/projects/:projectId/domains') - ->desc('List Domains') - ->groups(['api', 'projects']) - ->label('scope', 'projects.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'projects') - ->label('sdk.method', 'listDomains') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_DOMAIN_LIST) - ->param('projectId', '', new UID(), 'Project unique ID.') - ->inject('response') - ->inject('dbForConsole') - ->action(function (string $projectId, Response $response, Database $dbForConsole) { - - $project = $dbForConsole->getDocument('projects', $projectId); - - if ($project->isEmpty()) { - throw new Exception(Exception::PROJECT_NOT_FOUND); - } - - $domains = $dbForConsole->find('domains', [ - Query::equal('projectInternalId', [$project->getInternalId()]), - Query::limit(5000), - ]); - - $response->dynamic(new Document([ - 'domains' => $domains, - 'total' => count($domains), - ]), Response::MODEL_DOMAIN_LIST); - }); - -App::get('/v1/projects/:projectId/domains/:domainId') - ->desc('Get Domain') - ->groups(['api', 'projects']) - ->label('scope', 'projects.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'projects') - ->label('sdk.method', 'getDomain') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_DOMAIN) - ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('domainId', '', new UID(), 'Domain unique ID.') - ->inject('response') - ->inject('dbForConsole') - ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) { - - $project = $dbForConsole->getDocument('projects', $projectId); - - if ($project->isEmpty()) { - throw new Exception(Exception::PROJECT_NOT_FOUND); - } - - $domain = $dbForConsole->findOne('domains', [ - Query::equal('$id', [$domainId]), - Query::equal('projectInternalId', [$project->getInternalId()]), - ]); - - if ($domain === false || $domain->isEmpty()) { - throw new Exception(Exception::DOMAIN_NOT_FOUND); - } - - $response->dynamic($domain, Response::MODEL_DOMAIN); - }); - -App::patch('/v1/projects/:projectId/domains/:domainId/verification') - ->desc('Update Domain Verification Status') - ->groups(['api', 'projects']) - ->label('scope', 'projects.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'projects') - ->label('sdk.method', 'updateDomainVerification') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_DOMAIN) - ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('domainId', '', new UID(), 'Domain unique ID.') - ->inject('response') - ->inject('dbForConsole') - ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) { - - $project = $dbForConsole->getDocument('projects', $projectId); - - if ($project->isEmpty()) { - throw new Exception(Exception::PROJECT_NOT_FOUND); - } - - $domain = $dbForConsole->findOne('domains', [ - Query::equal('$id', [$domainId]), - Query::equal('projectInternalId', [$project->getInternalId()]), - ]); - - if ($domain === false || $domain->isEmpty()) { - throw new Exception(Exception::DOMAIN_NOT_FOUND); - } - - $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); - - if (!$target->isKnown() || $target->isTest()) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.'); - } - - if ($domain->getAttribute('verification') === true) { - return $response->dynamic($domain, Response::MODEL_DOMAIN); - } - - $validator = new CNAME($target->get()); // Verify Domain with DNS records - - if (!$validator->isValid($domain->getAttribute('domain', ''))) { - throw new Exception(Exception::DOMAIN_VERIFICATION_FAILED); - } - - - $dbForConsole->updateDocument('domains', $domain->getId(), $domain->setAttribute('verification', true)); - $dbForConsole->deleteCachedDocument('projects', $project->getId()); - - // Issue a TLS certificate when domain is verified - $event = new Certificate(); - $event - ->setDomain($domain) - ->trigger(); - - $response->dynamic($domain, Response::MODEL_DOMAIN); - }); - -App::delete('/v1/projects/:projectId/domains/:domainId') - ->desc('Delete Domain') - ->groups(['api', 'projects']) - ->label('scope', 'projects.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) - ->label('sdk.namespace', 'projects') - ->label('sdk.method', 'deleteDomain') - ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) - ->label('sdk.response.model', Response::MODEL_NONE) - ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('domainId', '', new UID(), 'Domain unique ID.') - ->inject('response') - ->inject('dbForConsole') - ->inject('deletes') - ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole, Delete $deletes) { - - $project = $dbForConsole->getDocument('projects', $projectId); - - if ($project->isEmpty()) { - throw new Exception(Exception::PROJECT_NOT_FOUND); - } - - $domain = $dbForConsole->findOne('domains', [ - Query::equal('$id', [$domainId]), - Query::equal('projectInternalId', [$project->getInternalId()]), - ]); - - if ($domain === false || $domain->isEmpty()) { - throw new Exception(Exception::DOMAIN_NOT_FOUND); - } - - if ($domain->getAttribute('domain') === App::getEnv('_APP_DOMAIN', '') || $domain->getAttribute('domain') === App::getEnv('_APP_DOMAIN_TARGET', '')) { - throw new Exception(Exception::DOMAIN_FORBIDDEN); - } - - $dbForConsole->deleteDocument('domains', $domain->getId()); - - $dbForConsole->deleteCachedDocument('projects', $project->getId()); - - $deletes - ->setType(DELETE_TYPE_CERTIFICATES) - ->setDocument($domain); - - $response->noContent(); - }); - // CUSTOM SMTP and Templates App::patch('/v1/projects/:projectId/smtp') ->desc('Update SMTP configuration') @@ -1654,15 +1521,17 @@ App::patch('/v1/projects/:projectId/smtp') ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('enabled', false, new Boolean(), 'Enable custom SMTP service') - ->param('sender', '', new Email(), 'SMTP sender email') - ->param('host', '', new HostName(), 'SMTP server host name') - ->param('port', null, new Integer(), 'SMTP server port') - ->param('username', null, new Text(0), 'SMTP server username') - ->param('password', null, new Text(0), 'SMTP server password') + ->param('senderName', '', new Text(255, 0), 'Name of the email sender', true) + ->param('senderEmail', '', new Email(), 'Email of the sender', true) + ->param('replyTo', '', new Email(), 'Reply to email', true) + ->param('host', '', new HostName(), 'SMTP server host name', true) + ->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) ->inject('response') ->inject('dbForConsole') - ->action(function (string $projectId, bool $enabled, string $sender, string $host, int $port, string $username, string $password, string $secure, Response $response, Database $dbForConsole) { + ->action(function (string $projectId, bool $enabled, string $senderName, string $senderEmail, string $replyTo, string $host, int $port, string $username, string $password, string $secure, Response $response, Database $dbForConsole) { $project = $dbForConsole->getDocument('projects', $projectId); @@ -1670,30 +1539,60 @@ App::patch('/v1/projects/:projectId/smtp') throw new Exception(Exception::PROJECT_NOT_FOUND); } - // validate SMTP settings - $mail = new PHPMailer(true); - $mail->isSMTP(); - $mail->Username = $username; - $mail->Password = $password; - $mail->Host = $host; - $mail->Port = $port; - $mail->SMTPSecure = $secure; - $mail->SMTPAutoTLS = false; - $valid = $mail->SmtpConnect(); - - if (!$valid) { - throw new Exception(Exception::GENERAL_SMTP_DISABLED); + // Ensure required params for when enabling SMTP + if ($enabled) { + if (empty($senderName)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Sender name is required when enabling SMTP.'); + } elseif (empty($senderEmail)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Sender email is required when enabling SMTP.'); + } elseif (empty($host)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Host is required when enabling SMTP.'); + } elseif (empty($port)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Port is required when enabling SMTP.'); + } } - $smtp = [ - 'enabled' => $enabled, - 'sender' => $sender, - 'host' => $host, - 'port' => $port, - 'username' => $username, - 'password' => $password, - 'secure' => $secure, - ]; + // validate SMTP settings + if ($enabled) { + $mail = new PHPMailer(true); + $mail->isSMTP(); + $mail->Username = $username; + $mail->Password = $password; + $mail->Host = $host; + $mail->Port = $port; + $mail->SMTPSecure = $secure; + $mail->SMTPAutoTLS = false; + $mail->Timeout = 5; + + try { + $valid = $mail->SmtpConnect(); + + if (!$valid) { + throw new Exception('Connection is not valid.'); + } + } catch (Throwable $error) { + throw new Exception(Exception::PROJECT_SMTP_CONFIG_INVALID, 'Could not connect to SMTP server: ' . $error->getMessage()); + } + } + + // Save SMTP settings + if ($enabled) { + $smtp = [ + 'enabled' => $enabled, + 'senderName' => $senderName, + 'senderEmail' => $senderEmail, + 'replyTo' => $replyTo, + 'host' => $host, + 'port' => $port, + 'username' => $username, + 'password' => $password, + 'secure' => $secure, + ]; + } else { + $smtp = [ + 'enabled' => false + ]; + } $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('smtp', $smtp)); @@ -1712,11 +1611,13 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale') ->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { + throw new Exception(Exception::GENERAL_NOT_IMPLEMENTED); + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1728,7 +1629,7 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale') if (is_null($template)) { $template = [ - 'message' => Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl')->render(), + 'message' => Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl')->render(), ]; } @@ -1750,7 +1651,7 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale') ->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { @@ -1766,27 +1667,22 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale') $localeObj = new Locale($locale); if (is_null($template)) { - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); - $message = $message + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); + $message ->setParam('{{hello}}', $localeObj->getText("emails.{$type}.hello")) - ->setParam('{{name}}', '') - ->setParam('{{body}}', $localeObj->getText("emails.{$type}.body")) + ->setParam('{{user}}', '') ->setParam('{{footer}}', $localeObj->getText("emails.{$type}.footer")) + ->setParam('{{body}}', $localeObj->getText('emails.' . $type . '.body')) ->setParam('{{thanks}}', $localeObj->getText("emails.{$type}.thanks")) ->setParam('{{signature}}', $localeObj->getText("emails.{$type}.signature")) - ->setParam('{{direction}}', $localeObj->getText('settings.direction')) - ->setParam('{{bg-body}}', '#f7f7f7') - ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{text-content}}', '#000000') - ->render(); + ->setParam('{{direction}}', $localeObj->getText('settings.direction')); + $message = $message->render(); - $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($localeObj->getText('emails.sender'), $project->getAttribute('name')); - $from = empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from; $template = [ 'message' => $message, 'subject' => $localeObj->getText('emails.' . $type . '.subject'), - 'senderEmail' => App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', ''), - 'senderName' => $from + 'senderEmail' => '', + 'senderName' => '' ]; } @@ -1808,12 +1704,14 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale') ->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->param('message', '', new Text(0), 'Template message') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, string $message, Response $response, Database $dbForConsole) { + throw new Exception(Exception::GENERAL_NOT_IMPLEMENTED); + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1846,15 +1744,15 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale') ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) - ->param('senderName', '', new Text(255), 'Name of the email sender') - ->param('senderEmail', '', new Email(), 'Email of the sender') + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->param('subject', '', new Text(255), 'Email Subject') ->param('message', '', new Text(0), 'Template message') + ->param('senderName', '', new Text(255, 0), 'Name of the email sender', true) + ->param('senderEmail', '', new Email(), 'Email of the sender', true) ->param('replyTo', '', new Email(), 'Reply to email', true) ->inject('response') ->inject('dbForConsole') - ->action(function (string $projectId, string $type, string $locale, string $senderName, string $senderEmail, string $subject, string $message, string $replyTo, Response $response, Database $dbForConsole) { + ->action(function (string $projectId, string $type, string $locale, string $subject, string $message, string $senderName, string $senderEmail, string $replyTo, Response $response, Database $dbForConsole) { $project = $dbForConsole->getDocument('projects', $projectId); @@ -1896,11 +1794,13 @@ App::delete('/v1/projects/:projectId/templates/sms/:type/:locale') ->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { + throw new Exception(Exception::GENERAL_NOT_IMPLEMENTED); + $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -1937,7 +1837,7 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale') ->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type') - ->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) + ->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes']) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) { diff --git a/app/controllers/api/proxy.php b/app/controllers/api/proxy.php new file mode 100644 index 0000000000..1c0c929024 --- /dev/null +++ b/app/controllers/api/proxy.php @@ -0,0 +1,316 @@ +groups(['api', 'proxy']) + ->desc('Create Rule') + ->label('scope', 'rules.write') + ->label('event', 'rules.[ruleId].create') + ->label('audits.event', 'rule.create') + ->label('audits.resource', 'rule/{response.$id}') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'proxy') + ->label('sdk.method', 'createRule') + ->label('sdk.description', '/docs/references/proxy/create-rule.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROXY_RULE) + ->param('domain', null, new ValidatorDomain(), 'Domain name.') + ->param('resourceType', null, new WhiteList(['api', 'function']), 'Action definition for the rule. Possible values are "api", "function"') + ->param('resourceId', '', new UID(), 'ID of resource for the action type. If resourceType is "api", leave empty. If resourceType is "function", provide ID of the function.', true) + ->inject('response') + ->inject('project') + ->inject('events') + ->inject('dbForConsole') + ->inject('dbForProject') + ->action(function (string $domain, string $resourceType, string $resourceId, Response $response, Document $project, Event $events, Database $dbForConsole, Database $dbForProject) { + $mainDomain = App::getEnv('_APP_DOMAIN', ''); + if ($domain === $mainDomain) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'You cannot assign your main domain to specific resource. Please use subdomain or a different domain.'); + } + if ($domain === 'localhost' || $domain === APP_HOSTNAME_INTERNAL) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please pick another one.'); + } + + $document = $dbForConsole->findOne('rules', [ + Query::equal('domain', [$domain]), + ]); + + if ($document && !$document->isEmpty()) { + if ($document->getAttribute('projectId') === $project->getId()) { + $resourceType = $document->getAttribute('resourceType'); + $resourceId = $document->getAttribute('resourceId'); + $message = "Domain already assigned to '{$resourceType}' service"; + if (!empty($resourceId)) { + $message .= " with ID '{$resourceId}'"; + } + + $message .= '.'; + } else { + $message = 'Domain already assigned to different project.'; + } + + throw new Exception(Exception::RULE_ALREADY_EXISTS, $message); + } + + $resourceInternalId = ''; + + if ($resourceType == 'function') { + if (empty($resourceId)) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } + + $function = $dbForProject->getDocument('functions', $resourceId); + + if ($function->isEmpty()) { + throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND); + } + + $resourceInternalId = $function->getInternalId(); + } + + $domain = new Domain($domain); + + $ruleId = ID::unique(); + $rule = new Document([ + '$id' => $ruleId, + 'projectId' => $project->getId(), + 'projectInternalId' => $project->getInternalId(), + 'domain' => $domain->get(), + 'resourceType' => $resourceType, + 'resourceId' => $resourceId, + 'resourceInternalId' => $resourceInternalId, + 'certificateId' => '', + ]); + + $status = 'created'; + $functionsDomain = App::getEnv('_APP_DOMAIN_FUNCTIONS'); + if (!empty($functionsDomain) && \str_ends_with($domain->get(), $functionsDomain)) { + $status = 'verified'; + } + + if ($status === 'created') { + $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); + $validator = new CNAME($target->get()); // Verify Domain with DNS records + + if ($validator->isValid($domain->get())) { + $status = 'verifying'; + + $event = new Certificate(); + $event + ->setDomain(new Document([ + 'domain' => $rule->getAttribute('domain') + ])) + ->trigger(); + } + } + + $rule->setAttribute('status', $status); + $rule = $dbForConsole->createDocument('rules', $rule); + + $events->setParam('ruleId', $rule->getId()); + + $rule->setAttribute('logs', ''); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($rule, Response::MODEL_PROXY_RULE); + }); + +App::get('/v1/proxy/rules') + ->groups(['api', 'proxy']) + ->desc('List Rules') + ->label('scope', 'rules.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'proxy') + ->label('sdk.method', 'listRules') + ->label('sdk.description', '/docs/references/proxy/list-rules.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROXY_RULE_LIST) + ->param('queries', [], new Rules(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Rules::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->action(function (array $queries, string $search, Response $response, Document $project, Database $dbForConsole) { + $queries = Query::parseQueries($queries); + + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + + $queries[] = Query::equal('projectInternalId', [$project->getInternalId()]); + + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); + if ($cursor) { + /** @var Query $cursor */ + $ruleId = $cursor->getValue(); + $cursorDocument = $dbForConsole->getDocument('rules', $ruleId); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Rule '{$ruleId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + + $filterQueries = Query::groupByType($queries)['filters']; + + $rules = $dbForConsole->find('rules', $queries); + foreach ($rules as $rule) { + $certificate = $dbForConsole->getDocument('certificates', $rule->getAttribute('certificateId', '')); + $rule->setAttribute('logs', $certificate->getAttribute('logs', '')); + $rule->setAttribute('renewAt', $certificate->getAttribute('renewDate', '')); + } + + $response->dynamic(new Document([ + 'rules' => $rules, + 'total' => $dbForConsole->count('rules', $filterQueries, APP_LIMIT_COUNT), + ]), Response::MODEL_PROXY_RULE_LIST); + }); + +App::get('/v1/proxy/rules/:ruleId') + ->groups(['api', 'proxy']) + ->desc('Get Rule') + ->label('scope', 'rules.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'proxy') + ->label('sdk.method', 'getRule') + ->label('sdk.description', '/docs/references/proxy/get-rule.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROXY_RULE) + ->param('ruleId', '', new UID(), 'Rule ID.') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->action(function (string $ruleId, Response $response, Document $project, Database $dbForConsole) { + $rule = $dbForConsole->getDocument('rules', $ruleId); + + if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getInternalId()) { + throw new Exception(Exception::RULE_NOT_FOUND); + } + + $certificate = $dbForConsole->getDocument('certificates', $rule->getAttribute('certificateId', '')); + $rule->setAttribute('logs', $certificate->getAttribute('logs', '')); + $rule->setAttribute('renewAt', $certificate->getAttribute('renewDate', '')); + + $response->dynamic($rule, Response::MODEL_PROXY_RULE); + }); + +App::delete('/v1/proxy/rules/:ruleId') + ->groups(['api', 'proxy']) + ->desc('Delete Rule') + ->label('scope', 'rules.write') + ->label('event', 'rules.[ruleId].delete') + ->label('audits.event', 'rules.delete') + ->label('audits.resource', 'rule/{request.ruleId}') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'proxy') + ->label('sdk.method', 'deleteRule') + ->label('sdk.description', '/docs/references/proxy/delete-rule.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('ruleId', '', new UID(), 'Rule ID.') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->inject('deletes') + ->inject('events') + ->action(function (string $ruleId, Response $response, Document $project, Database $dbForConsole, Delete $deletes, Event $events) { + $rule = $dbForConsole->getDocument('rules', $ruleId); + + if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getInternalId()) { + throw new Exception(Exception::RULE_NOT_FOUND); + } + + $dbForConsole->deleteDocument('rules', $rule->getId()); + + $deletes + ->setType(DELETE_TYPE_DOCUMENT) + ->setDocument($rule); + + $events->setParam('ruleId', $rule->getId()); + + $response->noContent(); + }); + +App::patch('/v1/proxy/rules/:ruleId/verification') + ->desc('Update Rule Verification Status') + ->groups(['api', 'proxy']) + ->label('scope', 'rules.write') + ->label('event', 'rules.[ruleId].update') + ->label('audits.event', 'rule.update') + ->label('audits.resource', 'rule/{response.$id}') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'proxy') + ->label('sdk.method', 'updateRuleVerification') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROXY_RULE) + ->param('ruleId', '', new UID(), 'Rule ID.') + ->inject('response') + ->inject('events') + ->inject('project') + ->inject('dbForConsole') + ->action(function (string $ruleId, Response $response, Event $events, Document $project, Database $dbForConsole) { + $rule = $dbForConsole->getDocument('rules', $ruleId); + + if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getInternalId()) { + throw new Exception(Exception::RULE_NOT_FOUND); + } + + $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); + + if (!$target->isKnown() || $target->isTest()) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Domain target must be configured as environment variable.'); + } + + if ($rule->getAttribute('verification') === true) { + return $response->dynamic($rule, Response::MODEL_PROXY_RULE); + } + + $validator = new CNAME($target->get()); // Verify Domain with DNS records + $domain = new Domain($rule->getAttribute('domain', '')); + + if (!$validator->isValid($domain->get())) { + throw new Exception(Exception::RULE_VERIFICATION_FAILED); + } + + $dbForConsole->updateDocument('rules', $rule->getId(), $rule->setAttribute('status', 'verifying')); + + // Issue a TLS certificate when domain is verified + $event = new Certificate(); + $event + ->setDomain(new Document([ + 'domain' => $rule->getAttribute('domain') + ])) + ->trigger(); + + $events->setParam('ruleId', $rule->getId()); + + $certificate = $dbForConsole->getDocument('certificates', $rule->getAttribute('certificateId', '')); + $rule->setAttribute('logs', $certificate->getAttribute('logs', '')); + + $response->dynamic($rule, Response::MODEL_PROXY_RULE); + }); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index c34515b5e1..8cad0aaf8f 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1,6 +1,7 @@ label('event', 'buckets.[bucketId].create') ->label('audits.event', 'bucket.create') ->label('audits.resource', 'bucket/{response.$id}') + ->label('usage.metric', 'buckets.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'createBucket') @@ -62,8 +64,8 @@ App::post('/v1/storage/buckets') ->param('name', '', new Text(128), 'Bucket name') ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true) ->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true) - ->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true) - ->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) + ->param('enabled', true, new Boolean(true), 'Is bucket enabled? When set to \'disabled\', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.', true) + ->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true) ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true) ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) @@ -146,6 +148,7 @@ App::get('/v1/storage/buckets') ->desc('List buckets') ->groups(['api', 'storage']) ->label('scope', 'buckets.read') + ->label('usage.metric', 'buckets.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'listBuckets') @@ -166,7 +169,9 @@ App::get('/v1/storage/buckets') } // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -192,6 +197,7 @@ App::get('/v1/storage/buckets/:bucketId') ->desc('Get Bucket') ->groups(['api', 'storage']) ->label('scope', 'buckets.read') + ->label('usage.metric', 'buckets.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getBucket') @@ -220,6 +226,7 @@ App::put('/v1/storage/buckets/:bucketId') ->label('event', 'buckets.[bucketId].update') ->label('audits.event', 'bucket.update') ->label('audits.resource', 'bucket/{response.$id}') + ->label('usage.metric', 'buckets.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateBucket') @@ -231,8 +238,8 @@ App::put('/v1/storage/buckets/:bucketId') ->param('name', null, new Text(128), 'Bucket name', false) ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true) ->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true) - ->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true) - ->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true) + ->param('enabled', true, new Boolean(true), 'Is bucket enabled? When set to \'disabled\', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.', true) + ->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true) ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true) ->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) @@ -287,6 +294,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->label('audits.event', 'bucket.delete') ->label('event', 'buckets.[bucketId].delete') ->label('audits.resource', 'bucket/{request.bucketId}') + ->label('usage.metric', 'buckets.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteBucket') @@ -329,6 +337,8 @@ App::post('/v1/storage/buckets/:bucketId/files') ->label('audits.event', 'file.create') ->label('event', 'buckets.[bucketId].files.[fileId].create') ->label('audits.resource', 'file/{response.$id}') + ->label('usage.metric', 'files.{scope}.requests.create') + ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}') ->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT) ->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT) @@ -354,10 +364,12 @@ App::post('/v1/storage/buckets/:bucketId/files') ->inject('deviceFiles') ->inject('deviceLocal') ->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -490,13 +502,20 @@ App::post('/v1/storage/buckets/:bucketId/files') $metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)]; if (!$file->isEmpty()) { $chunks = $file->getAttribute('chunksTotal', 1); + $uploaded = $file->getAttribute('chunksUploaded', 0); $metadata = $file->getAttribute('metadata', []); + if ($chunk === -1) { $chunk = $chunks; } + + if ($uploaded === $chunks) { + throw new Exception(Exception::STORAGE_FILE_ALREADY_EXISTS); + } } $chunksUploaded = $deviceFiles->upload($fileTmpName, $path, $chunk, $chunks, $metadata); + if (empty($chunksUploaded)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed uploading file'); } @@ -669,6 +688,8 @@ App::get('/v1/storage/buckets/:bucketId/files') ->groups(['api', 'storage']) ->label('scope', 'files.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) + ->label('usage.metric', 'files.{scope}.requests.read') + ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'listFiles') ->label('sdk.description', '/docs/references/storage/list-files.md') @@ -682,10 +703,12 @@ App::get('/v1/storage/buckets/:bucketId/files') ->inject('dbForProject') ->inject('mode') ->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -703,7 +726,9 @@ App::get('/v1/storage/buckets/:bucketId/files') } // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -744,6 +769,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) + ->label('usage.metric', 'files.{scope}.requests.read') + ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getFile') ->label('sdk.description', '/docs/references/storage/get-file.md') @@ -756,10 +783,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('dbForProject') ->inject('mode') ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, string $mode) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -791,6 +820,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->label('cache', true) ->label('cache.resourceType', 'bucket/{request.bucketId}') ->label('cache.resource', 'file/{request.fileId}') + ->label('usage.metric', 'files.{scope}.requests.read') + ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getFilePreview') @@ -826,7 +857,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -952,6 +986,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->desc('Get File for Download') ->groups(['api', 'storage']) ->label('scope', 'files.read') + ->label('usage.metric', 'files.{scope}.requests.read') + ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getFileDownload') @@ -970,7 +1006,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -1090,6 +1129,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->desc('Get File for View') ->groups(['api', 'storage']) ->label('scope', 'files.read') + ->label('usage.metric', 'files.{scope}.requests.read') + ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getFileView') @@ -1105,10 +1146,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->inject('mode') ->inject('deviceFiles') ->action(function (string $bucketId, string $fileId, Response $response, Request $request, Database $dbForProject, string $mode, Device $deviceFiles) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -1242,6 +1285,8 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->label('event', 'buckets.[bucketId].files.[fileId].update') ->label('audits.event', 'file.update') ->label('audits.resource', 'file/{response.$id}') + ->label('usage.metric', 'files.{scope}.requests.update') + ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}') ->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT) ->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT) @@ -1262,10 +1307,12 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->inject('mode') ->inject('events') ->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $events) { - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -1341,13 +1388,14 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') }); App::delete('/v1/storage/buckets/:bucketId/files/:fileId') - ->alias('/v1/storage/files/:fileId', ['bucketId' => 'default']) ->desc('Delete File') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].delete') ->label('audits.event', 'file.delete') ->label('audits.resource', 'file/{request.fileId}') + ->label('usage.metric', 'files.{scope}.requests.delete') + ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}') ->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT) ->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT) @@ -1368,7 +1416,10 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, string $mode, Device $deviceFiles, Delete $deletes) { $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -1449,62 +1500,103 @@ App::get('/v1/storage/usage') ->inject('dbForProject') ->action(function (string $range, Response $response, Database $dbForProject) { - $periods = Config::getParam('usage', []); - $stats = $usage = []; - $days = $periods[$range]; - $metrics = [ - METRIC_BUCKETS, - METRIC_FILES, - METRIC_FILES_STORAGE, - ]; + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') === 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], + ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { - foreach ($metrics as $metric) { - $limit = $days['limit']; - $period = $days['period']; - $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), - Query::equal('metric', [$metric]), - Query::limit($limit), - Query::orderDesc('time'), - ]); - $stats[$metric] = []; - foreach ($results as $result) { - $stats[$metric][$result->getAttribute('time')] = [ - 'value' => $result->getAttribute('value'), - ]; + $metrics = [ + 'project.$all.storage.size', + 'buckets.$all.count.total', + 'buckets.$all.requests.create', + 'buckets.$all.requests.read', + 'buckets.$all.requests.update', + 'buckets.$all.requests.delete', + 'files.$all.storage.size', + 'files.$all.count.total', + 'files.$all.requests.create', + 'files.$all.requests.read', + 'files.$all.requests.update', + 'files.$all.requests.delete', + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + $stats[$metric] = array_reverse($stats[$metric]); } - } - }); + }); - $format = (match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }); - - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; - } + $usage = new Document([ + 'range' => $range, + 'bucketsCount' => $stats['buckets.$all.count.total'], + 'bucketsCreate' => $stats['buckets.$all.requests.create'], + 'bucketsRead' => $stats['buckets.$all.requests.read'], + 'bucketsUpdate' => $stats['buckets.$all.requests.update'], + 'bucketsDelete' => $stats['buckets.$all.requests.delete'], + 'storage' => $stats['project.$all.storage.size'], + 'filesCount' => $stats['files.$all.count.total'], + 'filesCreate' => $stats['files.$all.requests.create'], + 'filesRead' => $stats['files.$all.requests.read'], + 'filesUpdate' => $stats['files.$all.requests.update'], + 'filesDelete' => $stats['files.$all.requests.delete'], + ]); } - $response->dynamic(new Document([ - 'range' => $range, - 'bucketsTotal' => $usage[$metrics[0]], - 'filesTotal' => $usage[$metrics[1]], - 'filesStorage' => $usage[$metrics[2]], - ]), Response::MODEL_USAGE_STORAGE); + $response->dynamic($usage, Response::MODEL_USAGE_STORAGE); }); App::get('/v1/storage/:bucketId/usage') - ->desc('Get usage stats for storage bucket') + ->desc('Get usage stats for a storage bucket') ->groups(['api', 'storage', 'usage']) ->label('scope', 'files.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) @@ -1525,55 +1617,86 @@ App::get('/v1/storage/:bucketId/usage') throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } - $periods = Config::getParam('usage', []); - $stats = $usage = []; - $days = $periods[$range]; - $metrics = [ - str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES), - str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE), - ]; + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') === 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], + ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { - foreach ($metrics as $metric) { - $limit = $days['limit']; - $period = $days['period']; - $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), - Query::equal('metric', [$metric]), - Query::limit($limit), - Query::orderDesc('time'), - ]); - $stats[$metric] = []; - foreach ($results as $result) { - $stats[$metric][$result->getAttribute('time')] = [ - 'value' => $result->getAttribute('value'), - ]; + $metrics = [ + "files.{$bucketId}.count.total", + "files.{$bucketId}.storage.size", + "files.{$bucketId}.requests.create", + "files.{$bucketId}.requests.read", + "files.{$bucketId}.requests.update", + "files.{$bucketId}.requests.delete", + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + $stats[$metric] = array_reverse($stats[$metric]); } - } - }); + }); - $format = (match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }); - - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; - } + $usage = new Document([ + 'range' => $range, + 'filesCount' => $stats[$metrics[0]], + 'filesStorage' => $stats[$metrics[1]], + 'filesCreate' => $stats[$metrics[2]], + 'filesRead' => $stats[$metrics[3]], + 'filesUpdate' => $stats[$metrics[4]], + 'filesDelete' => $stats[$metrics[5]], + ]); } - $response->dynamic(new Document([ - 'range' => $range, - 'filesTotal' => $usage[$metrics[0]], - 'filesStorage' => $usage[$metrics[1]], - ]), Response::MODEL_USAGE_BUCKETS); + $response->dynamic($usage, Response::MODEL_USAGE_BUCKETS); }); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 0c5398500d..c5dd3eed12 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -153,7 +153,9 @@ App::get('/v1/teams') } // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -442,6 +444,14 @@ App::post('/v1/teams/:teamId/memberships') } } + // Makes sure this email is not already used in another identity + $identityWithMatchingEmail = $dbForProject->findOne('identities', [ + Query::equal('providerEmail', [$email]), + ]); + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } + try { $userId = ID::unique(); $invitee = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([ @@ -472,7 +482,8 @@ App::post('/v1/teams/:teamId/memberships') 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $name]) + 'search' => implode(' ', [$userId, $email, $name]), + 'accessedAt' => DateTime::now(), ]))); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); @@ -532,44 +543,85 @@ App::post('/v1/teams/:teamId/memberships') if (!empty($email)) { $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); - $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); - $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $body = $locale->getText("emails.invitation.body"); $subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName); - - $smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false; $customTemplate = $project->getAttribute('templates', [])['email.invitation-' . $locale->default] ?? []; - if ($smtpEnabled && !empty($customTemplate)) { - $body = $customTemplate['message']; - $subject = $customTemplate['subject']; - $from = $customTemplate['senderName']; + + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); + $message->setParam('{{body}}', $body); + $body = $message->render(); + + $smtp = $project->getAttribute('smtp', []); + $smtpEnabled = $smtp['enabled'] ?? false; + + $senderEmail = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); + $senderName = App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'); + $replyTo = ""; + + if ($smtpEnabled) { + if (!empty($smtp['senderEmail'])) { + $senderEmail = $smtp['senderEmail']; + } + if (!empty($smtp['senderName'])) { + $senderName = $smtp['senderName']; + } + if (!empty($smtp['replyTo'])) { + $replyTo = $smtp['replyTo']; + } + + $mails + ->setSmtpHost($smtp['host'] ?? '') + ->setSmtpPort($smtp['port'] ?? '') + ->setSmtpUsername($smtp['username'] ?? '') + ->setSmtpPassword($smtp['password'] ?? '') + ->setSmtpSecure($smtp['secure'] ?? ''); + + if (!empty($customTemplate)) { + if (!empty($customTemplate['senderEmail'])) { + $senderEmail = $customTemplate['senderEmail']; + } + if (!empty($customTemplate['senderName'])) { + $senderName = $customTemplate['senderName']; + } + if (!empty($customTemplate['replyTo'])) { + $replyTo = $customTemplate['replyTo']; + } + + $body = $customTemplate['message'] ?? ''; + $subject = $customTemplate['subject'] ?? $subject; + } + + $mails + ->setSmtpReplyTo($replyTo) + ->setSmtpSenderEmail($senderEmail) + ->setSmtpSenderName($senderName); } - $body->setParam('{{owner}}', $user->getAttribute('name')); - $body->setParam('{{team}}', $team->getAttribute('name')); - - $body - ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.invitation.hello")) - ->setParam('{{name}}', $user->getAttribute('name')) - ->setParam('{{body}}', $locale->getText("emails.invitation.body")) - ->setParam('{{redirect}}', $url) - ->setParam('{{footer}}', $locale->getText("emails.invitation.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.invitation.signature")) - ->setParam('{{project}}', $projectName) - ->setParam('{{direction}}', $locale->getText('settings.direction')) - ->setParam('{{bg-body}}', '#f7f7f7') - ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{text-content}}', '#000000'); - - $body = $body->render(); + $emailVariables = [ + 'owner' => $user->getAttribute('name'), + 'subject' => $subject, + 'hello' => $locale->getText("emails.invitation.hello"), + 'body' => $body, + 'footer' => $locale->getText("emails.invitation.footer"), + 'thanks' => $locale->getText("emails.invitation.thanks"), + 'signature' => $locale->getText("emails.invitation.signature"), + 'direction' => $locale->getText('settings.direction'), + 'bg-body' => '#f7f7f7', + 'bg-content' => '#ffffff', + 'text-content' => '#000000', + /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ + 'user' => $user->getAttribute('name'), + 'team' => $team->getAttribute('name'), + 'project' => $projectName, + 'redirect' => $url + ]; $mails ->setSubject($subject) ->setBody($body) - ->setFrom($from) ->setRecipient($invitee->getAttribute('email')) ->setName($invitee->getAttribute('name')) + ->setVariables($emailVariables) ->trigger() ; } elseif (!empty($phone)) { @@ -641,7 +693,9 @@ App::get('/v1/teams/:teamId/memberships') $queries[] = Query::equal('teamId', [$teamId]); // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -731,7 +785,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') }); App::patch('/v1/teams/:teamId/memberships/:membershipId') - ->desc('Update Membership Roles') + ->desc('Update Membership') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update') ->label('scope', 'teams.write') @@ -739,8 +793,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') - ->label('sdk.method', 'updateMembershipRoles') - ->label('sdk.description', '/docs/references/teams/update-team-membership-roles.md') + ->label('sdk.method', 'updateMembership') + ->label('sdk.description', '/docs/references/teams/update-team-membership.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MEMBERSHIP) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index c3129d41eb..c6d9b2d4e3 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -8,6 +8,7 @@ use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Network\Validator\Email; use Appwrite\Utopia\Database\Validator\CustomId; +use Appwrite\Utopia\Database\Validator\Queries\Identities; use Utopia\Database\Validator\Queries; use Appwrite\Utopia\Database\Validator\Queries\Users; use Utopia\Database\Validator\Query\Limit; @@ -47,6 +48,14 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e if (!empty($email)) { $email = \strtolower($email); + + // Makes sure this email is not already used in another identity + $identityWithMatchingEmail = $dbForProject->findOne('identities', [ + Query::equal('providerEmail', [$email]), + ]); + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } } try { @@ -87,7 +96,8 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'sessions' => null, 'tokens' => null, 'memberships' => null, - 'search' => implode(' ', [$userId, $email, $phone, $name]) + 'search' => implode(' ', [$userId, $email, $phone, $name]), + 'accessedAt' => DateTime::now(), ])); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); @@ -105,6 +115,7 @@ App::post('/v1/users') ->label('scope', 'users.write') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'create') @@ -137,6 +148,7 @@ App::post('/v1/users/bcrypt') ->label('scope', 'users.write') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createBcryptUser') @@ -167,6 +179,7 @@ App::post('/v1/users/md5') ->label('scope', 'users.write') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createMD5User') @@ -197,6 +210,7 @@ App::post('/v1/users/argon2') ->label('scope', 'users.write') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createArgon2User') @@ -227,6 +241,7 @@ App::post('/v1/users/sha') ->label('scope', 'users.write') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createSHAUser') @@ -264,6 +279,7 @@ App::post('/v1/users/phpass') ->label('scope', 'users.write') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createPHPassUser') @@ -294,6 +310,7 @@ App::post('/v1/users/scrypt') ->label('scope', 'users.write') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createScryptUser') @@ -337,6 +354,7 @@ App::post('/v1/users/scrypt-modified') ->label('scope', 'users.write') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'createScryptModifiedUser') @@ -367,6 +385,7 @@ App::get('/v1/users') ->desc('List Users') ->groups(['api', 'users']) ->label('scope', 'users.read') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'list') @@ -387,7 +406,9 @@ App::get('/v1/users') } // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); $cursor = reset($cursor); if ($cursor) { /** @var Query $cursor */ @@ -413,6 +434,7 @@ App::get('/v1/users/:userId') ->desc('Get User') ->groups(['api', 'users']) ->label('scope', 'users.read') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'get') @@ -438,6 +460,7 @@ App::get('/v1/users/:userId/prefs') ->desc('Get User Preferences') ->groups(['api', 'users']) ->label('scope', 'users.read') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'getPrefs') @@ -465,6 +488,7 @@ App::get('/v1/users/:userId/sessions') ->desc('List User Sessions') ->groups(['api', 'users']) ->label('scope', 'users.read') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'listSessions') @@ -506,6 +530,7 @@ App::get('/v1/users/:userId/memberships') ->desc('List User Memberships') ->groups(['api', 'users']) ->label('scope', 'users.read') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'listMemberships') @@ -545,6 +570,7 @@ App::get('/v1/users/:userId/logs') ->desc('List User Logs') ->groups(['api', 'users']) ->label('scope', 'users.read') + ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'listLogs') @@ -622,6 +648,55 @@ App::get('/v1/users/:userId/logs') ]), Response::MODEL_LOG_LIST); }); +App::get('/v1/users/identities') + ->desc('List Identities') + ->groups(['api', 'users']) + ->label('scope', 'users.read') + ->label('usage.metric', 'users.{scope}.requests.read') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'users') + ->label('sdk.method', 'listIdentities') + ->label('sdk.description', '/docs/references/users/list-identities.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_IDENTITY_LIST) + ->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Identities::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) + ->inject('response') + ->inject('dbForProject') + ->action(function (array $queries, string $search, Response $response, Database $dbForProject) { + + $queries = Query::parseQueries($queries); + + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + + // Get cursor document if there was a cursor query + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + }); + $cursor = reset($cursor); + if ($cursor) { + /** @var Query $cursor */ + $identityId = $cursor->getValue(); + $cursorDocument = $dbForProject->getDocument('identities', $identityId); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "User '{$identityId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + + $filterQueries = Query::groupByType($queries)['filters']; + + $response->dynamic(new Document([ + 'identities' => $dbForProject->find('identities', $queries), + 'total' => $dbForProject->count('identities', $filterQueries, APP_LIMIT_COUNT), + ]), Response::MODEL_IDENTITY_LIST); + }); + App::patch('/v1/users/:userId/status') ->desc('Update User Status') ->groups(['api', 'users']) @@ -630,6 +705,7 @@ App::patch('/v1/users/:userId/status') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateStatus') @@ -665,7 +741,6 @@ App::put('/v1/users/:userId/labels') ->label('scope', 'users.write') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') - ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') @@ -697,41 +772,6 @@ App::put('/v1/users/:userId/labels') $response->dynamic($user, Response::MODEL_USER); }); -App::patch('/v1/users/:userId/verification') - ->desc('Update Email Verification') - ->groups(['api', 'users']) - ->label('event', 'users.[userId].update.verification') - ->label('scope', 'users.write') - ->label('audits.event', 'verification.update') - ->label('audits.resource', 'user/{response.$id}') - ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'users') - ->label('sdk.method', 'updateEmailVerification') - ->label('sdk.description', '/docs/references/users/update-user-email-verification.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_USER) - ->param('userId', '', new UID(), 'User ID.') - ->param('emailVerification', false, new Boolean(), 'User email verification status.') - ->inject('response') - ->inject('dbForProject') - ->inject('events') - ->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) { - - $user = $dbForProject->getDocument('users', $userId); - - if ($user->isEmpty()) { - throw new Exception(Exception::USER_NOT_FOUND); - } - - $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', $emailVerification)); - - $events - ->setParam('userId', $user->getId()); - - $response->dynamic($user, Response::MODEL_USER); - }); - App::patch('/v1/users/:userId/verification/phone') ->desc('Update Phone Verification') ->groups(['api', 'users']) @@ -739,6 +779,7 @@ App::patch('/v1/users/:userId/verification/phone') ->label('scope', 'users.write') ->label('audits.event', 'verification.update') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePhoneVerification') @@ -775,6 +816,7 @@ App::patch('/v1/users/:userId/name') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateName') @@ -812,6 +854,7 @@ App::patch('/v1/users/:userId/password') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePassword') @@ -876,6 +919,7 @@ App::patch('/v1/users/:userId/email') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateEmail') @@ -898,6 +942,15 @@ App::patch('/v1/users/:userId/email') $email = \strtolower($email); + // Makes sure this email is not already used in another identity + $identityWithMatchingEmail = $dbForProject->findOne('identities', [ + Query::equal('providerEmail', [$email]), + Query::notEqual('userId', $user->getId()), + ]); + if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } + $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) @@ -922,6 +975,7 @@ App::patch('/v1/users/:userId/phone') ->label('scope', 'users.write') ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePhone') @@ -966,6 +1020,7 @@ App::patch('/v1/users/:userId/verification') ->label('audits.event', 'verification.update') ->label('audits.resource', 'user/{request.userId}') ->label('audits.userId', '{request.userId}') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateEmailVerification') @@ -998,6 +1053,7 @@ App::patch('/v1/users/:userId/prefs') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'users.write') + ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'updatePrefs') @@ -1033,6 +1089,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId') ->label('scope', 'users.write') ->label('audits.event', 'session.delete') ->label('audits.resource', 'user/{request.userId}') + ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'deleteSession') @@ -1076,6 +1133,7 @@ App::delete('/v1/users/:userId/sessions') ->label('scope', 'users.write') ->label('audits.event', 'session.delete') ->label('audits.resource', 'user/{user.$id}') + ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'deleteSessions') @@ -1118,6 +1176,7 @@ App::delete('/v1/users/:userId') ->label('scope', 'users.write') ->label('audits.event', 'user.delete') ->label('audits.resource', 'user/{request.userId}') + ->label('usage.metric', 'users.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'users') ->label('sdk.method', 'delete') @@ -1153,6 +1212,38 @@ App::delete('/v1/users/:userId') $response->noContent(); }); +App::delete('/v1/users/identities/:identityId') + ->desc('Delete Identity') + ->groups(['api', 'users']) + ->label('event', 'users.[userId].identities.[identityId].delete') + ->label('scope', 'users.write') + ->label('audits.event', 'identity.delete') + ->label('audits.resource', 'identity/{request.$identityId}') + ->label('usage.metric', 'users.{scope}.requests.delete') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'users') + ->label('sdk.method', 'deleteIdentity') + ->label('sdk.description', '/docs/references/users/delete-identity.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('identityId', '', new UID(), 'Identity ID.') + ->inject('response') + ->inject('dbForProject') + ->inject('events') + ->inject('deletes') + ->action(function (string $identityId, Response $response, Database $dbForProject, Event $events, Delete $deletes) { + + $identity = $dbForProject->getDocument('identities', $identityId); + + if ($identity->isEmpty()) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + $dbForProject->deleteDocument('identities', $identityId); + + return $response->noContent(); + }); + App::get('/v1/users/usage') ->desc('Get usage stats for the users API') ->groups(['api', 'users', 'usage']) @@ -1164,59 +1255,96 @@ App::get('/v1/users/usage') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_USAGE_USERS) ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true) + ->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('providers', [])))), true), 'Provider Name.', true) ->inject('response') ->inject('dbForProject') ->inject('register') - ->action(function (string $range, Response $response, Database $dbForProject) { + ->action(function (string $range, string $provider, Response $response, Database $dbForProject) { - $periods = Config::getParam('usage', []); - $stats = $usage = []; - $days = $periods[$range]; - $metrics = [ - METRIC_USERS, - METRIC_SESSIONS, - ]; - - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { - foreach ($metrics as $metric) { - $limit = $days['limit']; - $period = $days['period']; - $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), - Query::equal('metric', [$metric]), - Query::limit($limit), - Query::orderDesc('time'), - ]); - $stats[$metric] = []; - foreach ($results as $result) { - $stats[$metric][$result->getAttribute('time')] = [ - 'value' => $result->getAttribute('value'), - ]; - } - } - }); - - $format = match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }; - - foreach ($metrics as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ - 'value' => $stats[$metric][$formatDate]['value'] ?? 0, - 'date' => $formatDate, + $usage = []; + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $periods = [ + '24h' => [ + 'period' => '1h', + 'limit' => 24, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + ], ]; - } - } - $response->dynamic(new Document([ - 'range' => $range, - 'usersTotal' => $usage[$metrics[0]], - 'sessionsTotal' => $usage[$metrics[1]], - ]), Response::MODEL_USAGE_USERS); + $metrics = [ + 'users.$all.count.total', + 'users.$all.requests.create', + 'users.$all.requests.read', + 'users.$all.requests.update', + 'users.$all.requests.delete', + 'sessions.$all.requests.create', + 'sessions.$all.requests.delete', + "sessions.$provider.requests.create", + ]; + + $stats = []; + + Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $periods[$range]['limit']; + $period = $periods[$range]['period']; + + $requestDocs = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); + + $stats[$metric] = []; + foreach ($requestDocs as $requestDoc) { + $stats[$metric][] = [ + 'value' => $requestDoc->getAttribute('value'), + 'date' => $requestDoc->getAttribute('time'), + ]; + } + + // backfill metrics with empty values for graphs + $backfill = $limit - \count($requestDocs); + while ($backfill > 0) { + $last = $limit - $backfill - 1; // array index of last added metric + $diff = match ($period) { // convert period to seconds for unix timestamp math + '1h' => 3600, + '1d' => 86400, + }; + $stats[$metric][] = [ + 'value' => 0, + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), + ]; + $backfill--; + } + $stats[$metric] = array_reverse($stats[$metric]); + } + }); + + $usage = new Document([ + 'range' => $range, + 'usersCount' => $stats['users.$all.count.total'] ?? [], + 'usersCreate' => $stats['users.$all.requests.create'] ?? [], + 'usersRead' => $stats['users.$all.requests.read'] ?? [], + 'usersUpdate' => $stats['users.$all.requests.update'] ?? [], + 'usersDelete' => $stats['users.$all.requests.delete'] ?? [], + 'sessionsCreate' => $stats['sessions.$all.requests.create'] ?? [], + 'sessionsProviderCreate' => $stats["sessions.$provider.requests.create"] ?? [], + 'sessionsDelete' => $stats['sessions.$all.requests.delete' ?? []] + ]); + } + + $response->dynamic($usage, Response::MODEL_USAGE_USERS); }); diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php new file mode 100644 index 0000000000..543a7e6b8b --- /dev/null +++ b/app/controllers/api/vcs.php @@ -0,0 +1,1090 @@ +getAttribute('resourceType'); + + if ($resourceType === "function") { + $projectId = $resource->getAttribute('projectId'); + $project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId)); + $dbForProject = $getProjectDB($project); + + $functionId = $resource->getAttribute('resourceId'); + $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); + + $deploymentId = ID::unique(); + $repositoryId = $resource->getId(); + $repositoryInternalId = $resource->getInternalId(); + $providerRepositoryId = $resource->getAttribute('providerRepositoryId'); + $installationId = $resource->getAttribute('installationId'); + $installationInternalId = $resource->getAttribute('installationInternalId'); + $productionBranch = $function->getAttribute('providerBranch'); + $activate = false; + + if ($providerBranch == $productionBranch && $external === false) { + $activate = true; + } + + $owner = $github->getOwnerName($providerInstallationId) ?? ''; + $repositoryName = $github->getRepositoryName($providerRepositoryId) ?? ''; + + if (empty($repositoryName)) { + throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND); + } + + $isAuthorized = !$external; + + if (!$isAuthorized && !empty($providerPullRequestId)) { + if (\in_array($providerPullRequestId, $resource->getAttribute('providerPullRequestIds', []))) { + $isAuthorized = true; + } + } + + $commentStatus = $isAuthorized ? 'waiting' : 'failed'; + + $authorizeUrl = $request->getProtocol() . '://' . $request->getHostname() . "/git/authorize-contributor?projectId={$projectId}&installationId={$installationId}&repositoryId={$repositoryId}&providerPullRequestId={$providerPullRequestId}"; + + $action = $isAuthorized ? ['type' => 'logs'] : ['type' => 'authorize', 'url' => $authorizeUrl]; + + $latestCommentId = ''; + + if (!empty($providerPullRequestId)) { + $latestComment = Authorization::skip(fn () => $dbForConsole->findOne('vcsComments', [ + Query::equal('providerRepositoryId', [$providerRepositoryId]), + Query::equal('providerPullRequestId', [$providerPullRequestId]), + Query::orderDesc('$createdAt'), + ])); + + if ($latestComment !== false && !$latestComment->isEmpty()) { + $latestCommentId = $latestComment->getAttribute('providerCommentId', ''); + $comment = new Comment(); + $comment->parseComment($github->getComment($owner, $repositoryName, $latestCommentId)); + $comment->addBuild($project, $function, $commentStatus, $deploymentId, $action); + + $latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment())); + } else { + $comment = new Comment(); + $comment->addBuild($project, $function, $commentStatus, $deploymentId, $action); + $latestCommentId = \strval($github->createComment($owner, $repositoryName, $providerPullRequestId, $comment->generateComment())); + + if (!empty($latestCommentId)) { + $teamId = $project->getAttribute('teamId', ''); + + $latestComment = Authorization::skip(fn () => $dbForConsole->createDocument('vcsComments', new Document([ + '$id' => ID::unique(), + '$permissions' => [ + Permission::read(Role::team(ID::custom($teamId))), + Permission::update(Role::team(ID::custom($teamId), 'owner')), + Permission::update(Role::team(ID::custom($teamId), 'developer')), + Permission::delete(Role::team(ID::custom($teamId), 'owner')), + Permission::delete(Role::team(ID::custom($teamId), 'developer')), + ], + 'installationInternalId' => $installationInternalId, + 'installationId' => $installationId, + 'projectInternalId' => $project->getInternalId(), + 'projectId' => $project->getId(), + 'providerRepositoryId' => $providerRepositoryId, + 'providerBranch' => $providerBranch, + 'providerPullRequestId' => $providerPullRequestId, + 'providerCommentId' => $latestCommentId + ]))); + } + } + } elseif (!empty($providerBranch)) { + $latestComments = Authorization::skip(fn () => $dbForConsole->find('vcsComments', [ + Query::equal('providerRepositoryId', [$providerRepositoryId]), + Query::equal('providerBranch', [$providerBranch]), + Query::orderDesc('$createdAt'), + ])); + + foreach ($latestComments as $comment) { + $latestCommentId = $comment->getAttribute('providerCommentId', ''); + $comment = new Comment(); + $comment->parseComment($github->getComment($owner, $repositoryName, $latestCommentId)); + $comment->addBuild($project, $function, $commentStatus, $deploymentId, $action); + + $latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment())); + } + } + + if (!$isAuthorized) { + $functionName = $function->getAttribute('name'); + $projectName = $project->getAttribute('name'); + $name = "{$functionName} ({$projectName})"; + $message = 'Authorization required for external contributor.'; + + $providerRepositoryId = $resource->getAttribute('providerRepositoryId'); + $repositoryName = $github->getRepositoryName($providerRepositoryId); + $owner = $github->getOwnerName($providerInstallationId); + $github->updateCommitStatus($repositoryName, $providerCommitHash, $owner, 'failure', $message, $authorizeUrl, $name); + continue; + } + + if ($external) { + $pullRequestResponse = $github->getPullRequest($owner, $repositoryName, $providerPullRequestId); + $providerRepositoryName = $pullRequestResponse['head']['repo']['owner']['login']; + $providerRepositoryOwner = $pullRequestResponse['head']['repo']['name']; + } + + $deployment = $dbForProject->createDocument('deployments', new Document([ + '$id' => $deploymentId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'resourceId' => $functionId, + 'resourceType' => 'functions', + 'entrypoint' => $function->getAttribute('entrypoint'), + 'commands' => $function->getAttribute('commands'), + 'type' => 'vcs', + 'installationId' => $installationId, + 'installationInternalId' => $installationInternalId, + 'providerRepositoryId' => $providerRepositoryId, + 'repositoryId' => $repositoryId, + 'repositoryInternalId' => $repositoryInternalId, + 'providerBranchUrl' => $providerBranchUrl, + 'providerRepositoryName' => $providerRepositoryName, + 'providerRepositoryOwner' => $providerRepositoryOwner, + 'providerRepositoryUrl' => $providerRepositoryUrl, + 'providerCommitHash' => $providerCommitHash, + 'providerCommitAuthorUrl' => $providerCommitAuthorUrl, + 'providerCommitAuthor' => $providerCommitAuthor, + 'providerCommitMessage' => $providerCommitMessage, + 'providerCommitUrl' => $providerCommitUrl, + 'providerCommentId' => \strval($latestCommentId), + 'providerBranch' => $providerBranch, + 'search' => implode(' ', [$deploymentId, $function->getAttribute('entrypoint')]), + 'activate' => $activate, + ])); + + if (!empty($providerCommitHash) && $function->getAttribute('providerSilentMode', false) === false) { + $functionName = $function->getAttribute('name'); + $projectName = $project->getAttribute('name'); + $name = "{$functionName} ({$projectName})"; + $message = 'Starting...'; + + $providerRepositoryId = $resource->getAttribute('providerRepositoryId'); + $repositoryName = $github->getRepositoryName($providerRepositoryId); + $owner = $github->getOwnerName($providerInstallationId); + + $providerTargetUrl = $request->getProtocol() . '://' . $request->getHostname() . "/console/project-$projectId/functions/function-$functionId"; + $github->updateCommitStatus($repositoryName, $providerCommitHash, $owner, 'pending', $message, $providerTargetUrl, $name); + } + + $buildEvent = new Build(); + $buildEvent + ->setType(BUILD_TYPE_DEPLOYMENT) + ->setResource($function) + ->setDeployment($deployment) + ->setProject($project) + ->trigger(); + + //TODO: Add event? + } + } +}; + +App::get('/v1/vcs/github/authorize') + ->desc('Install GitHub App') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.read') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'createGitHubInstallation') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_MOVED_PERMANENTLY) + ->label('sdk.response.type', Response::CONTENT_TYPE_HTML) + ->label('sdk.methodType', 'webAuth') + ->label('sdk.hide', true) + ->param('success', '', fn ($clients) => new Host($clients), 'URL to redirect back to console after a successful installation attempt.', true, ['clients']) + ->param('failure', '', fn ($clients) => new Host($clients), 'URL to redirect back to console after a failed installation attempt.', true, ['clients']) + ->inject('request') + ->inject('response') + ->inject('project') + ->action(function (string $success, string $failure, Request $request, Response $response, Document $project) { + $state = \json_encode([ + 'projectId' => $project->getId(), + 'success' => $success, + 'failure' => $failure, + ]); + + $appName = App::getEnv('_APP_VCS_GITHUB_APP_NAME'); + $url = "https://github.com/apps/$appName/installations/new?" . \http_build_query([ + 'state' => $state, + 'redirect_uri' => $request->getProtocol() . '://' . $request->getHostname() . "/v1/vcs/github/callback" + ]); + + $response + ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->addHeader('Pragma', 'no-cache') + ->redirect($url); + }); + +App::get('/v1/vcs/github/callback') + ->desc('Capture installation and authorization from GitHub App') + ->groups(['api', 'vcs']) + ->label('scope', 'public') + ->label('error', __DIR__ . '/../../views/general/error.phtml') + ->param('installation_id', '', new Text(256, 0), 'GitHub installation ID', true) + ->param('setup_action', '', new Text(256, 0), 'GitHub setup actuon type', true) + ->param('state', '', new Text(2048), 'GitHub state. Contains info sent when starting authorization flow.', true) + ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) + ->inject('gitHub') + ->inject('user') + ->inject('project') + ->inject('request') + ->inject('response') + ->inject('dbForConsole') + ->action(function (string $providerInstallationId, string $setupAction, string $state, string $code, GitHub $github, Document $user, Document $project, Request $request, Response $response, Database $dbForConsole) { + if (empty($state)) { + $error = 'Installation requests from organisation members for the Appwrite GitHub App are currently unsupported. To proceed with the installation, login to the Appwrite Console and install the GitHub App.'; + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $error); + } + + $state = \json_decode($state, true); + $projectId = $state['projectId'] ?? ''; + + $defaultState = [ + 'success' => $request->getProtocol() . '://' . $request->getHostname() . "/console/project-$projectId/settings/git-installations", + 'failure' => $request->getProtocol() . '://' . $request->getHostname() . "/console/project-$projectId/settings/git-installations", + ]; + + $state = \array_merge($defaultState, $state ?? []); + + $redirectSuccess = $state['success'] ?? ''; + $redirectFailure = $state['failure'] ?? ''; + + $project = $dbForConsole->getDocument('projects', $projectId); + + if ($project->isEmpty()) { + $error = 'Project with the ID from state could not be found.'; + + if (!empty($redirectFailure)) { + $separator = \str_contains($redirectFailure, '?') ? '&' : ':'; + return $response + ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->addHeader('Pragma', 'no-cache') + ->redirect($redirectFailure . $separator . \http_build_query(['error' => $error])); + } + + throw new Exception(Exception::PROJECT_NOT_FOUND, $error); + } + + $personalSlug = ''; + + // OAuth Authroization + if (!empty($code)) { + $oauth2 = new OAuth2Github(App::getEnv('_APP_VCS_GITHUB_CLIENT_ID', ''), App::getEnv('_APP_VCS_GITHUB_CLIENT_SECRET', ''), ""); + $accessToken = $oauth2->getAccessToken($code) ?? ''; + $refreshToken = $oauth2->getRefreshToken($code) ?? ''; + $accessTokenExpiry = $oauth2->getAccessTokenExpiry($code) ?? ''; + $personalSlug = $oauth2->getUserSlug($accessToken) ?? ''; + $email = $oauth2->getUserEmail($accessToken); + $oauth2ID = $oauth2->getUserID($accessToken); + + // Makes sure this email is not already used in another identity + $identity = $dbForConsole->findOne('identities', [ + Query::equal('providerEmail', [$email]), + ]); + if ($identity !== false && !$identity->isEmpty()) { + if ($identity->getAttribute('userInternalId', '') !== $user->getInternalId()) { + throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); + } + } + + if ($identity !== false && !$identity->isEmpty()) { + $identity = $identity + ->setAttribute('providerAccessToken', $accessToken) + ->setAttribute('providerRefreshToken', $refreshToken) + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry)); + + $dbForConsole->updateDocument('identities', $identity->getId(), $identity); + } else { + $identity = $dbForConsole->createDocument('identities', new Document([ + '$id' => ID::unique(), + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], + 'userInternalId' => $user->getInternalId(), + 'userId' => $user->getId(), + 'provider' => 'github', + 'providerUid' => $oauth2ID, + 'providerEmail' => $email, + 'providerAccessToken' => $accessToken, + 'providerRefreshToken' => $refreshToken, + 'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry), + ])); + } + } + + // Create / Update installation + if (!empty($providerInstallationId)) { + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + $owner = $github->getOwnerName($providerInstallationId) ?? ''; + + $projectInternalId = $project->getInternalId(); + + $installation = $dbForConsole->findOne('installations', [ + Query::equal('providerInstallationId', [$providerInstallationId]), + Query::equal('projectInternalId', [$projectInternalId]) + ]); + + if ($installation === false || $installation->isEmpty()) { + $teamId = $project->getAttribute('teamId', ''); + + $installation = new Document([ + '$id' => ID::unique(), + '$permissions' => [ + Permission::read(Role::team(ID::custom($teamId))), + Permission::update(Role::team(ID::custom($teamId), 'owner')), + Permission::update(Role::team(ID::custom($teamId), 'developer')), + Permission::delete(Role::team(ID::custom($teamId), 'owner')), + Permission::delete(Role::team(ID::custom($teamId), 'developer')), + ], + 'providerInstallationId' => $providerInstallationId, + 'projectId' => $projectId, + 'projectInternalId' => $projectInternalId, + 'provider' => 'github', + 'organization' => $owner, + 'personal' => $personalSlug === $owner + ]); + + $installation = $dbForConsole->createDocument('installations', $installation); + } else { + $installation = $installation + ->setAttribute('organization', $owner) + ->setAttribute('personal', $personalSlug === $owner); + $installation = $dbForConsole->updateDocument('installations', $installation->getId(), $installation); + } + } else { + $error = 'Installation of the Appwrite GitHub App on organization accounts is restricted to organization owners. As a member of the organization, you do not have the necessary permissions to install this GitHub App. Please contact the organization owner to create the installation from the Appwrite console.'; + + if (!empty($redirectFailure)) { + $separator = \str_contains($redirectFailure, '?') ? '&' : ':'; + return $response + ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->addHeader('Pragma', 'no-cache') + ->redirect($redirectFailure . $separator . \http_build_query(['error' => $error])); + } + + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $error); + } + + $response + ->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->addHeader('Pragma', 'no-cache') + ->redirect($redirectSuccess); + }); + +App::post('/v1/vcs/github/installations/:installationId/providerRepositories/:providerRepositoryId/detection') + ->desc('Detect runtime settings from source code') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.write') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'createRepositoryDetection') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_DETECTION) + ->param('installationId', '', new Text(256), 'Installation Id') + ->param('providerRepositoryId', '', new Text(256), 'Repository Id') + ->param('providerRootDirectory', '', new Text(256, 0), 'Path to Root Directory', true) + ->inject('gitHub') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->action(function (string $installationId, string $providerRepositoryId, string $providerRootDirectory, GitHub $github, Response $response, Document $project, Database $dbForConsole) { + $installation = $dbForConsole->getDocument('installations', $installationId); + + if ($installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + $providerInstallationId = $installation->getAttribute('providerInstallationId'); + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + + $owner = $github->getOwnerName($providerInstallationId); + $repositoryName = $github->getRepositoryName($providerRepositoryId); + + if (empty($repositoryName)) { + throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND); + } + + $files = $github->listRepositoryContents($owner, $repositoryName, $providerRootDirectory); + $languages = $github->listRepositoryLanguages($owner, $repositoryName); + + $detectorFactory = new Detector($files, $languages); + + $detectorFactory + ->addDetector(new JavaScript()) + ->addDetector(new PHP()) + ->addDetector(new Python()) + ->addDetector(new Dart()) + ->addDetector(new Swift()) + ->addDetector(new Ruby()) + ->addDetector(new Java()) + ->addDetector(new CPP()) + ->addDetector(new Deno()) + ->addDetector(new Dotnet()); + + $runtime = $detectorFactory->detect(); + + $runtimes = Config::getParam('runtimes'); + $runtimeDetail = \array_reverse(\array_filter(\array_keys($runtimes), function ($key) use ($runtime, $runtimes) { + return $runtimes[$key]['key'] === $runtime; + }))[0] ?? ''; + + $detection = []; + $detection['runtime'] = $runtimeDetail; + + $response->dynamic(new Document($detection), Response::MODEL_DETECTION); + }); + +App::get('/v1/vcs/github/installations/:installationId/providerRepositories') + ->desc('List Repositories') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.read') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'listRepositories') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER_REPOSITORY_LIST) + ->param('installationId', '', new Text(256), 'Installation Id') + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) + ->inject('gitHub') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->action(function (string $installationId, string $search, GitHub $github, Response $response, Document $project, Database $dbForConsole) { + if (empty($search)) { + $search = ""; + } + + $installation = $dbForConsole->getDocument('installations', $installationId); + + if ($installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + $providerInstallationId = $installation->getAttribute('providerInstallationId'); + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + + $page = 1; + $perPage = 4; + + $owner = $github->getOwnerName($providerInstallationId); + $repos = $github->searchRepositories($owner, $page, $perPage, $search); + + $repos = \array_map(function ($repo) use ($installation) { + $repo['id'] = \strval($repo['id'] ?? ''); + $repo['pushedAt'] = $repo['pushed_at'] ?? null; + $repo['provider'] = $installation->getAttribute('provider', '') ?? ''; + $repo['organization'] = $installation->getAttribute('organization', '') ?? ''; + return $repo; + }, $repos); + + $repos = batch(\array_map(function ($repo) use ($github) { + return function () use ($repo, $github) { + try { + $files = $github->listRepositoryContents($repo['organization'], $repo['name'], ''); + $languages = $github->listRepositoryLanguages($repo['organization'], $repo['name']); + + $detectorFactory = new Detector($files, $languages); + + $detectorFactory + ->addDetector(new JavaScript()) + ->addDetector(new PHP()) + ->addDetector(new Python()) + ->addDetector(new Dart()) + ->addDetector(new Swift()) + ->addDetector(new Ruby()) + ->addDetector(new Java()) + ->addDetector(new CPP()) + ->addDetector(new Deno()) + ->addDetector(new Dotnet()); + + $runtime = $detectorFactory->detect(); + + $runtimes = Config::getParam('runtimes'); + $runtimeDetail = \array_reverse(\array_filter(\array_keys($runtimes), function ($key) use ($runtime, $runtimes) { + return $runtimes[$key]['key'] === $runtime; + }))[0] ?? ''; + + $repo['runtime'] = $runtimeDetail; + } catch (Throwable $error) { + $repo['runtime'] = ""; + Console::warning("Runtime not detected for " . $repo['organization'] . "/" . $repo['name']); + } + return $repo; + }; + }, $repos)); + + $repos = \array_map(function ($repo) { + return new Document($repo); + }, $repos); + + $response->dynamic(new Document([ + 'providerRepositories' => $repos, + 'total' => \count($repos), + ]), Response::MODEL_PROVIDER_REPOSITORY_LIST); + }); + +App::post('/v1/vcs/github/installations/:installationId/providerRepositories') + ->desc('Create repository') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.write') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'createRepository') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER_REPOSITORY) + ->param('installationId', '', new Text(256), 'Installation Id') + ->param('name', '', new Text(256), 'Repository name (slug)') + ->param('private', '', new Boolean(false), 'Mark repository public or private') + ->inject('gitHub') + ->inject('user') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->action(function (string $installationId, string $name, bool $private, GitHub $github, Document $user, Response $response, Document $project, Database $dbForConsole) { + $installation = $dbForConsole->getDocument('installations', $installationId); + + if ($installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + if ($installation->getAttribute('personal', false) === true) { + $oauth2 = new OAuth2Github(App::getEnv('_APP_VCS_GITHUB_CLIENT_ID', ''), App::getEnv('_APP_VCS_GITHUB_CLIENT_SECRET', ''), ""); + + $identity = $dbForConsole->findOne('identities', [ + Query::equal('provider', ['github']), + Query::equal('userInternalId', [$user->getInternalId()]), + ]); + if ($identity === false || $identity->isEmpty()) { + throw new Exception(Exception::USER_IDENTITY_NOT_FOUND); + } + + $accessToken = $identity->getAttribute('providerAccessToken'); + $refreshToken = $identity->getAttribute('providerRefreshToken'); + $accessTokenExpiry = $identity->getAttribute('providerAccessTokenExpiry'); + + $isExpired = new \DateTime($accessTokenExpiry) < new \DateTime('now'); + if ($isExpired) { + $oauth2->refreshTokens($refreshToken); + + $accessToken = $oauth2->getAccessToken(''); + $refreshToken = $oauth2->getRefreshToken(''); + + $verificationId = $oauth2->getUserID($accessToken); + + if (empty($verificationId)) { + throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED, "Another request is currently refreshing OAuth token. Please try again."); + } + + $identity = $identity + ->setAttribute('providerAccessToken', $accessToken) + ->setAttribute('providerRefreshToken', $refreshToken) + ->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry(''))); + + $dbForConsole->updateDocument('identities', $identity->getId(), $identity); + } + + try { + $repository = $oauth2->createRepository($accessToken, $name, $private); + } catch (Exception $exception) { + throw new Exception(Exception::GENERAL_PROVIDER_FAILURE, "GitHub failed to process the request: " . $exception->getMessage()); + } + } else { + $providerInstallationId = $installation->getAttribute('providerInstallationId'); + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + $owner = $github->getOwnerName($providerInstallationId); + + try { + $repository = $github->createRepository($owner, $name, $private); + } catch (Exception $exception) { + throw new Exception(Exception::GENERAL_PROVIDER_FAILURE, "GitHub failed to process the request: " . $exception->getMessage()); + } + } + + if (isset($repository['errors'])) { + $message = $repository['message'] ?? 'Unknown error.'; + if (isset($repository['errors'][0])) { + $message .= ' ' . $repository['errors'][0]['message']; + } + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Provider Error: ' . $message); + } + + if (isset($repository['message'])) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Provider Error: ' . $repository['message']); + } + + $repository['id'] = \strval($repository['id']) ?? ''; + $repository['pushedAt'] = $repository['pushed_at'] ?? ''; + $repository['organization'] = $installation->getAttribute('organization', ''); + $repository['provider'] = $installation->getAttribute('provider', ''); + + $response->dynamic(new Document($repository), Response::MODEL_PROVIDER_REPOSITORY); + }); + +App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:providerRepositoryId') + ->desc('Get repository') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.read') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'getRepository') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER_REPOSITORY) + ->param('installationId', '', new Text(256), 'Installation Id') + ->param('providerRepositoryId', '', new Text(256), 'Repository Id') + ->inject('gitHub') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->action(function (string $installationId, string $providerRepositoryId, GitHub $github, Response $response, Document $project, Database $dbForConsole) { + $installation = $dbForConsole->getDocument('installations', $installationId); + + if ($installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + $providerInstallationId = $installation->getAttribute('providerInstallationId'); + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + + $owner = $github->getOwnerName($providerInstallationId) ?? ''; + $repositoryName = $github->getRepositoryName($providerRepositoryId) ?? ''; + + if (empty($repositoryName)) { + throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND); + } + + $repository = $github->getRepository($owner, $repositoryName); + + $repository['id'] = \strval($repository['id']) ?? ''; + $repository['pushedAt'] = $repository['pushed_at'] ?? ''; + $repository['organization'] = $installation->getAttribute('organization', ''); + $repository['provider'] = $installation->getAttribute('provider', ''); + + $response->dynamic(new Document($repository), Response::MODEL_PROVIDER_REPOSITORY); + }); + +App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:providerRepositoryId/branches') + ->desc('List Repository Branches') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.read') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'listRepositoryBranches') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_BRANCH_LIST) + ->param('installationId', '', new Text(256), 'Installation Id') + ->param('providerRepositoryId', '', new Text(256), 'Repository Id') + ->inject('gitHub') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->action(function (string $installationId, string $providerRepositoryId, GitHub $github, Response $response, Document $project, Database $dbForConsole) { + $installation = $dbForConsole->getDocument('installations', $installationId); + + if ($installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + $providerInstallationId = $installation->getAttribute('providerInstallationId'); + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + + $owner = $github->getOwnerName($providerInstallationId) ?? ''; + $repositoryName = $github->getRepositoryName($providerRepositoryId) ?? ''; + + if (empty($repositoryName)) { + throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND); + } + + $branches = $github->listBranches($owner, $repositoryName) ?? []; + + $response->dynamic(new Document([ + 'branches' => \array_map(function ($branch) { + return new Document(['name' => $branch]); + }, $branches), + 'total' => \count($branches), + ]), Response::MODEL_BRANCH_LIST); + }); + +App::post('/v1/vcs/github/events') + ->desc('Create Event') + ->groups(['api', 'vcs']) + ->label('scope', 'public') + ->inject('gitHub') + ->inject('request') + ->inject('response') + ->inject('dbForConsole') + ->inject('getProjectDB') + ->action( + function (GitHub $github, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB) use ($createGitDeployments) { + $signature = $request->getHeader('x-hub-signature-256', ''); + $payload = $request->getRawPayload(); + + $signatureKey = App::getEnv('_APP_VCS_GITHUB_WEBHOOK_SECRET', ''); + + $valid = $github->validateWebhookEvent($payload, $signature, $signatureKey); + if (!$valid) { + throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN, "Invalid webhook signature."); + } + + $event = $request->getHeader('x-github-event', ''); + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); + $parsedPayload = $github->getEvent($event, $payload); + + if ($event == $github::EVENT_PUSH) { + $providerBranchCreated = $parsedPayload["branchCreated"] ?? false; + $providerBranch = $parsedPayload["branch"] ?? ''; + $providerBranchUrl = $parsedPayload["branchUrl"] ?? ''; + $providerRepositoryId = $parsedPayload["repositoryId"] ?? ''; + $providerRepositoryName = $parsedPayload["repositoryName"] ?? ''; + $providerInstallationId = $parsedPayload["installationId"] ?? ''; + $providerRepositoryUrl = $parsedPayload["repositoryUrl"] ?? ''; + $providerCommitHash = $parsedPayload["commitHash"] ?? ''; + $providerRepositoryOwner = $parsedPayload["owner"] ?? ''; + $providerCommitAuthor = $parsedPayload["headCommitAuthor"] ?? ''; + $providerCommitAuthorUrl = $parsedPayload["authorUrl"] ?? ''; + $providerCommitMessage = $parsedPayload["headCommitMessage"] ?? ''; + $providerCommitUrl = $parsedPayload["headCommitUrl"] ?? ''; + + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + + //find functionId from functions table + $repositories = $dbForConsole->find('repositories', [ + Query::equal('providerRepositoryId', [$providerRepositoryId]), + Query::limit(100), + ]); + + // create new deployment only on push and not when branch is created + if (!$providerBranchCreated) { + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForConsole, $getProjectDB, $request); + } + } elseif ($event == $github::EVENT_INSTALLATION) { + if ($parsedPayload["action"] == "deleted") { + // TODO: Use worker for this job instead (update function as well) + $providerInstallationId = $parsedPayload["installationId"]; + + $installations = $dbForConsole->find('installations', [ + Query::equal('providerInstallationId', [$providerInstallationId]), + Query::limit(1000) + ]); + + foreach ($installations as $installation) { + $repositories = $dbForConsole->find('repositories', [ + Query::equal('installationInternalId', [$installation->getInternalId()]), + Query::limit(1000) + ]); + + foreach ($repositories as $repository) { + $dbForConsole->deleteDocument('repositories', $repository->getId()); + } + + $dbForConsole->deleteDocument('installations', $installation->getId()); + } + } + } elseif ($event == $github::EVENT_PULL_REQUEST) { + if ($parsedPayload["action"] == "opened" || $parsedPayload["action"] == "reopened" || $parsedPayload["action"] == "synchronize") { + $providerBranch = $parsedPayload["branch"] ?? ''; + $providerBranchUrl = $parsedPayload["branchUrl"] ?? ''; + $providerRepositoryId = $parsedPayload["repositoryId"] ?? ''; + $providerRepositoryName = $parsedPayload["repositoryName"] ?? ''; + $providerInstallationId = $parsedPayload["installationId"] ?? ''; + $providerRepositoryUrl = $parsedPayload["repositoryUrl"] ?? ''; + $providerPullRequestId = $parsedPayload["pullRequestNumber"] ?? ''; + $providerCommitHash = $parsedPayload["commitHash"] ?? ''; + $providerRepositoryOwner = $parsedPayload["owner"] ?? ''; + $external = $parsedPayload["external"] ?? true; + $providerCommitUrl = $parsedPayload["headCommitUrl"] ?? ''; + $providerCommitAuthorUrl = $parsedPayload["authorUrl"] ?? ''; + + // Ignore sync for non-external. We handle it in push webhook + if (!$external && $parsedPayload["action"] == "synchronize") { + return $response->json($parsedPayload); + } + + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + + $commitDetails = $github->getCommit($providerRepositoryOwner, $providerRepositoryName, $providerCommitHash); + $providerCommitAuthor = $commitDetails["commitAuthor"] ?? ''; + $providerCommitMessage = $commitDetails["commitMessage"] ?? ''; + + $repositories = $dbForConsole->find('repositories', [ + Query::equal('providerRepositoryId', [$providerRepositoryId]), + Query::orderDesc('$createdAt') + ]); + + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForConsole, $getProjectDB, $request); + } elseif ($parsedPayload["action"] == "closed") { + // Allowed external contributions cleanup + + $providerRepositoryId = $parsedPayload["repositoryId"] ?? ''; + $providerPullRequestId = $parsedPayload["pullRequestNumber"] ?? ''; + $external = $parsedPayload["external"] ?? true; + + if ($external) { + $repositories = $dbForConsole->find('repositories', [ + Query::equal('providerRepositoryId', [$providerRepositoryId]), + Query::orderDesc('$createdAt') + ]); + + foreach ($repositories as $repository) { + $providerPullRequestIds = $repository->getAttribute('providerPullRequestIds', []); + + if (\in_array($providerPullRequestId, $providerPullRequestIds)) { + $providerPullRequestIds = \array_diff($providerPullRequestIds, [$providerPullRequestId]); + $repository = $repository->setAttribute('providerPullRequestIds', $providerPullRequestIds); + $repository = Authorization::skip(fn () => $dbForConsole->updateDocument('repositories', $repository->getId(), $repository)); + } + } + } + } + } + + $response->json($parsedPayload); + } + ); + +App::get('/v1/vcs/installations') + ->desc('List installations') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.read') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'listInstallations') + ->label('sdk.description', '/docs/references/vcs/list-installations.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_INSTALLATION_LIST) + ->param('queries', [], new Installations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Installations::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) + ->inject('response') + ->inject('project') + ->inject('dbForProject') + ->inject('dbForConsole') + ->action(function (array $queries, string $search, Response $response, Document $project, Database $dbForProject, Database $dbForConsole) { + $queries = Query::parseQueries($queries); + + $queries[] = Query::equal('projectInternalId', [$project->getInternalId()]); + + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); + if ($cursor) { + /** @var Query $cursor */ + $installationId = $cursor->getValue(); + $cursorDocument = $dbForConsole->getDocument('installations', $installationId); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Installation '{$installationId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + + $filterQueries = Query::groupByType($queries)['filters']; + + $results = $dbForConsole->find('installations', $queries); + $total = $dbForConsole->count('installations', $filterQueries, APP_LIMIT_COUNT); + + $response->dynamic(new Document([ + 'installations' => $results, + 'total' => $total, + ]), Response::MODEL_INSTALLATION_LIST); + }); + +App::get('/v1/vcs/installations/:installationId') + ->desc('Get installation') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.read') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'getInstallation') + ->label('sdk.description', '/docs/references/vcs/get-installation.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_INSTALLATION) + ->param('installationId', '', new Text(256), 'Installation Id') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->action(function (string $installationId, Response $response, Document $project, Database $dbForConsole) { + $installation = $dbForConsole->getDocument('installations', $installationId); + + if ($installation === false || $installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + if ($installation->getAttribute('projectInternalId') !== $project->getInternalId()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + $response->dynamic($installation, Response::MODEL_INSTALLATION); + }); + +App::delete('/v1/vcs/installations/:installationId') + ->desc('Delete Installation') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.write') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'deleteInstallation') + ->label('sdk.description', '/docs/references/vcs/delete-installation.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('installationId', '', new Text(256), 'Installation Id') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->inject('deletes') + ->action(function (string $installationId, Response $response, Document $project, Database $dbForConsole, Delete $deletes) { + $installation = $dbForConsole->getDocument('installations', $installationId); + + if ($installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + if (!$dbForConsole->deleteDocument('installations', $installation->getId())) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove installation from DB'); + } + + $deletes + ->setType(DELETE_TYPE_DOCUMENT) + ->setDocument($installation); + + $response->noContent(); + }); + +App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositoryId') + ->desc('Authorize external deployment') + ->groups(['api', 'vcs']) + ->label('scope', 'vcs.write') + ->label('sdk.namespace', 'vcs') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.method', 'updateExternalDeployments') + ->label('sdk.description', '') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('installationId', '', new Text(256), 'Installation Id') + ->param('repositoryId', '', new Text(256), 'VCS Repository Id') + ->param('providerPullRequestId', '', new Text(256), 'GitHub Pull Request Id') + ->inject('gitHub') + ->inject('request') + ->inject('response') + ->inject('project') + ->inject('dbForConsole') + ->inject('getProjectDB') + ->action(function (string $installationId, string $repositoryId, string $providerPullRequestId, GitHub $github, Request $request, Response $response, Document $project, Database $dbForConsole, callable $getProjectDB) use ($createGitDeployments) { + $installation = $dbForConsole->getDocument('installations', $installationId); + + if ($installation->isEmpty()) { + throw new Exception(Exception::INSTALLATION_NOT_FOUND); + } + + $repository = $dbForConsole->getDocument('repositories', $repositoryId, [ + Query::equal('projectInternalId', [$project->getInternalId()]) + ]); + + if ($repository->isEmpty()) { + throw new Exception(Exception::REPOSITORY_NOT_FOUND); + } + + if (\in_array($providerPullRequestId, $repository->getAttribute('providerPullRequestIds', []))) { + throw new Exception(Exception::PROVIDER_CONTRIBUTION_CONFLICT); + } + + $providerPullRequestIds = \array_unique(\array_merge($repository->getAttribute('providerPullRequestIds', []), [$providerPullRequestId])); + $repository = $repository->setAttribute('providerPullRequestIds', $providerPullRequestIds); + + // TODO: Delete from array when PR is closed + + $repository = $dbForConsole->updateDocument('repositories', $repository->getId(), $repository); + + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); + $providerInstallationId = $installation->getAttribute('providerInstallationId'); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + + $repositories = [$repository]; + $providerRepositoryId = $repository->getAttribute('providerRepositoryId'); + + $owner = $github->getOwnerName($providerInstallationId); + $repositoryName = $github->getRepositoryName($providerRepositoryId); + $pullRequestResponse = $github->getPullRequest($owner, $repositoryName, $providerPullRequestId); + + $providerBranch = \explode(':', $pullRequestResponse['head']['label'])[1] ?? ''; + $providerCommitHash = $pullRequestResponse['head']['sha'] ?? ''; + + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerCommitHash, $providerPullRequestId, true, $dbForConsole, $getProjectDB, $request); + + $response->noContent(); + }); diff --git a/app/controllers/general.php b/app/controllers/general.php index e8d6bb225a..e3b47098b2 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -8,6 +8,9 @@ use Utopia\Locale\Locale; use Utopia\Logger\Logger; use Utopia\Logger\Log; use Utopia\Logger\Log\User; +use Swoole\Http\Request as SwooleRequest; +use Utopia\Cache\Cache; +use Utopia\Pools\Group; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\View; @@ -22,6 +25,7 @@ use Appwrite\Utopia\Response\Filters\V12 as ResponseV12; use Appwrite\Utopia\Response\Filters\V13 as ResponseV13; use Appwrite\Utopia\Response\Filters\V14 as ResponseV14; use Appwrite\Utopia\Response\Filters\V15 as ResponseV15; +use Appwrite\Utopia\Response\Filters\V16 as ResponseV16; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\DateTime; @@ -33,6 +37,7 @@ use Appwrite\Utopia\Request\Filters\V12 as RequestV12; use Appwrite\Utopia\Request\Filters\V13 as RequestV13; use Appwrite\Utopia\Request\Filters\V14 as RequestV14; use Appwrite\Utopia\Request\Filters\V15 as RequestV15; +use Appwrite\Utopia\Request\Filters\V16 as RequestV16; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -40,9 +45,136 @@ Config::setParam('domainVerification', false); Config::setParam('cookieDomain', 'localhost'); Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE); +function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleRequest, Request $request, Response $response) +{ + $utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml'); + + $host = $request->getHostname() ?? ''; + + $route = Authorization::skip( + fn () => $dbForConsole->find('rules', [ + Query::equal('domain', [$host]), + Query::limit(1) + ]) + )[0] ?? null; + + if ($route === null) { + $mainDomain = App::getEnv('_APP_DOMAIN', ''); + + if ($mainDomain === 'localhost') { + throw new AppwriteException(AppwriteException::ROUTER_DOMAIN_NOT_CONFIGURED); + } else { + throw new AppwriteException(AppwriteException::ROUTER_HOST_NOT_FOUND); + } + } + + $projectId = $route->getAttribute('projectId'); + $project = Authorization::skip( + fn () => $dbForConsole->getDocument('projects', $projectId) + ); + if (array_key_exists('proxy', $project->getAttribute('services', []))) { + $status = $project->getAttribute('services', [])['proxy']; + if (!$status) { + throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED); + } + } + + // Skip Appwrite Router for ACME challenge. Nessessary for certificate generation + $path = ($swooleRequest->server['request_uri'] ?? '/'); + if (\str_starts_with($path, '/.well-known/acme-challenge')) { + return false; + } + + $type = $route->getAttribute('resourceType'); + + if ($type === 'function') { + $functionId = $route->getAttribute('resourceId'); + $projectId = $route->getAttribute('projectId'); + + $path = ($swooleRequest->server['request_uri'] ?? '/'); + $query = ($swooleRequest->server['query_string'] ?? ''); + if (!empty($query)) { + $path .= '?' . $query; + } + + $body = \json_encode([ + 'async' => false, + 'body' => $swooleRequest->getContent() ?? '', + 'method' => $swooleRequest->server['request_method'], + 'path' => $path, + 'headers' => $swooleRequest->header + ]); + + $headers = [ + 'Content-Type: application/json', + 'Content-Length: ' . \strlen($body), + 'X-Appwrite-Project: ' . $projectId + ]; + + $ch = \curl_init(); + \curl_setopt($ch, CURLOPT_URL, "http://localhost/v1/functions/{$functionId}/executions"); + \curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); + \curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + \curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + \curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + // \curl_setopt($ch, CURLOPT_HEADER, true); + \curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); + + $executionResponse = \curl_exec($ch); + $statusCode = \curl_getinfo($ch, CURLINFO_HTTP_CODE); + $error = \curl_error($ch); + $errNo = \curl_errno($ch); + + \curl_close($ch); + + if ($errNo !== 0) { + throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, "Internal error: " . $error); + } + + if ($statusCode >= 400) { + $error = \json_decode($executionResponse, true)['message']; + throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, "Execution error: " . $error); + } + + $execution = \json_decode($executionResponse, true); + + $contentType = 'text/plain'; + foreach ($execution['responseHeaders'] as $header) { + if (\strtolower($header['name']) === 'content-type') { + $contentType = $header['value']; + } + + $response->setHeader($header['name'], $header['value']); + } + + $body = $execution['responseBody'] ?? ''; + + $encodingKey = \array_search('x-open-runtimes-encoding', \array_column($execution['responseHeaders'], 'name')); + if ($encodingKey !== false) { + if (($execution['responseHeaders'][$encodingKey]['value'] ?? '') === 'base64') { + $body = \base64_decode($body); + } + } + + $response + ->setContentType($contentType) + ->setStatusCode($execution['responseStatusCode'] ?? 200) + ->send($body); + + return true; + } elseif ($type === 'api') { + return false; + } else { + throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Unknown resource type ' . $type); + } + + return false; +} + App::init() - ->groups(['api']) + ->groups(['api', 'web']) ->inject('utopia') + ->inject('swooleRequest') ->inject('request') ->inject('response') ->inject('console') @@ -53,13 +185,30 @@ App::init() ->inject('localeCodes') ->inject('clients') ->inject('servers') - ->action(function (App $utopia, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, Document $user, Locale $locale, array $localeCodes, array $clients, array $servers) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, Document $user, Locale $locale, array $localeCodes, array $clients, array $servers) { + /* + * Appwrite Router + */ + + $host = $request->getHostname() ?? ''; + $mainDomain = App::getEnv('_APP_DOMAIN', ''); + // Only run Router when external domain + if ($host !== $mainDomain && $host !== 'localhost' && $host !== APP_HOSTNAME_INTERNAL) { + if (router($utopia, $dbForConsole, $swooleRequest, $request, $response)) { + return; + } + } + /* * Request format */ - $route = $utopia->match($request); + $route = $utopia->getRoute(); Request::setRoute($route); + if ($route === null) { + return $response->setStatusCode(404)->send('Not Found'); + } + $requestFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', '')); if ($requestFormat) { switch ($requestFormat) { @@ -75,6 +224,9 @@ App::init() case version_compare($requestFormat, '0.15.3', '<'): Request::setFilter(new RequestV15()); break; + case version_compare($requestFormat, '1.4.0', '<'): + Request::setFilter(new RequestV16()); + break; default: Request::setFilter(null); } @@ -82,60 +234,6 @@ App::init() Request::setFilter(null); } - $domain = $request->getHostname(); - $domains = Config::getParam('domains', []); - if (!array_key_exists($domain, $domains)) { - $domain = new Domain(!empty($domain) ? $domain : ''); - - if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) { - $domains[$domain->get()] = false; - Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.'); - } elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) { - Console::warning('Skipping SSL certificates generation on ACME challenge.'); - } else { - Authorization::disable(); - - $envDomain = App::getEnv('_APP_DOMAIN', ''); - $mainDomain = null; - if (!empty($envDomain) && $envDomain !== 'localhost') { - $mainDomain = $envDomain; - } else { - $domainDocument = $dbForConsole->findOne('domains', [Query::orderAsc('_id')]); - $mainDomain = $domainDocument ? $domainDocument->getAttribute('domain') : $domain->get(); - } - - if ($mainDomain !== $domain->get()) { - Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.'); - } else { - $domainDocument = $dbForConsole->findOne('domains', [ - Query::equal('domain', [$domain->get()]) - ]); - - if (!$domainDocument) { - $domainDocument = new Document([ - 'domain' => $domain->get(), - 'tld' => $domain->getSuffix(), - 'registerable' => $domain->getRegisterable(), - 'verification' => false, - 'certificateId' => null, - ]); - - $domainDocument = $dbForConsole->createDocument('domains', $domainDocument); - - Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...'); - - (new Certificate()) - ->setDomain($domainDocument) - ->trigger(); - } - } - $domains[$domain->get()] = true; - - Authorization::reset(); // ensure authorization is re-enabled - } - Config::setParam('domains', $domains); - } - $localeParam = (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', '')); if (\in_array($localeParam, $localeCodes)) { $locale->setDefault($localeParam); @@ -172,7 +270,7 @@ App::init() Config::setParam( 'domainVerification', ($selfDomain->getRegisterable() === $endDomain->getRegisterable()) && - $endDomain->getRegisterable() !== '' + $endDomain->getRegisterable() !== '' ); $isLocalHost = $request->getHostname() === 'localhost' || $request->getHostname() === 'localhost:' . $request->getPort(); @@ -212,6 +310,9 @@ App::init() case version_compare($responseFormat, '0.15.3', '<='): Response::setFilter(new ResponseV15()); break; + case version_compare($responseFormat, '1.4.0', '<'): + Response::setFilter(new ResponseV16()); + break; default: Response::setFilter(null); } @@ -226,7 +327,7 @@ App::init() * @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers */ if (App::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS - if ($request->getProtocol() !== 'https') { + if ($request->getProtocol() !== 'https' && ($swooleRequest->header['host'] ?? '') !== 'localhost' && ($swooleRequest->header['host'] ?? '') !== APP_HOSTNAME_INTERNAL) { // Localhost allowed for proxy, APP_HOSTNAME_INTERNAL allowed for migrations if ($request->getMethod() !== Request::METHOD_GET) { throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP.'); } @@ -246,8 +347,7 @@ App::init() ->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma') ->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies') ->addHeader('Access-Control-Allow-Origin', $refDomain) - ->addHeader('Access-Control-Allow-Credentials', 'true') - ; + ->addHeader('Access-Control-Allow-Credentials', 'true'); /* * Validate Client Domain - Check to avoid CSRF attack @@ -274,7 +374,7 @@ App::init() : Role::users()->toString(); // Add user roles - $memberships = $user->find('teamId', $project->getAttribute('teamId', null), 'memberships'); + $memberships = $user->find('teamId', $project->getAttribute('teamId'), 'memberships'); if ($memberships) { foreach ($memberships->getAttribute('roles', []) as $memberRole) { @@ -320,7 +420,7 @@ App::init() $expire = $key->getAttribute('expire'); if (!empty($expire) && $expire < DateTime::formatTz(DateTime::now())) { - throw new AppwriteException(AppwriteException:: PROJECT_KEY_EXPIRED); + throw new AppwriteException(AppwriteException::PROJECT_KEY_EXPIRED); } Authorization::setRole(Auth::USER_ROLE_APPS); @@ -385,9 +485,23 @@ App::init() }); App::options() + ->inject('utopia') + ->inject('swooleRequest') ->inject('request') ->inject('response') - ->action(function (Request $request, Response $response) { + ->inject('dbForConsole') + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole) { + /* + * Appwrite Router + */ + $host = $request->getHostname() ?? ''; + $mainDomain = App::getEnv('_APP_DOMAIN', ''); + // Only run Router when external domain + if ($host !== $mainDomain && $host !== 'localhost' && $host !== APP_HOSTNAME_INTERNAL) { + if (router($utopia, $dbForConsole, $swooleRequest, $request, $response)) { + return; + } + } $origin = $request->getOrigin(); @@ -412,7 +526,7 @@ App::error() ->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, array $loggerBreadcrumbs) { $version = App::getEnv('_APP_VERSION', 'UNKNOWN'); - $route = $utopia->match($request); + $route = $utopia->getRoute(); if ($logger) { if ($error->getCode() >= 500 || $error->getCode() === 0) { @@ -548,8 +662,7 @@ App::error() ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate') ->addHeader('Expires', '0') ->addHeader('Pragma', 'no-cache') - ->setStatusCode($code) - ; + ->setStatusCode($code); $template = ($route) ? $route->getLabel('error', null) : null; @@ -564,8 +677,7 @@ App::error() ->setParam('message', $error->getMessage()) ->setParam('type', $type) ->setParam('code', $code) - ->setParam('trace', $trace) - ; + ->setParam('trace', $trace); $response->html($layout->render()); } @@ -649,6 +761,13 @@ App::get('/.well-known/acme-challenge/*') include_once __DIR__ . '/shared/api.php'; include_once __DIR__ . '/shared/api/auth.php'; +App::wildcard() + ->groups(['api']) + ->label('scope', 'global') + ->action(function () { + throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND); + }); + foreach (Config::getParam('services', []) as $service) { include_once $service['controller']; } diff --git a/app/controllers/mock.php b/app/controllers/mock.php index 892c41d872..a763df82c0 100644 --- a/app/controllers/mock.php +++ b/app/controllers/mock.php @@ -198,7 +198,6 @@ App::delete('/v1/mock/tests/bar') ->action(function ($required, $default, $z) { }); -/** Endpoint to test if required headers are sent from the SDK */ App::get('/v1/mock/tests/general/headers') ->desc('Get headers') ->groups(['mock']) @@ -443,35 +442,6 @@ App::post('/v1/mock/tests/general/nullable') ->action(function (string $required, string $nullable, ?string $optional) { }); -/** Endpoint to test if required headers are sent from the SDK */ -App::get('/v1/mock/tests/general/headers') - ->desc('Get headers') - ->groups(['mock']) - ->label('scope', 'public') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) - ->label('sdk.namespace', 'general') - ->label('sdk.method', 'headers') - ->label('sdk.description', 'Return headers from the request') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.model', Response::MODEL_MOCK) - ->label('sdk.mock', true) - ->inject('request') - ->inject('response') - ->action(function (Request $request, Response $response) { - $res = [ - 'x-sdk-name' => $request->getHeader('x-sdk-name'), - 'x-sdk-platform' => $request->getHeader('x-sdk-platform'), - 'x-sdk-language' => $request->getHeader('x-sdk-language'), - 'x-sdk-version' => $request->getHeader('x-sdk-version'), - ]; - $res = array_map(function ($key, $value) { - return $key . ': ' . $value; - }, array_keys($res), $res); - $res = implode("; ", $res); - - $response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK); - }); - App::get('/v1/mock/tests/general/400-error') ->desc('400 Error') ->groups(['mock']) @@ -643,7 +613,7 @@ App::shutdown() ->action(function (App $utopia, Response $response, Request $request) { $result = []; - $route = $utopia->match($request); + $route = $utopia->getRoute(); $path = APP_STORAGE_CACHE . '/tests.json'; $tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : []; diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 2bbac41811..9dd800b69b 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -8,8 +8,8 @@ use Appwrite\Event\Event; use Appwrite\Event\Func; use Appwrite\Event\Mail; use Appwrite\Extend\Exception; -use Appwrite\Event\Usage; use Appwrite\Messaging\Adapter\Realtime; +use Appwrite\Usage\Stats; use Appwrite\Utopia\Response; use Appwrite\Utopia\Request; use Utopia\App; @@ -48,99 +48,43 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar return $label; }; -$databaseListener = function (string $event, Document $document, Document $project, Usage $queueForUsage, Database $dbForProject) { - - $value = 1; +$databaseListener = function (string $event, Document $document, Stats $usage) { + $multiplier = 1; if ($event === Database::EVENT_DOCUMENT_DELETE) { - $value = -1; + $multiplier = -1; } - switch (true) { - case $document->getCollection() === 'teams': - $queueForUsage - ->addMetric(METRIC_TEAMS, $value); // per project + $collection = $document->getCollection(); + switch ($collection) { + case 'users': + $usage->setParam('users.{scope}.count.total', 1 * $multiplier); break; - case $document->getCollection() === 'users': - $queueForUsage - ->addMetric(METRIC_USERS, $value); // per project - if ($event === Database::EVENT_DOCUMENT_DELETE) { - $queueForUsage - ->addReduce($document); - } + case 'databases': + $usage->setParam('databases.{scope}.count.total', 1 * $multiplier); break; - case $document->getCollection() === 'sessions': // sessions - $queueForUsage - ->addMetric(METRIC_SESSIONS, $value); //per project + case 'buckets': + $usage->setParam('buckets.{scope}.count.total', 1 * $multiplier); break; - case $document->getCollection() === 'databases': // databases - $queueForUsage - ->addMetric(METRIC_DATABASES, $value); // per project - - if ($event === Database::EVENT_DOCUMENT_DELETE) { - $queueForUsage - ->addReduce($document); - } - break; - case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections - $parts = explode('_', $document->getCollection()); - $databaseInternalId = $parts[1] ?? 0; - $queueForUsage - ->addMetric(METRIC_COLLECTIONS, $value) // per project - ->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value) // per database - ; - - if ($event === Database::EVENT_DOCUMENT_DELETE) { - $queueForUsage - ->addReduce($document); - } - break; - case str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_'): //documents - $parts = explode('_', $document->getCollection()); - $databaseInternalId = $parts[1] ?? 0; - $collectionInternalId = $parts[3] ?? 0; - $queueForUsage - ->addMetric(METRIC_DOCUMENTS, $value) // per project - ->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_DOCUMENTS), $value) // per database - ->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS), $value); // per collection - break; - case $document->getCollection() === 'buckets': //buckets - $queueForUsage - ->addMetric(METRIC_BUCKETS, $value); // per project - if ($event === Database::EVENT_DOCUMENT_DELETE) { - $queueForUsage - ->addReduce($document); - } - break; - case str_starts_with($document->getCollection(), 'bucket_'): // files - $queueForUsage - ->addMetric(METRIC_FILES, $value) // per project - ->addMetric(METRIC_FILES_STORAGE, $document->getAttribute('sizeOriginal') * $value) // per project - ->addMetric(str_replace('{bucketInternalId}', $document->getAttribute('bucketInternalId'), METRIC_BUCKET_ID_FILES), $value) // per bucket - ->addMetric(str_replace('{bucketInternalId}', $document->getAttribute('bucketInternalId'), METRIC_BUCKET_ID_FILES_STORAGE), $document->getAttribute('sizeOriginal') * $value); // per bucket - break; - case $document->getCollection() === 'functions': - $queueForUsage - ->addMetric(METRIC_FUNCTIONS, $value); // per project - - if ($event === Database::EVENT_DOCUMENT_DELETE) { - $queueForUsage - ->addReduce($document); - } - break; - case $document->getCollection() === 'deployments': - $queueForUsage - ->addMetric(METRIC_DEPLOYMENTS, $value) // per project - ->addMetric(METRIC_DEPLOYMENTS_STORAGE, $document->getAttribute('size') * $value) // per project - ->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS), $value)// per function - ->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value);// per function - - break; - case $document->getCollection() === 'executions': - $queueForUsage - ->addMetric(METRIC_EXECUTIONS, $value) // per project - ->addMetric(str_replace('{functionInternalId}', $document->getAttribute('functionInternalId'), METRIC_FUNCTION_ID_EXECUTIONS), $value);// per function + case 'deployments': + $usage->setParam('deployments.{scope}.storage.size', $document->getAttribute('size') * $multiplier); break; default: + if (strpos($collection, 'bucket_') === 0) { + $usage + ->setParam('bucketId', $document->getAttribute('bucketId')) + ->setParam('files.{scope}.storage.size', $document->getAttribute('sizeOriginal') * $multiplier) + ->setParam('files.{scope}.count.total', 1 * $multiplier); + } elseif (strpos($collection, 'database_') === 0) { + $usage + ->setParam('databaseId', $document->getAttribute('databaseId')); + if (strpos($collection, '_collection_') !== false) { + $usage + ->setParam('collectionId', $document->getAttribute('$collectionId')) + ->setParam('documents.{scope}.count.total', 1 * $multiplier); + } else { + $usage->setParam('collections.{scope}.count.total', 1 * $multiplier); + } + } break; } }; @@ -157,12 +101,12 @@ App::init() ->inject('deletes') ->inject('database') ->inject('dbForProject') - ->inject('queueForUsage') ->inject('mode') ->inject('mails') - ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, Usage $queueForUsage, string $mode, Mail $mails) use ($databaseListener) { + ->inject('usage') + ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, string $mode, Mail $mails, Stats $usage) use ($databaseListener) { - $route = $utopia->match($request); + $route = $utopia->getRoute(); if ($project->isEmpty() && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope throw new Exception(Exception::PROJECT_UNKNOWN); @@ -242,25 +186,19 @@ App::init() ->setProject($project) ->setUser($user); - $smtp = $project->getAttribute('smtp', []); - if (!empty($smtp) && ($smtp['enabled'] ?? false)) { - $mails - ->setSmtpHost($smtp['host'] ?? '') - ->setSmtpPort($smtp['port'] ?? 25) - ->setSmtpUsername($smtp['username'] ?? '') - ->setSmtpPassword($smtp['password'] ?? '') - ->setSmtpSenderEmail($smtp['sender'] ?? '') - ->setSmtpReplyTo($smtp['replyTo'] ?? ''); - } + $usage + ->setParam('projectInternalId', $project->getInternalId()) + ->setParam('projectId', $project->getId()) + ->setParam('project.{scope}.network.requests', 1) + ->setParam('httpMethod', $request->getMethod()) + ->setParam('project.{scope}.network.inbound', 0) + ->setParam('project.{scope}.network.outbound', 0); $deletes->setProject($project); $database->setProject($project); - $calculateUsage = fn ($event, Document $document) => $databaseListener($event, $document, $project, $queueForUsage, $dbForProject); - - $dbForProject - ->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', $calculateUsage) - ->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', $calculateUsage); + $dbForProject->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, Document $document) => $databaseListener($event, $document, $usage)); + $dbForProject->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, Document $document) => $databaseListener($event, $document, $usage)); $useCache = $route->getLabel('cache', false); @@ -282,7 +220,10 @@ App::init() $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); - if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { + $isAPIKey = Auth::isAppUser(Authorization::getRoles()); + $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); + + if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); } @@ -328,7 +269,7 @@ App::init() ->inject('project') ->action(function (App $utopia, Request $request, Document $project) { - $route = $utopia->match($request); + $route = $utopia->getRoute(); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); @@ -423,14 +364,14 @@ App::shutdown() ->inject('user') ->inject('events') ->inject('audits') + ->inject('usage') ->inject('deletes') ->inject('database') ->inject('dbForProject') ->inject('queueForFunctions') - ->inject('queueForUsage') ->inject('mode') ->inject('dbForConsole') - ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, Func $queueForFunctions, Usage $queueForUsage, string $mode, Database $dbForConsole) use ($parseLabel) { + ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Stats $usage, Delete $deletes, EventDatabase $database, Database $dbForProject, Func $queueForFunctions, string $mode, Database $dbForConsole) use ($parseLabel) { $responsePayload = $response->getPayload(); @@ -489,7 +430,7 @@ App::shutdown() } } - $route = $utopia->match($request); + $route = $utopia->getRoute(); $requestParams = $route->getParamsValues(); /** @@ -583,48 +524,35 @@ App::shutdown() } } + if ( + App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled' + && $project->getId() + && !empty($route->getLabel('sdk.namespace', null)) + ) { // Don't calculate console usage on admin mode + $metric = $route->getLabel('usage.metric', ''); + $usageParams = $route->getLabel('usage.params', []); - - if ($project->getId() !== 'console') { - if ($mode !== APP_MODE_ADMIN) { - $fileSize = 0; - $file = $request->getFiles('file'); - if (!empty($file)) { - $fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size']; - } - - $queueForUsage - ->addMetric(METRIC_NETWORK_REQUESTS, 1) - ->addMetric(METRIC_NETWORK_INBOUND, $request->getSize() + $fileSize) - ->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize()); - } - - $queueForUsage - ->setProject($project) - ->trigger(); - } - - /** - * Update user last activity - */ - if (!$user->isEmpty()) { - $accessedAt = $user->getAttribute('accessedAt', ''); - if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_USER_ACCCESS)) > $accessedAt) { - $user->setAttribute('accessedAt', DateTime::now()); - - if (APP_MODE_ADMIN !== $mode) { - $dbForProject->updateDocument('users', $user->getId(), $user); - } else { - $dbForConsole->updateDocument('users', $user->getId(), $user); + if (!empty($metric)) { + $usage->setParam($metric, 1); + foreach ($usageParams as $param) { + $param = $parseLabel($param, $responsePayload, $requestParams, $user); + $parts = explode(':', $param); + if (count($parts) != 2) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Usage params not properly set'); + } + $usage->setParam($parts[0], $parts[1]); } } - } - }); -App::init() - ->groups(['usage']) - ->action(function () { - if (App::getEnv('_APP_USAGE_STATS', 'enabled') !== 'enabled') { - throw new Exception(Exception::GENERAL_USAGE_DISABLED); + $fileSize = 0; + $file = $request->getFiles('file'); + if (!empty($file)) { + $fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size']; + } + + $usage + ->setParam('project.{scope}.network.inbound', $request->getSize() + $fileSize) + ->setParam('project.{scope}.network.outbound', $response->getSize()) + ->submit(); } }); diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index dcf9c80a51..d7496b03bd 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -1,5 +1,6 @@ inject('request') ->inject('response') ->action(function (Request $request, Response $response) { + // Serve static files (console) only for main domain + $host = $request->getHostname() ?? ''; + $mainDomain = App::getEnv('_APP_DOMAIN', ''); + if ($host !== $mainDomain && $host !== 'localhost' && $host !== APP_HOSTNAME_INTERNAL) { + throw new Exception(Exception::GENERAL_ROUTE_NOT_FOUND); + } + $fallback = file_get_contents(__DIR__ . '/../../../console/index.html'); // Card SSR diff --git a/app/controllers/web/home.php b/app/controllers/web/home.php index e90f3ec25b..27b2614c37 100644 --- a/app/controllers/web/home.php +++ b/app/controllers/web/home.php @@ -6,7 +6,7 @@ use Utopia\Config\Config; App::get('/versions') ->desc('Get Version') - ->groups(['home']) + ->groups(['home', 'web']) ->label('scope', 'public') ->inject('response') ->action(function (Response $response) { diff --git a/app/http.php b/app/http.php index 8ce7b6f017..053db20ffc 100644 --- a/app/http.php +++ b/app/http.php @@ -61,8 +61,9 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { $app = new App('UTC'); go(function () use ($register, $app) { - $pools = $register->get('pools'); /** @var Group $pools */ - App::setResource('pools', fn() => $pools); + $pools = $register->get('pools'); + /** @var Group $pools */ + App::setResource('pools', fn () => $pools); // wait for database to be ready $attempts = 0; @@ -72,7 +73,8 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { do { try { $attempts++; - $dbForConsole = $app->getResource('dbForConsole'); /** @var Utopia\Database\Database $dbForConsole */ + $dbForConsole = $app->getResource('dbForConsole'); + /** @var Utopia\Database\Database $dbForConsole */ break; // leave the do-while if successful } catch (\Exception $e) { Console::warning("Database not ready. Retrying connection ({$attempts})..."); @@ -221,25 +223,33 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { }); $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) use ($register) { + App::setResource('swooleRequest', fn () => $swooleRequest); + App::setResource('swooleResponse', fn () => $swooleResponse); + $request = new Request($swooleRequest); $response = new Response($swooleResponse); - if (Files::isFileLoaded($request->getURI())) { - $time = (60 * 60 * 24 * 365 * 2); // 45 days cache + // Serve static files (console) only for main domain + $host = $request->getHostname() ?? ''; + $mainDomain = App::getEnv('_APP_DOMAIN', ''); + if ($host === $mainDomain || $host === 'localhost') { + if (Files::isFileLoaded($request->getURI())) { + $time = (60 * 60 * 24 * 365 * 2); // 45 days cache - $response - ->setContentType(Files::getFileMimeType($request->getURI())) - ->addHeader('Cache-Control', 'public, max-age=' . $time) - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache - ->send(Files::getFileContents($request->getURI())); + $response + ->setContentType(Files::getFileMimeType($request->getURI())) + ->addHeader('Cache-Control', 'public, max-age=' . $time) + ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache + ->send(Files::getFileContents($request->getURI())); - return; + return; + } } $app = new App('UTC'); $pools = $register->get('pools'); - App::setResource('pools', fn() => $pools); + App::setResource('pools', fn () => $pools); try { Authorization::cleanRoles(); @@ -259,7 +269,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo } $loggerBreadcrumbs = $app->getResource("loggerBreadcrumbs"); - $route = $app->match($request); + $route = $app->getRoute(); $log = new Utopia\Logger\Log(); diff --git a/app/init.php b/app/init.php index 9f3d41ba0a..f2d7bc7db4 100644 --- a/app/init.php +++ b/app/init.php @@ -32,6 +32,7 @@ use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\Origin; use Appwrite\OpenSSL\OpenSSL; use Appwrite\URL\URL as AppwriteURL; +use Appwrite\Usage\Stats; use Utopia\App; use Utopia\Logger\Logger; use Utopia\Cache\Adapter\Redis as RedisCache; @@ -68,6 +69,7 @@ use Utopia\Pools\Group; use Utopia\Pools\Pool; use Ahc\Jwt\JWT; use Ahc\Jwt\JWTException; +use Appwrite\Auth\OAuth2\Github; use Appwrite\Event\Func; use MaxMind\Db\Reader; use PHPMailer\PHPMailer\PHPMailer; @@ -75,6 +77,7 @@ use Swoole\Database\PDOProxy; use Utopia\Queue; use Utopia\Queue\Connection; use Utopia\Storage\Storage; +use Utopia\VCS\Adapter\Git\GitHub as VcsGitHub; use Utopia\Validator\Range; use Utopia\Validator\IP; use Utopia\Validator\URL; @@ -105,8 +108,8 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours const APP_USER_ACCCESS = 24 * 60 * 60; // 24 hours const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours -const APP_CACHE_BUSTER = 506; -const APP_VERSION_STABLE = '1.3.8'; +const APP_CACHE_BUSTER = 508; +const APP_VERSION_STABLE = '1.4.1'; const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; const APP_DATABASE_ATTRIBUTE_ENUM = 'enum'; const APP_DATABASE_ATTRIBUTE_IP = 'ip'; @@ -133,6 +136,7 @@ const APP_SOCIAL_DISCORD_CHANNEL = '564160730845151244'; 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'; // Database Reconnect const DATABASE_RECONNECT_SLEEP = 2; const DATABASE_RECONNECT_MAX_ATTEMPTS = 10; @@ -156,10 +160,11 @@ const DELETE_TYPE_TEAMS = 'teams'; const DELETE_TYPE_EXECUTIONS = 'executions'; const DELETE_TYPE_AUDIT = 'audit'; const DELETE_TYPE_ABUSE = 'abuse'; -const DELETE_TYPE_CERTIFICATES = 'certificates'; const DELETE_TYPE_USAGE = 'usage'; const DELETE_TYPE_REALTIME = 'realtime'; const DELETE_TYPE_BUCKETS = 'buckets'; +const DELETE_TYPE_INSTALLATIONS = 'installations'; +const DELETE_TYPE_RULES = 'rules'; const DELETE_TYPE_SESSIONS = 'sessions'; const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp'; const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; @@ -181,6 +186,9 @@ const APP_AUTH_TYPE_KEY = 'Key'; const APP_AUTH_TYPE_ADMIN = 'Admin'; // Response related const MAX_OUTPUT_CHUNK_SIZE = 2 * 1024 * 1024; // 2MB +// Function headers +const FUNCTION_ALLOWLIST_HEADERS_REQUEST = ['content-type', 'agent', 'content-length', 'host']; +const FUNCTION_ALLOWLIST_HEADERS_RESPONSE = ['content-type', 'content-length']; // Usage metrics const METRIC_TEAMS = 'teams'; const METRIC_USERS = 'users'; @@ -229,7 +237,6 @@ Config::load('providers', __DIR__ . '/config/providers.php'); Config::load('platforms', __DIR__ . '/config/platforms.php'); Config::load('collections', __DIR__ . '/config/collections.php'); Config::load('runtimes', __DIR__ . '/config/runtimes.php'); -Config::load('usage', __DIR__ . '/config/usage.php'); Config::load('roles', __DIR__ . '/config/roles.php'); // User roles and scopes Config::load('scopes', __DIR__ . '/config/scopes.php'); // User roles and scopes Config::load('services', __DIR__ . '/config/services.php'); // List of services @@ -286,7 +293,7 @@ Database::addFilter( return $value; }, function (mixed $value, Document $attribute) { - $formatOptions = json_decode($attribute->getAttribute('formatOptions', '[]'), true); + $formatOptions = \json_decode($attribute->getAttribute('formatOptions', '[]'), true); if (isset($formatOptions['elements'])) { $attribute->setAttribute('elements', $formatOptions['elements']); } @@ -356,7 +363,7 @@ Database::addFilter( ->find('indexes', [ Query::equal('collectionInternalId', [$document->getInternalId()]), Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]), - Query::limit(64), + Query::limit($database->getLimitForIndexes()), ]); } ); @@ -375,20 +382,6 @@ Database::addFilter( } ); -Database::addFilter( - 'subQueryDomains', - function (mixed $value) { - return null; - }, - function (mixed $value, Document $document, Database $database) { - return $database - ->find('domains', [ - Query::equal('projectInternalId', [$document->getInternalId()]), - Query::limit(APP_LIMIT_SUBQUERY), - ]); - } -); - Database::addFilter( 'subQueryKeys', function (mixed $value) { @@ -466,7 +459,8 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { return $database ->find('variables', [ - Query::equal('functionInternalId', [$document->getInternalId()]), + Query::equal('resourceInternalId', [$document->getInternalId()]), + Query::equal('resourceType', ['function']), Query::limit(APP_LIMIT_SUBQUERY), ]); } @@ -498,6 +492,21 @@ Database::addFilter( } ); +// READ-ONLY! TO update, write directly to 'variables' collection. After update to vars, make sure to deleteCachedDocument() +Database::addFilter( + 'subQueryProjectVariables', + function (mixed $value) { + return null; + }, + function (mixed $value, Document $document, Database $database) { + return $database + ->find('variables', [ + Query::equal('resourceType', ['project']), + Query::limit(APP_LIMIT_SUBQUERY) + ]); + } +); + Database::addFilter( 'userSearch', function (mixed $value, Document $user) { @@ -593,14 +602,15 @@ $register->set('logger', function () { $register->set('pools', function () { $group = new Group(); - $fallbackForDB = AppwriteURL::unparse([ + $fallbackForDB = 'db_main=' . AppwriteURL::unparse([ 'scheme' => 'mariadb', 'host' => App::getEnv('_APP_DB_HOST', 'mariadb'), 'port' => App::getEnv('_APP_DB_PORT', '3306'), 'user' => App::getEnv('_APP_DB_USER', ''), 'pass' => App::getEnv('_APP_DB_PASS', ''), + 'path' => App::getEnv('_APP_DB_SCHEMA', ''), ]); - $fallbackForRedis = AppwriteURL::unparse([ + $fallbackForRedis = 'redis_main=' . AppwriteURL::unparse([ 'scheme' => 'redis', 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), @@ -774,21 +784,46 @@ $register->set('pools', function () { return $group; }); +$register->set('influxdb', function () { + + // Register DB connection + $host = App::getEnv('_APP_INFLUXDB_HOST', ''); + $port = App::getEnv('_APP_INFLUXDB_PORT', ''); + + if (empty($host) || empty($port)) { + return; + } + $driver = new InfluxDB\Driver\Curl("http://{$host}:{$port}"); + $client = new InfluxDB\Client($host, $port, '', '', false, false, 5); + $client->setDriver($driver); + + return $client; +}); +$register->set('statsd', function () { + // Register DB connection + $host = App::getEnv('_APP_STATSD_HOST', 'telegraf'); + $port = App::getEnv('_APP_STATSD_PORT', 8125); + + $connection = new \Domnikl\Statsd\Connection\UdpSocket($host, $port); + $statsd = new \Domnikl\Statsd\Client($connection); + + return $statsd; +}); $register->set('smtp', function () { $mail = new PHPMailer(true); $mail->isSMTP(); - $username = App::getEnv('_APP_SMTP_USERNAME', null); - $password = App::getEnv('_APP_SMTP_PASSWORD', null); + $username = App::getEnv('_APP_SMTP_USERNAME'); + $password = App::getEnv('_APP_SMTP_PASSWORD'); $mail->XMailer = 'Appwrite Mailer'; $mail->Host = App::getEnv('_APP_SMTP_HOST', 'smtp'); $mail->Port = App::getEnv('_APP_SMTP_PORT', 25); - $mail->SMTPAuth = (!empty($username) && !empty($password)); + $mail->SMTPAuth = !empty($username) && !empty($password); $mail->Username = $username; $mail->Password = $password; - $mail->SMTPSecure = App::getEnv('_APP_SMTP_SECURE', false); + $mail->SMTPSecure = App::getEnv('_APP_SMTP_SECURE', ''); $mail->SMTPAutoTLS = false; $mail->CharSet = 'UTF-8'; @@ -877,9 +912,9 @@ App::setResource('queue', function (Group $pools) { App::setResource('queueForFunctions', function (Connection $queue) { return new Func($queue); }, ['queue']); -App::setResource('queueForUsage', function (Connection $queue) { - return new Usage($queue); -}, ['queue']); +App::setResource('usage', function ($register) { + return new Stats($register->get('statsd')); +}, ['register']); App::setResource('clients', function ($request, $console, $project) { $console->setAttribute('platforms', [ // Always allow current host '$collection' => ID::custom('platforms'), @@ -962,7 +997,11 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons if ($project->isEmpty()) { $user = new Document([]); } else { - $user = $dbForProject->getDocument('users', Auth::$unique); + if ($project->getId() === 'console') { + $user = $dbForConsole->getDocument('users', Auth::$unique); + } else { + $user = $dbForProject->getDocument('users', Auth::$unique); + } } } else { $user = $dbForConsole->getDocument('users', Auth::$unique); @@ -1016,7 +1055,7 @@ App::setResource('project', function ($dbForConsole, $request, $console) { $projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', '')); - if ($projectId === 'console') { + if (empty($projectId) || $projectId === 'console') { return $console; } @@ -1091,11 +1130,44 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) { $database = new Database($dbAdapter, $cache); - $database->setNamespace('console'); + $database->setNamespace('_console'); return $database; }, ['pools', 'cache']); +App::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, $cache) { + $databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools + + $getProjectDB = function (Document $project) use ($pools, $dbForConsole, $cache, &$databases) { + if ($project->isEmpty() || $project->getId() === 'console') { + return $dbForConsole; + } + + $databaseName = $project->getAttribute('database'); + + if (isset($databases[$databaseName])) { + $database = $databases[$databaseName]; + $database->setNamespace('_' . $project->getInternalId()); + return $database; + } + + $dbAdapter = $pools + ->get($databaseName) + ->pop() + ->getResource(); + + $database = new Database($dbAdapter, $cache); + + $databases[$databaseName] = $database; + + $database->setNamespace('_' . $project->getInternalId()); + + return $database; + }; + + return $getProjectDB; +}, ['pools', 'dbForConsole', 'cache']); + App::setResource('cache', function (Group $pools) { $list = Config::getParam('pools-cache', []); $adapters = []; @@ -1131,38 +1203,81 @@ function getDevice($root): Device { $connection = App::getEnv('_APP_CONNECTIONS_STORAGE', ''); - $acl = 'private'; - $device = Storage::DEVICE_LOCAL; - $accessKey = ''; - $accessSecret = ''; - $bucket = ''; - $region = ''; + if (!empty($connection)) { + $acl = 'private'; + $device = Storage::DEVICE_LOCAL; + $accessKey = ''; + $accessSecret = ''; + $bucket = ''; + $region = ''; - try { - $dsn = new DSN($connection); - $device = $dsn->getScheme(); - $accessKey = $dsn->getUser(); - $accessSecret = $dsn->getPassword(); - $bucket = $dsn->getPath(); - $region = $dsn->getParam('region'); - } catch (\Exception $e) { - Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); - } + try { + $dsn = new DSN($connection); + $device = $dsn->getScheme(); + $accessKey = $dsn->getUser() ?? ''; + $accessSecret = $dsn->getPassword() ?? ''; + $bucket = $dsn->getPath() ?? ''; + $region = $dsn->getParam('region'); + } catch (\Exception $e) { + Console::warning($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); + } - switch ($device) { - case Storage::DEVICE_S3: - return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case STORAGE::DEVICE_DO_SPACES: - return new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case Storage::DEVICE_BACKBLAZE: - return new Backblaze($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case Storage::DEVICE_LINODE: - return new Linode($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case Storage::DEVICE_WASABI: - return new Wasabi($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case Storage::DEVICE_LOCAL: - default: - return new Local($root); + switch ($device) { + case Storage::DEVICE_S3: + return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case STORAGE::DEVICE_DO_SPACES: + return new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case Storage::DEVICE_BACKBLAZE: + return new Backblaze($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case Storage::DEVICE_LINODE: + return new Linode($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case Storage::DEVICE_WASABI: + return new Wasabi($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case Storage::DEVICE_LOCAL: + default: + return new Local($root); + } + } else { + switch (strtolower(App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL) ?? '')) { + case Storage::DEVICE_LOCAL: + default: + return new Local($root); + case Storage::DEVICE_S3: + $s3AccessKey = App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', ''); + $s3SecretKey = App::getEnv('_APP_STORAGE_S3_SECRET', ''); + $s3Region = App::getEnv('_APP_STORAGE_S3_REGION', ''); + $s3Bucket = App::getEnv('_APP_STORAGE_S3_BUCKET', ''); + $s3Acl = 'private'; + return new S3($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl); + case Storage::DEVICE_DO_SPACES: + $doSpacesAccessKey = App::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', ''); + $doSpacesSecretKey = App::getEnv('_APP_STORAGE_DO_SPACES_SECRET', ''); + $doSpacesRegion = App::getEnv('_APP_STORAGE_DO_SPACES_REGION', ''); + $doSpacesBucket = App::getEnv('_APP_STORAGE_DO_SPACES_BUCKET', ''); + $doSpacesAcl = 'private'; + return new DOSpaces($root, $doSpacesAccessKey, $doSpacesSecretKey, $doSpacesBucket, $doSpacesRegion, $doSpacesAcl); + case Storage::DEVICE_BACKBLAZE: + $backblazeAccessKey = App::getEnv('_APP_STORAGE_BACKBLAZE_ACCESS_KEY', ''); + $backblazeSecretKey = App::getEnv('_APP_STORAGE_BACKBLAZE_SECRET', ''); + $backblazeRegion = App::getEnv('_APP_STORAGE_BACKBLAZE_REGION', ''); + $backblazeBucket = App::getEnv('_APP_STORAGE_BACKBLAZE_BUCKET', ''); + $backblazeAcl = 'private'; + return new Backblaze($root, $backblazeAccessKey, $backblazeSecretKey, $backblazeBucket, $backblazeRegion, $backblazeAcl); + case Storage::DEVICE_LINODE: + $linodeAccessKey = App::getEnv('_APP_STORAGE_LINODE_ACCESS_KEY', ''); + $linodeSecretKey = App::getEnv('_APP_STORAGE_LINODE_SECRET', ''); + $linodeRegion = App::getEnv('_APP_STORAGE_LINODE_REGION', ''); + $linodeBucket = App::getEnv('_APP_STORAGE_LINODE_BUCKET', ''); + $linodeAcl = 'private'; + return new Linode($root, $linodeAccessKey, $linodeSecretKey, $linodeBucket, $linodeRegion, $linodeAcl); + case Storage::DEVICE_WASABI: + $wasabiAccessKey = App::getEnv('_APP_STORAGE_WASABI_ACCESS_KEY', ''); + $wasabiSecretKey = App::getEnv('_APP_STORAGE_WASABI_SECRET', ''); + $wasabiRegion = App::getEnv('_APP_STORAGE_WASABI_REGION', ''); + $wasabiBucket = App::getEnv('_APP_STORAGE_WASABI_BUCKET', ''); + $wasabiAcl = 'private'; + return new Wasabi($root, $wasabiAccessKey, $wasabiSecretKey, $wasabiBucket, $wasabiRegion, $wasabiAcl); + } } } @@ -1305,22 +1420,26 @@ App::setResource('schema', function ($utopia, $dbForProject) { }, ['utopia', 'dbForProject']); App::setResource('contributors', function () { - $path = 'app/config/cloud/contributors.json'; + $path = 'app/config/contributors.json'; $list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : []; return $list; -}, []); +}); App::setResource('employees', function () { - $path = 'app/config/cloud/employees.json'; + $path = 'app/config/employees.json'; $list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : []; return $list; -}, []); +}); App::setResource('heroes', function () { - $path = 'app/config/cloud/heroes.json'; + $path = 'app/config/heroes.json'; $list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : []; return $list; -}, []); +}); + +App::setResource('gitHub', function (Cache $cache) { + return new VcsGitHub($cache); +}, ['cache']); App::setResource('requestTimestamp', function ($request) { //TODO: Move this to the Request class itself diff --git a/app/realtime.php b/app/realtime.php index 772eee49d6..25b0532b42 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -47,7 +47,7 @@ function getConsoleDB(): Database $database = new Database($dbAdapter, getCache()); - $database->setNamespace('console'); + $database->setNamespace('_console'); return $database; } diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 6a07b07822..4cbfc2fd1a 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -30,15 +30,6 @@ services: ports: - :80 - :443 - ulimits: - nofile: - soft: 655350 - hard: 655350 - sysctls: - - net.core.somaxconn=1024 - - net.ipv4.tcp_rmem=1024 4096 16384 - - net.ipv4.tcp_wmem=1024 4096 16384 - - net.ipv4.ip_local_port_range=1025 65535 volumes: - /var/run/docker.sock:/var/run/docker.sock - appwrite-config:/storage/config:ro @@ -80,6 +71,7 @@ services: - mariadb - redis # - clamav + - influxdb environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -87,8 +79,6 @@ services: - _APP_CONSOLE_WHITELIST_ROOT - _APP_CONSOLE_WHITELIST_EMAILS - _APP_CONSOLE_WHITELIST_IPS - - _APP_CONSOLE_INVITES - - _APP_CONSOLE_ROOT_SESSION - _APP_SYSTEM_EMAIL_NAME - _APP_SYSTEM_EMAIL_ADDRESS - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS @@ -98,28 +88,50 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET + - _APP_DOMAIN_FUNCTIONS + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_CONNECTIONS_MAX - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE - _APP_SMTP_USERNAME - _APP_SMTP_PASSWORD - _APP_USAGE_STATS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT - _APP_STORAGE_LIMIT - _APP_STORAGE_PREVIEW_LIMIT - _APP_STORAGE_ANTIVIRUS - _APP_STORAGE_ANTIVIRUS_HOST - _APP_STORAGE_ANTIVIRUS_PORT - - _APP_CONNECTIONS_STORAGE + - _APP_STORAGE_DEVICE + - _APP_STORAGE_S3_ACCESS_KEY + - _APP_STORAGE_S3_SECRET + - _APP_STORAGE_S3_REGION + - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_DO_SPACES_ACCESS_KEY + - _APP_STORAGE_DO_SPACES_SECRET + - _APP_STORAGE_DO_SPACES_REGION + - _APP_STORAGE_DO_SPACES_BUCKET + - _APP_STORAGE_BACKBLAZE_ACCESS_KEY + - _APP_STORAGE_BACKBLAZE_SECRET + - _APP_STORAGE_BACKBLAZE_REGION + - _APP_STORAGE_BACKBLAZE_BUCKET + - _APP_STORAGE_LINODE_ACCESS_KEY + - _APP_STORAGE_LINODE_SECRET + - _APP_STORAGE_LINODE_REGION + - _APP_STORAGE_LINODE_BUCKET + - _APP_STORAGE_WASABI_ACCESS_KEY + - _APP_STORAGE_WASABI_SECRET + - _APP_STORAGE_WASABI_REGION + - _APP_STORAGE_WASABI_BUCKET - _APP_FUNCTIONS_SIZE_LIMIT - _APP_FUNCTIONS_TIMEOUT - _APP_FUNCTIONS_BUILD_TIMEOUT @@ -130,6 +142,8 @@ services: - _APP_EXECUTOR_HOST - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG + - _APP_STATSD_HOST + - _APP_STATSD_PORT - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -142,6 +156,15 @@ services: - _APP_GRAPHQL_MAX_BATCH_SIZE - _APP_GRAPHQL_MAX_COMPLEXITY - _APP_GRAPHQL_MAX_DEPTH + - _APP_VCS_GITHUB_APP_NAME + - _APP_VCS_GITHUB_PRIVATE_KEY + - _APP_VCS_GITHUB_APP_ID + - _APP_VCS_GITHUB_WEBHOOK_SECRET + - _APP_VCS_GITHUB_CLIENT_SECRET + - _APP_VCS_GITHUB_CLIENT_ID + - _APP_MIGRATIONS_FIREBASE_CLIENT_ID + - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET + - _APP_ASSISTANT_OPENAI_API_KEY appwrite-realtime: image: /: @@ -174,16 +197,15 @@ services: - _APP_WORKER_PER_CORE - _APP_OPTIONS_ABUSE - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_CONNECTIONS_MAX - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - _APP_USAGE_STATS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -201,16 +223,17 @@ services: - mariadb environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -227,6 +250,7 @@ services: - mariadb environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS - _APP_REDIS_HOST @@ -255,17 +279,38 @@ services: - appwrite-certificates:/storage/certificates:rw environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_STORAGE + - _APP_STORAGE_DEVICE + - _APP_STORAGE_S3_ACCESS_KEY + - _APP_STORAGE_S3_SECRET + - _APP_STORAGE_S3_REGION + - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_DO_SPACES_ACCESS_KEY + - _APP_STORAGE_DO_SPACES_SECRET + - _APP_STORAGE_DO_SPACES_REGION + - _APP_STORAGE_DO_SPACES_BUCKET + - _APP_STORAGE_BACKBLAZE_ACCESS_KEY + - _APP_STORAGE_BACKBLAZE_SECRET + - _APP_STORAGE_BACKBLAZE_REGION + - _APP_STORAGE_BACKBLAZE_BUCKET + - _APP_STORAGE_LINODE_ACCESS_KEY + - _APP_STORAGE_LINODE_SECRET + - _APP_STORAGE_LINODE_REGION + - _APP_STORAGE_LINODE_BUCKET + - _APP_STORAGE_WASABI_ACCESS_KEY + - _APP_STORAGE_WASABI_SECRET + - _APP_STORAGE_WASABI_REGION + - _APP_STORAGE_WASABI_BUCKET - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG - _APP_EXECUTOR_SECRET @@ -284,16 +329,17 @@ services: - mariadb environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -310,20 +356,30 @@ services: - mariadb environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG + - _APP_VCS_GITHUB_APP_NAME + - _APP_VCS_GITHUB_PRIVATE_KEY + - _APP_VCS_GITHUB_APP_ID + - _APP_FUNCTIONS_TIMEOUT + - _APP_FUNCTIONS_BUILD_TIMEOUT + - _APP_FUNCTIONS_CPUS + - _APP_FUNCTIONS_MEMORY + - _APP_OPTIONS_FORCE_HTTPS + - _APP_DOMAIN appwrite-worker-certificates: image: /: @@ -341,19 +397,21 @@ services: - appwrite-certificates:/storage/certificates:rw environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET + - _APP_DOMAIN_FUNCTIONS - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -371,20 +429,28 @@ services: - openruntimes-executor environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - _APP_FUNCTIONS_TIMEOUT + - _APP_FUNCTIONS_BUILD_TIMEOUT + - _APP_FUNCTIONS_CPUS + - _APP_FUNCTIONS_MEMORY - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST - _APP_USAGE_STATS + - _APP_DOCKER_HUB_USERNAME + - _APP_DOCKER_HUB_PASSWORD + - _APP_LOGGING_CONFIG + - _APP_LOGGING_PROVIDER appwrite-worker-mails: image: /: @@ -398,6 +464,7 @@ services: - redis environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 - _APP_SYSTEM_EMAIL_NAME - _APP_SYSTEM_EMAIL_ADDRESS @@ -425,6 +492,7 @@ services: - redis environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -446,24 +514,57 @@ services: - redis environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET + - _APP_DOMAIN_FUNCTIONS + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE - _APP_MAINTENANCE_RETENTION_ABUSE - _APP_MAINTENANCE_RETENTION_AUDIT - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY + - _APP_MAINTENANCE_RETENTION_SCHEDULES + + appwrite-usage: + image: /: + entrypoint: usage + container_name: appwrite-usage + <<: *x-logging + restart: unless-stopped + networks: + - appwrite + depends_on: + - influxdb + - mariadb + environment: + - _APP_ENV + - _APP_WORKER_PER_CORE + - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT + - _APP_USAGE_AGGREGATION_INTERVAL + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS + - _APP_LOGGING_PROVIDER + - _APP_LOGGING_CONFIG appwrite-schedule: image: /: @@ -477,17 +578,23 @@ services: - redis environment: - _APP_ENV + - _APP_WORKER_PER_CORE - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS openruntimes-executor: container_name: openruntimes-executor - hostname: exc1 + hostname: executor <<: *x-logging stop_signal: SIGINT - image: openruntimes/executor:0.1.4 + image: openruntimes/executor:0.3.5 networks: - appwrite - runtimes @@ -497,7 +604,6 @@ services: - appwrite-functions:/storage/functions:rw - /tmp:/tmp:rw environment: - - OPR_EXECUTOR_CONNECTION_STORAGE=$_APP_CONNECTIONS_STORAGE - OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_FUNCTIONS_INACTIVE_THRESHOLD - OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_FUNCTIONS_MAINTENANCE_INTERVAL - OPR_EXECUTOR_NETWORK=$_APP_FUNCTIONS_RUNTIMES_NETWORK @@ -508,6 +614,27 @@ services: - OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET - OPR_EXECUTOR_LOGGING_PROVIDER=$_APP_LOGGING_PROVIDER - OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG + - OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE + - OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET + - OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION + - OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET + - OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET + - OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION + - OPR_EXECUTOR_STORAGE_DO_SPACES_BUCKET=$_APP_STORAGE_DO_SPACES_BUCKET + - OPR_EXECUTOR_STORAGE_BACKBLAZE_ACCESS_KEY=$_APP_STORAGE_BACKBLAZE_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_BACKBLAZE_SECRET=$_APP_STORAGE_BACKBLAZE_SECRET + - OPR_EXECUTOR_STORAGE_BACKBLAZE_REGION=$_APP_STORAGE_BACKBLAZE_REGION + - OPR_EXECUTOR_STORAGE_BACKBLAZE_BUCKET=$_APP_STORAGE_BACKBLAZE_BUCKET + - OPR_EXECUTOR_STORAGE_LINODE_ACCESS_KEY=$_APP_STORAGE_LINODE_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_LINODE_SECRET=$_APP_STORAGE_LINODE_SECRET + - OPR_EXECUTOR_STORAGE_LINODE_REGION=$_APP_STORAGE_LINODE_REGION + - OPR_EXECUTOR_STORAGE_LINODE_BUCKET=$_APP_STORAGE_LINODE_BUCKET + - OPR_EXECUTOR_STORAGE_WASABI_ACCESS_KEY=$_APP_STORAGE_WASABI_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_WASABI_SECRET=$_APP_STORAGE_WASABI_SECRET + - OPR_EXECUTOR_STORAGE_WASABI_REGION=$_APP_STORAGE_WASABI_REGION + - OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET mariadb: image: mariadb:10.7 # fix issues when upgrading using: mysql_upgrade -u root -p @@ -523,7 +650,7 @@ services: - MYSQL_DATABASE=${_APP_DB_SCHEMA} - MYSQL_USER=${_APP_DB_USER} - MYSQL_PASSWORD=${_APP_DB_PASS} - command: 'mysqld --innodb-flush-method=fsync --max_connections=${_APP_CONNECTIONS_MAX}' + command: 'mysqld --innodb-flush-method=fsync' redis: image: redis:7.0.4-alpine @@ -549,41 +676,26 @@ services: # volumes: # - appwrite-uploads:/storage/uploads - appwrite-worker-usage: - image: /: - entrypoint: worker-usage + influxdb: + image: appwrite/influxdb:1.5.0 + container_name: appwrite-influxdb <<: *x-logging - container_name: appwrite-worker-usage + restart: unless-stopped networks: - appwrite volumes: - - ./app:/usr/src/code/app - - ./src:/usr/src/code/src - depends_on: - - redis - - mariadb + - appwrite-influxdb:/var/lib/influxdb:rw + + telegraf: + image: appwrite/telegraf:1.4.0 + container_name: appwrite-telegraf + <<: *x-logging + restart: unless-stopped + networks: + - appwrite environment: - - _APP_ENV - - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - - _APP_OPENSSL_KEY_V1 - - _APP_DB_HOST - - _APP_DB_PORT - - _APP_DB_SCHEMA - - _APP_DB_USER - - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - - _APP_USAGE_STATS - - _APP_LOGGING_PROVIDER - - _APP_LOGGING_CONFIG + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT networks: gateway: @@ -599,6 +711,7 @@ volumes: appwrite-cache: appwrite-uploads: appwrite-certificates: - appwrite-config: appwrite-functions: appwrite-builds: + appwrite-influxdb: + appwrite-config: diff --git a/app/worker.php b/app/worker.php index ea086fa43d..51e42969f4 100644 --- a/app/worker.php +++ b/app/worker.php @@ -4,14 +4,17 @@ require_once __DIR__ . '/init.php'; use Appwrite\Event\Func; use Appwrite\Event\Usage; +use Appwrite\Usage\Stats; use Swoole\Runtime; use Utopia\App; use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; +use Utopia\CLI\CLI; use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Queue\Adapter\Swoole; use Utopia\Queue\Message; use Utopia\Queue\Server; @@ -35,7 +38,7 @@ Server::setResource('dbForConsole', function (Cache $cache, Registry $register) ; $adapter = new Database($database, $cache); - $adapter->setNamespace('console'); + $adapter->setNamespace('_console'); return $adapter; }, ['cache', 'register']); @@ -86,22 +89,16 @@ Server::setResource('queueForFunctions', function (Registry $register) { ); }, ['register']); -Server::setResource('queueForUsage', function (Registry $register) { - $pools = $register->get('pools'); - return new Usage( - $pools - ->get('queue') - ->pop() - ->getResource() - ); -}, ['register']); - Server::setResource('log', fn() => new Log()); Server::setResource('logger', function ($register) { return $register->get('logger'); }, ['register']); +Server::setResource('statsd', function ($register) { + return $register->get('statsd'); +}, ['register']); + Server::setResource('pools', function ($register) { return $register->get('pools'); }, ['register']); @@ -111,7 +108,7 @@ $connection = $pools->get('queue')->pop()->getResource(); $workerNumber = swoole_cpu_num() * intval(App::getEnv('_APP_WORKER_PER_CORE', 6)); if (empty(App::getEnv('QUEUE'))) { - throw new Exception('Please configure "QUEUE" environemnt variable.'); + throw new Exception('Please configure "QUEUE" environment variable.'); } $adapter = new Swoole($connection, $workerNumber, App::getEnv('QUEUE')); @@ -149,7 +146,7 @@ $server $log->addExtra('line', $error->getLine()); $log->addExtra('trace', $error->getTraceAsString()); $log->addExtra('detailedTrace', $error->getTrace()); - $log->addExtra('roles', \Utopia\Database\Validator\Authorization::$roles); + $log->addExtra('roles', Authorization::getRoles()); $isProduction = App::getEnv('_APP_ENV', 'development') === 'production'; $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); diff --git a/app/workers/builds.php b/app/workers/builds.php index 972eb5dd18..41867a5dd3 100644 --- a/app/workers/builds.php +++ b/app/workers/builds.php @@ -1,11 +1,14 @@ args['project'] ?? []); $resource = new Document($this->args['resource'] ?? []); $deployment = new Document($this->args['deployment'] ?? []); + $template = new Document($this->args['template'] ?? []); switch ($type) { case BUILD_TYPE_DEPLOYMENT: case BUILD_TYPE_RETRY: Console::info('Creating build for deployment: ' . $deployment->getId()); - $this->buildDeployment($project, $resource, $deployment); + $github = new GitHub($this->getCache()); + $this->buildDeployment($github, $project, $resource, $deployment, $template); break; default: @@ -61,11 +69,12 @@ class BuildsV1 extends Worker * @throws \Utopia\Database\Exception\Structure * @throws Throwable */ - protected function buildDeployment(Document $project, Document $function, Document $deployment) + protected function buildDeployment(GitHub $github, Document $project, Document $function, Document $deployment, Document $template) { global $register; $dbForProject = $this->getProjectDB($project); + $dbForConsole = $this->getConsoleDB(); $function = $dbForProject->getDocument('functions', $function->getId()); if ($function->isEmpty()) { @@ -77,6 +86,10 @@ class BuildsV1 extends Worker throw new Exception('Deployment not found', 404); } + if (empty($deployment->getAttribute('entrypoint', ''))) { + throw new Exception('Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".', 500); + } + $runtimes = Config::getParam('runtimes', []); $key = $function->getAttribute('runtime'); $runtime = isset($runtimes[$key]) ? $runtimes[$key] : null; @@ -84,18 +97,20 @@ class BuildsV1 extends Worker throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); } - $connection = App::getEnv('_APP_CONNECTIONS_STORAGE', ''); /** @TODO : move this to the registry or someplace else */ - $device = Storage::DEVICE_LOCAL; - try { - $dsn = new DSN($connection); - $device = $dsn->getScheme(); - } catch (\Exception $e) { - Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); - } + // Realtime preparation + $allEvents = Event::generateEvents('functions.[functionId].deployments.[deploymentId].update', [ + 'functionId' => $function->getId(), + 'deploymentId' => $deployment->getId() + ]); + + $startTime = DateTime::now(); + $durationStart = \microtime(true); $buildId = $deployment->getAttribute('buildId', ''); - $startTime = DateTime::now(); - if (empty($buildId)) { + + $isNewBuild = empty($buildId); + + if ($isNewBuild) { $buildId = ID::unique(); $build = $dbForProject->createDocument('builds', new Document([ '$id' => $buildId, @@ -104,15 +119,16 @@ class BuildsV1 extends Worker 'deploymentInternalId' => $deployment->getInternalId(), 'deploymentId' => $deployment->getId(), 'status' => 'processing', - 'outputPath' => '', + 'path' => '', 'runtime' => $function->getAttribute('runtime'), - 'source' => $deployment->getAttribute('path'), - 'sourceType' => $device, - 'stdout' => '', - 'stderr' => '', + 'source' => $deployment->getAttribute('path', ''), + 'sourceType' => strtolower(App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL)), + 'logs' => '', 'endTime' => null, - 'duration' => 0 + 'duration' => 0, + 'size' => 0 ])); + $deployment->setAttribute('buildId', $build->getId()); $deployment->setAttribute('buildInternalId', $build->getInternalId()); $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment); @@ -120,91 +136,307 @@ class BuildsV1 extends Worker $build = $dbForProject->getDocument('builds', $buildId); } - /** Request the executor to build the code... */ - $build->setAttribute('status', 'building'); - $build = $dbForProject->updateDocument('builds', $buildId, $build); + $source = $deployment->getAttribute('path', ''); + $installationId = $deployment->getAttribute('installationId', ''); + $providerRepositoryId = $deployment->getAttribute('providerRepositoryId', ''); + $providerCommitHash = $deployment->getAttribute('providerCommitHash', ''); + $isVcsEnabled = $providerRepositoryId ? true : false; + $owner = ''; + $repositoryName = ''; - /** Trigger Webhook */ - $deploymentModel = new Deployment(); + if ($isVcsEnabled) { + $installation = $dbForConsole->getDocument('installations', $installationId); + $providerInstallationId = $installation->getAttribute('providerInstallationId'); + $privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID'); - $deploymentUpdate = new Event(Event::WEBHOOK_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME); - $deploymentUpdate - ->setProject($project) - ->setEvent('functions.[functionId].deployments.[deploymentId].update') - ->setParam('functionId', $function->getId()) - ->setParam('deploymentId', $deployment->getId()) - ->setPayload($deployment->getArrayCopy(array_keys($deploymentModel->getRules()))) - ->trigger(); - - /** Trigger Functions */ - $pools = $register->get('pools'); - $connection = $pools->get('queue')->pop(); - - $functions = new Func($connection->getResource()); - $functions - ->from($deploymentUpdate) - ->trigger(); - - $connection->reclaim(); - - /** Trigger Realtime */ - $allEvents = Event::generateEvents('functions.[functionId].deployments.[deploymentId].update', [ - 'functionId' => $function->getId(), - 'deploymentId' => $deployment->getId() - ]); - $target = Realtime::fromPayload( - // Pass first, most verbose event pattern - event: $allEvents[0], - payload: $build, - project: $project - ); - - Realtime::send( - projectId: 'console', - payload: $build->getArrayCopy(), - events: $allEvents, - channels: $target['channels'], - roles: $target['roles'] - ); - - $source = $deployment->getAttribute('path'); - - $vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { - $carry[$var->getAttribute('key')] = $var->getAttribute('value'); - return $carry; - }, []); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + } try { - $response = $this->executor->createRuntime( - deploymentId: $deployment->getId(), - projectId: $project->getId(), - source: $source, - image: $runtime['image'], - remove: true, - entrypoint: $deployment->getAttribute('entrypoint'), - workdir: '/usr/code', - destination: APP_STORAGE_BUILDS . "/app-{$project->getId()}", - variables: $vars, - commands: [ - 'sh', '-c', - 'tar -zxf /tmp/code.tar.gz -C /usr/code && \ - cd /usr/local/src/ && ./build.sh' - ] + if ($isNewBuild && $isVcsEnabled) { + $tmpDirectory = '/tmp/builds/' . $buildId . '/code'; + $rootDirectory = $function->getAttribute('providerRootDirectory', ''); + $rootDirectory = \rtrim($rootDirectory, '/'); + $rootDirectory = \ltrim($rootDirectory, '.'); + $rootDirectory = \ltrim($rootDirectory, '/'); + + $owner = $github->getOwnerName($providerInstallationId); + $repositoryName = $github->getRepositoryName($providerRepositoryId); + + $cloneOwner = $deployment->getAttribute('providerRepositoryOwner', $owner); + $cloneRepository = $deployment->getAttribute('providerRepositoryName', $repositoryName); + + $branchName = $deployment->getAttribute('providerBranch'); + $commitHash = $deployment->getAttribute('providerCommitHash', ''); + $gitCloneCommand = $github->generateCloneCommand($cloneOwner, $cloneRepository, $branchName, $tmpDirectory, $rootDirectory, $commitHash); + $stdout = ''; + $stderr = ''; + Console::execute('mkdir -p /tmp/builds/' . \escapeshellcmd($buildId), '', $stdout, $stderr); + $exit = Console::execute($gitCloneCommand, '', $stdout, $stderr); + + if ($exit !== 0) { + throw new \Exception('Unable to clone code repository: ' . $stderr); + } + + // Build from template + $templateRepositoryName = $template->getAttribute('repositoryName', ''); + $templateOwnerName = $template->getAttribute('ownerName', ''); + $templateBranch = $template->getAttribute('branch', ''); + + $templateRootDirectory = $template->getAttribute('rootDirectory', ''); + $templateRootDirectory = \rtrim($templateRootDirectory, '/'); + $templateRootDirectory = \ltrim($templateRootDirectory, '.'); + $templateRootDirectory = \ltrim($templateRootDirectory, '/'); + + if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateBranch)) { + // Clone template repo + $tmpTemplateDirectory = '/tmp/builds/' . \escapeshellcmd($buildId) . '/template'; + $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, $tmpTemplateDirectory, $templateRootDirectory); + $exit = Console::execute($gitCloneCommandForTemplate, '', $stdout, $stderr); + + if ($exit !== 0) { + throw new \Exception('Unable to clone code repository: ' . $stderr); + } + + // Ensure directories + Console::execute('mkdir -p ' . $tmpTemplateDirectory . '/' . $templateRootDirectory, '', $stdout, $stderr); + Console::execute('mkdir -p ' . $tmpDirectory . '/' . $rootDirectory, '', $stdout, $stderr); + + // Merge template into user repo + Console::execute('cp -rfn ' . $tmpTemplateDirectory . '/' . $templateRootDirectory . '/* ' . $tmpDirectory . '/' . $rootDirectory, '', $stdout, $stderr); + + // Commit and push + $exit = Console::execute('git config --global user.email "team@appwrite.io" && git config --global user.name "Appwrite" && cd ' . $tmpDirectory . ' && git add . && git commit -m "Create \'' . \escapeshellcmd($function->getAttribute('name', '')) . '\' function" && git push origin ' . \escapeshellcmd($branchName), '', $stdout, $stderr); + + if ($exit !== 0) { + throw new \Exception('Unable to push code repository: ' . $stderr); + } + + $exit = Console::execute('cd ' . $tmpDirectory . ' && git rev-parse HEAD', '', $stdout, $stderr); + + if ($exit !== 0) { + throw new \Exception('Unable to get vcs commit SHA: ' . $stderr); + } + + $providerCommitHash = \trim($stdout); + $authorUrl = "https://github.com/$cloneOwner"; + + $deployment->setAttribute('providerCommitHash', $providerCommitHash ?? ''); + $deployment->setAttribute('providerCommitAuthorUrl', $authorUrl); + $deployment->setAttribute('providerCommitAuthor', 'Appwrite'); + $deployment->setAttribute('providerCommitMessage', "Create '" . $function->getAttribute('name', '') . "' function"); + $deployment->setAttribute('providerCommitUrl', "https://github.com/$cloneOwner/$cloneRepository/commit/$providerCommitHash"); + $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment); + + /** + * Send realtime Event + */ + $target = Realtime::fromPayload( + // Pass first, most verbose event pattern + event: $allEvents[0], + payload: $build, + project: $project + ); + Realtime::send( + projectId: 'console', + payload: $build->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'] + ); + } + + Console::execute('tar --exclude code.tar.gz -czf /tmp/builds/' . \escapeshellcmd($buildId) . '/code.tar.gz -C /tmp/builds/' . \escapeshellcmd($buildId) . '/code' . (empty($rootDirectory) ? '' : '/' . $rootDirectory) . ' .', '', $stdout, $stderr); + + $deviceFunctions = $this->getFunctionsDevice($project->getId()); + + $fileName = 'code.tar.gz'; + $fileTmpName = '/tmp/builds/' . $buildId . '/code.tar.gz'; + + $path = $deviceFunctions->getPath($deployment->getId() . '.' . \pathinfo($fileName, PATHINFO_EXTENSION)); + + $result = $deviceFunctions->move($fileTmpName, $path); + + if (!$result) { + throw new \Exception("Unable to move file"); + } + + Console::execute('rm -rf /tmp/builds/' . \escapeshellcmd($buildId), '', $stdout, $stderr); + + $source = $path; + + $build = $dbForProject->updateDocument('builds', $build->getId(), $build->setAttribute('source', $source)); + + $this->runGitAction('processing', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole); + } + + /** Request the executor to build the code... */ + $build->setAttribute('status', 'building'); + $build = $dbForProject->updateDocument('builds', $buildId, $build); + + if ($isVcsEnabled) { + $this->runGitAction('building', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole); + } + + /** Trigger Webhook */ + $deploymentModel = new Deployment(); + + $deploymentUpdate = new Event(Event::WEBHOOK_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME); + $deploymentUpdate + ->setProject($project) + ->setEvent('functions.[functionId].deployments.[deploymentId].update') + ->setParam('functionId', $function->getId()) + ->setParam('deploymentId', $deployment->getId()) + ->setPayload($deployment->getArrayCopy(array_keys($deploymentModel->getRules()))) + ->trigger(); + + /** Trigger Functions */ + $pools = $register->get('pools'); + $connection = $pools->get('queue')->pop(); + + $functions = new Func($connection->getResource()); + $functions + ->from($deploymentUpdate) + ->trigger(); + + $connection->reclaim(); + + /** Trigger Realtime */ + $target = Realtime::fromPayload( + // Pass first, most verbose event pattern + event: $allEvents[0], + payload: $build, + project: $project ); - $endTime = new \DateTime(); - $endTime->setTimestamp($response['endTimeUnix']); + Realtime::send( + projectId: 'console', + payload: $build->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'] + ); + + $vars = []; + + // Global vars + $varsFromProject = $dbForProject->find('variables', [ + Query::equal('resourceType', ['project']), + Query::limit(APP_LIMIT_SUBQUERY) + ]); + + foreach ($varsFromProject as $var) { + $vars[$var->getAttribute('key')] = $var->getAttribute('value') ?? ''; + } + + // Function vars + $vars = \array_merge($vars, array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { + $carry[$var->getAttribute('key')] = $var->getAttribute('value'); + return $carry; + }, [])); + + // Appwrite vars + $vars = \array_merge($vars, [ + 'APPWRITE_FUNCTION_ID' => $function->getId(), + 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'), + 'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(), + 'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(), + 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '', + 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '', + ]); + + $command = $deployment->getAttribute('commands', ''); + $command = \str_replace('"', '\\"', $command); + + $response = null; + + $err = null; + + // TODO: Remove run() wrapper when switching to new utopia queue. That should be done on Swoole adapter in the libary + Co\run(function () use ($project, $deployment, &$response, $source, $function, $runtime, $vars, $command, &$build, $dbForProject, $allEvents, &$err) { + Co::join([ + Co\go(function () use (&$response, $project, $deployment, $source, $function, $runtime, $vars, $command, &$err) { + try { + $response = $this->executor->createRuntime( + deploymentId: $deployment->getId(), + projectId: $project->getId(), + source: $source, + image: $runtime['image'], + version: $function->getAttribute('version'), + remove: true, + entrypoint: $deployment->getAttribute('entrypoint'), + destination: APP_STORAGE_BUILDS . "/app-{$project->getId()}", + variables: $vars, + command: 'tar -zxf /tmp/code.tar.gz -C /mnt/code && helpers/build.sh "' . $command . '"' + ); + } catch (Exception $error) { + $err = $error; + } + }), + Co\go(function () use ($project, $deployment, &$response, &$build, $dbForProject, $allEvents, &$err) { + try { + $this->executor->getLogs( + deploymentId: $deployment->getId(), + projectId: $project->getId(), + callback: function ($logs) use (&$response, &$build, $dbForProject, $allEvents, $project) { + if ($response === null) { + $build = $dbForProject->getDocument('builds', $build->getId()); + + if ($build->isEmpty()) { + throw new Exception('Build not found', 404); + } + + $build = $build->setAttribute('logs', $build->getAttribute('logs', '') . $logs); + $build = $dbForProject->updateDocument('builds', $build->getId(), $build); + + /** + * Send realtime Event + */ + $target = Realtime::fromPayload( + // Pass first, most verbose event pattern + event: $allEvents[0], + payload: $build, + project: $project + ); + Realtime::send( + projectId: 'console', + payload: $build->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'] + ); + } + } + ); + } catch (Exception $error) { + if (empty($err)) { + $err = $error; + } + } + }), + ]); + }); + + if ($err) { + throw $err; + } + + $endTime = DateTime::now(); + $durationEnd = \microtime(true); /** Update the build document */ - $build->setAttribute('endTime', DateTime::format($endTime)); - $build->setAttribute('duration', \intval($response['duration'])); - $build->setAttribute('status', $response['status']); - $build->setAttribute('outputPath', $response['outputPath']); - $build->setAttribute('stderr', $response['stderr']); - $build->setAttribute('stdout', $response['stdout']); + $build->setAttribute('startTime', DateTime::format((new \DateTime())->setTimestamp($response['startTime']))); + $build->setAttribute('endTime', $endTime); + $build->setAttribute('duration', \intval(\ceil($durationEnd - $durationStart))); + $build->setAttribute('status', 'ready'); + $build->setAttribute('path', $response['path']); + $build->setAttribute('size', $response['size']); + $build->setAttribute('logs', $response['output']); - /* Also update the deployment buildTime */ - $deployment->setAttribute('buildTime', $response['duration']); + if ($isVcsEnabled) { + $this->runGitAction('ready', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole); + } Console::success("Build id: $buildId created"); @@ -212,28 +444,33 @@ class BuildsV1 extends Worker if ($deployment->getAttribute('activate') === true) { $function->setAttribute('deploymentInternalId', $deployment->getInternalId()); $function->setAttribute('deployment', $deployment->getId()); + $function->setAttribute('live', true); $function = $dbForProject->updateDocument('functions', $function->getId(), $function); } /** Update function schedule */ $dbForConsole = $this->getConsoleDB(); + // Inform scheduler if function is still active $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); - $schedule->setAttribute('resourceUpdatedAt', DateTime::now()); - $schedule + ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); - - Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); } catch (\Throwable $th) { $endTime = DateTime::now(); - $interval = (new \DateTime($endTime))->diff(new \DateTime($startTime)); + $durationEnd = \microtime(true); $build->setAttribute('endTime', $endTime); - $build->setAttribute('duration', $interval->format('%s') + 0); + $build->setAttribute('duration', \intval(\ceil($durationEnd - $durationStart))); $build->setAttribute('status', 'failed'); - $build->setAttribute('stderr', $th->getMessage()); + $build->setAttribute('logs', $th->getMessage()); Console::error($th->getMessage()); + Console::error($th->getFile() . ':' . $th->getLine()); + Console::error($th->getTraceAsString()); + + if ($isVcsEnabled) { + $this->runGitAction('failed', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole); + } } finally { $build = $dbForProject->updateDocument('builds', $buildId, $build); @@ -241,7 +478,7 @@ class BuildsV1 extends Worker * Send realtime Event */ $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $allEvents[0], payload: $build, project: $project @@ -253,20 +490,93 @@ class BuildsV1 extends Worker channels: $target['channels'], roles: $target['roles'] ); + + /** Update usage stats */ + if (App::getEnv('_APP_USAGE_STATS', 'enabled') === 'enabled') { + $statsd = $register->get('statsd'); + $usage = new Stats($statsd); + $usage + ->setParam('projectInternalId', $project->getInternalId()) + ->setParam('projectId', $project->getId()) + ->setParam('functionId', $function->getId()) + ->setParam('builds.{scope}.compute', 1) + ->setParam('buildStatus', $build->getAttribute('status', '')) + ->setParam('buildTime', $build->getAttribute('duration')) + ->setParam('networkRequestSize', 0) + ->setParam('networkResponseSize', 0) + ->submit(); + } + } + } + + protected function runGitAction(string $status, GitHub $github, string $providerCommitHash, string $owner, string $repositoryName, Document $project, Document $function, string $deploymentId, Database $dbForProject, Database $dbForConsole): void + { + if ($function->getAttribute('providerSilentMode', false) === true) { + return; } - /** Trigger usage queue */ - $this - ->getUsageQueue() - ->setProject($project) - ->addMetric(METRIC_BUILDS, 1) // per project - ->addMetric(METRIC_BUILDS_STORAGE, $build->getAttribute('size', 0)) - ->addMetric(METRIC_BUILDS_COMPUTE, (int)$build->getAttribute('duration', 0) * 1000) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS), 1) // per function - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE), $build->getAttribute('size', 0)) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int)$build->getAttribute('duration', 0) * 1000) - ->trigger() - ; + $deployment = $dbForProject->getDocument('deployments', $deploymentId); + $commentId = $deployment->getAttribute('providerCommentId', ''); + + if (!empty($providerCommitHash)) { + $message = match ($status) { + 'ready' => 'Build succeeded.', + 'failed' => 'Build failed.', + 'processing' => 'Building...', + default => $status + }; + + $state = match ($status) { + 'ready' => 'success', + 'failed' => 'failure', + 'processing' => 'pending', + default => $status + }; + + $functionName = $function->getAttribute('name'); + $projectName = $project->getAttribute('name'); + + $name = "{$functionName} ({$projectName})"; + + $protocol = App::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; + $hostname = App::getEnv('_APP_DOMAIN'); + $functionId = $function->getId(); + $projectId = $project->getId(); + $providerTargetUrl = $protocol . '://' . $hostname . "/console/project-$projectId/functions/function-$functionId"; + + $github->updateCommitStatus($repositoryName, $providerCommitHash, $owner, $state, $message, $providerTargetUrl, $name); + } + + if (!empty($commentId)) { + $retries = 0; + + while (true) { + $retries++; + + try { + $dbForConsole->createDocument('vcsCommentLocks', new Document([ + '$id' => $commentId + ])); + break; + } catch (Exception $err) { + if ($retries >= 9) { + throw $err; + } + + \sleep(1); + } + } + + // Wrap in try/finally to ensure lock file gets deleted + try { + $comment = new Comment(); + $comment->parseComment($github->getComment($owner, $repositoryName, $commentId)); + $comment->addBuild($project, $function, $status, $deployment->getId(), ['type' => 'logs']); + $github->updateComment($owner, $repositoryName, $commentId, $comment->generateComment()); + } finally { + $dbForConsole->deleteDocument('vcsCommentLocks', $commentId); + } + } } public function shutdown(): void diff --git a/app/workers/certificates.php b/app/workers/certificates.php index 824a296b75..5a1e173b3a 100644 --- a/app/workers/certificates.php +++ b/app/workers/certificates.php @@ -2,6 +2,9 @@ use Appwrite\Event\Mail; use Appwrite\Network\Validator\CNAME; +use Appwrite\Utopia\Response\Model\Rule; +use Appwrite\Messaging\Adapter\Realtime; +use Appwrite\Event\Event; use Appwrite\Resque\Worker; use Appwrite\Template\Template; use Utopia\App; @@ -46,7 +49,7 @@ class CertificatesV1 extends Worker * 4. Validate security email. Cannot be empty, required by LetsEncrypt * 5. Validate renew date with certificate file, unless requested to skip by parameter * 6. Issue a certificate using certbot CLI - * 7. Update 'log' attribute on certificate document with Certbot message + * 7. Update 'logs' attribute on certificate document with Certbot message * 8. Create storage folder for certificate, if not ready already * 9. Move certificates from Certbot location to our Storage * 10. Create/Update our Storage with new Traefik config with new certificate paths @@ -56,7 +59,7 @@ class CertificatesV1 extends Worker * If at any point unexpected error occurs, program stops without applying changes to document, and error is thrown into worker * * If code stops with expected error: - * 1. 'log' attribute on document is updated with error message + * 1. 'logs' attribute on document is updated with error message * 2. 'attempts' amount is increased * 3. Console log is shown * 4. Email is sent to security email @@ -84,6 +87,8 @@ class CertificatesV1 extends Worker $certificate->setAttribute('domain', $domain->get()); } + $success = false; + try { // Email for alerts is required by LetsEncrypt $email = App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS'); @@ -110,11 +115,8 @@ class CertificatesV1 extends Worker $letsEncryptData = $this->issueCertificate($folder, $domain->get(), $email); // Command succeeded, store all data into document - // We store stderr too, because it may include warnings - $certificate->setAttribute('log', \json_encode([ - 'stdout' => $letsEncryptData['stdout'], - 'stderr' => $letsEncryptData['stderr'], - ])); + $logs = 'Certificate successfully generated.'; + $certificate->setAttribute('logs', \mb_strcut($logs, 0, 1000000));// Limit to 1MB // Give certificates to Traefik $this->applyCertificateFiles($folder, $domain->get(), $letsEncryptData); @@ -123,9 +125,13 @@ class CertificatesV1 extends Worker $certificate->setAttribute('renewDate', $this->getRenewDate($domain->get())); $certificate->setAttribute('attempts', 0); $certificate->setAttribute('issueDate', DateTime::now()); + + $success = true; } catch (Throwable $e) { + $logs = $e->getMessage(); + // Set exception as log in certificate document - $certificate->setAttribute('log', $e->getMessage()); + $certificate->setAttribute('logs', \mb_strcut($logs, 0, 1000000));// Limit to 1MB // Increase attempts count $attempts = $certificate->getAttribute('attempts', 0) + 1; @@ -141,7 +147,7 @@ class CertificatesV1 extends Worker $certificate->setAttribute('updated', DateTime::now()); // Save all changes we made to certificate document into database - $this->saveCertificateDocument($domain->get(), $certificate); + $this->saveCertificateDocument($domain->get(), $certificate, $success); } } @@ -154,10 +160,11 @@ class CertificatesV1 extends Worker * * @param string $domain Domain name that certificate is for * @param Document $certificate Certificate document that we need to save + * @param bool $success Was certificate generation successful? * * @return void */ - private function saveCertificateDocument(string $domain, Document $certificate): void + private function saveCertificateDocument(string $domain, Document $certificate, bool $success): void { // Check if update or insert required $certificateDocument = $this->dbForConsole->findOne('certificates', [Query::equal('domain', [$domain])]); @@ -171,7 +178,7 @@ class CertificatesV1 extends Worker } $certificateId = $certificate->getId(); - $this->updateDomainDocuments($certificateId, $domain); + $this->updateDomainDocuments($certificateId, $domain, $success); } /** @@ -184,11 +191,6 @@ class CertificatesV1 extends Worker $envDomain = App::getEnv('_APP_DOMAIN', ''); if (!empty($envDomain) && $envDomain !== 'localhost') { return $envDomain; - } else { - $domainDocument = $this->dbForConsole->findOne('domains', [Query::orderAsc('_id')]); - if ($domainDocument) { - return $domainDocument->getAttribute('domain'); - } } return null; @@ -279,7 +281,7 @@ class CertificatesV1 extends Worker $stderr = ''; $staging = (App::isProduction()) ? '' : ' --dry-run'; - $exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}" + $exit = Console::execute("certbot certonly -v --webroot --noninteractive --agree-tos{$staging}" . " --email " . $email . " --cert-name " . $folder . " -w " . APP_STORAGE_CERTIFICATES @@ -420,25 +422,64 @@ class CertificatesV1 extends Worker * * @param string $certificateId ID of a new or updated certificate document * @param string $domain Domain that is affected by new certificate + * @param bool $success Was certificate generation successful? * * @return void */ - private function updateDomainDocuments(string $certificateId, string $domain): void + private function updateDomainDocuments(string $certificateId, string $domain, bool $success): void { - $domains = $this->dbForConsole->find('domains', [ + $rule = $this->dbForConsole->findOne('rules', [ Query::equal('domain', [$domain]), - Query::limit(1000), ]); - foreach ($domains as $domainDocument) { - $domainDocument->setAttribute('updated', DateTime::now()); - $domainDocument->setAttribute('certificateId', $certificateId); + if ($rule !== false && !$rule->isEmpty()) { + $rule->setAttribute('certificateId', $certificateId); + $rule->setAttribute('status', $success ? 'verified' : 'unverified'); + $this->dbForConsole->updateDocument('rules', $rule->getId(), $rule); - $this->dbForConsole->updateDocument('domains', $domainDocument->getId(), $domainDocument); + $projectId = $rule->getAttribute('projectId'); + $project = $this->dbForConsole->getDocument('projects', $projectId); - if ($domainDocument->getAttribute('projectId')) { - $this->dbForConsole->deleteCachedDocument('projects', $domainDocument->getAttribute('projectId')); - } + /** Trigger Webhook */ + $ruleModel = new Rule(); + $ruleUpdate = new Event(Event::WEBHOOK_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME); + $ruleUpdate + ->setProject($project) + ->setEvent('rules.[ruleId].update') + ->setParam('ruleId', $rule->getId()) + ->setPayload($rule->getArrayCopy(array_keys($ruleModel->getRules()))) + ->trigger(); + + /** Trigger Functions */ + $ruleUpdate + ->setClass(Event::FUNCTIONS_CLASS_NAME) + ->setQueue(Event::FUNCTIONS_QUEUE_NAME) + ->trigger(); + + /** Trigger realtime event */ + $allEvents = Event::generateEvents('rules.[ruleId].update', [ + 'ruleId' => $rule->getId(), + ]); + $target = Realtime::fromPayload( + // Pass first, most verbose event pattern + event: $allEvents[0], + payload: $rule, + project: $project + ); + Realtime::send( + projectId: 'console', + payload: $rule->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'] + ); + Realtime::send( + projectId: $project->getId(), + payload: $rule->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'] + ); } } } diff --git a/app/workers/deletes.php b/app/workers/deletes.php index 6aa91cd590..f3968c07f2 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -1,6 +1,7 @@ deleteBucket($document, $project); break; + case DELETE_TYPE_INSTALLATIONS: + $this->deleteInstallation($document, $project); + break; + case DELETE_TYPE_RULES: + $this->deleteRule($document, $project); + break; default: if (\str_starts_with($document->getCollection(), 'database_')) { $this->deleteCollection($document, $project); @@ -106,11 +113,6 @@ class DeletesV1 extends Worker $this->deleteExpiredSessions(); break; - case DELETE_TYPE_CERTIFICATES: - $document = new Document($this->args['document']); - $this->deleteCertificates($document); - break; - case DELETE_TYPE_USAGE: $this->deleteUsageStats($this->args['hourlyUsageRetentionDatetime']); break; @@ -470,6 +472,11 @@ class DeletesV1 extends Worker $this->deleteByGroup('tokens', [ Query::equal('userInternalId', [$userInternalId]) ], $dbForProject); + + // Delete identities + $this->deleteByGroup('identities', [ + Query::equal('userInternalId', [$userInternalId]) + ], $dbForProject); } /** @@ -584,15 +591,29 @@ class DeletesV1 extends Worker { $projectId = $project->getId(); $dbForProject = $this->getProjectDB($project); + $dbForConsole = $this->getConsoleDB(); $functionId = $document->getId(); $functionInternalId = $document->getInternalId(); + /** + * Delete rules + */ + Console::info("Deleting rules for function " . $functionId); + $this->deleteByGroup('rules', [ + Query::equal('resourceType', ['function']), + Query::equal('resourceInternalId', [$functionInternalId]), + Query::equal('projectInternalId', [$project->getInternalId()]) + ], $dbForConsole, function (Document $document) use ($project) { + $this->deleteRule($document, $project); + }); + /** * Delete Variables */ Console::info("Deleting variables for function " . $functionId); $this->deleteByGroup('variables', [ - Query::equal('functionInternalId', [$functionInternalId]) + Query::equal('resourceType', ['function']), + Query::equal('resourceInternalId', [$functionInternalId]) ], $dbForProject); /** @@ -600,11 +621,11 @@ class DeletesV1 extends Worker */ Console::info("Deleting deployments for function " . $functionId); $storageFunctions = $this->getFunctionsDevice($projectId); - $deploymentIds = []; + $deploymentInternalIds = []; $this->deleteByGroup('deployments', [ - Query::equal('resourceId', [$functionId]) - ], $dbForProject, function (Document $document) use ($storageFunctions, &$deploymentIds) { - $deploymentIds[] = $document->getId(); + Query::equal('resourceInternalId', [$functionInternalId]) + ], $dbForProject, function (Document $document) use ($storageFunctions, &$deploymentInternalIds) { + $deploymentInternalIds[] = $document->getInternalId(); if ($storageFunctions->delete($document->getAttribute('path', ''), true)) { Console::success('Deleted deployment files: ' . $document->getAttribute('path', '')); } else { @@ -617,14 +638,14 @@ class DeletesV1 extends Worker */ Console::info("Deleting builds for function " . $functionId); $storageBuilds = $this->getBuildsDevice($projectId); - foreach ($deploymentIds as $deploymentId) { + foreach ($deploymentInternalIds as $deploymentInternalId) { $this->deleteByGroup('builds', [ - Query::equal('deploymentId', [$deploymentId]) - ], $dbForProject, function (Document $document) use ($storageBuilds, $deploymentId) { - if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) { - Console::success('Deleted build files: ' . $document->getAttribute('outputPath', '')); + Query::equal('deploymentInternalId', [$deploymentInternalId]) + ], $dbForProject, function (Document $document) use ($storageBuilds) { + if ($storageBuilds->delete($document->getAttribute('path', ''), true)) { + Console::success('Deleted build files: ' . $document->getAttribute('path', '')); } else { - Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', '')); + Console::error('Failed to delete build files: ' . $document->getAttribute('path', '')); } }); } @@ -634,10 +655,14 @@ class DeletesV1 extends Worker */ Console::info("Deleting executions for function " . $functionId); $this->deleteByGroup('executions', [ - Query::equal('functionId', [$functionId]) + Query::equal('functionInternalId', [$functionInternalId]) ], $dbForProject); - // TODO: Request executor to delete runtime + /** + * Request executor to delete all deployment containers + */ + Console::info("Requesting executor to delete all deployment containers for function " . $functionId); + $this->deleteRuntimes($document, $project); } /** @@ -649,7 +674,7 @@ class DeletesV1 extends Worker $projectId = $project->getId(); $dbForProject = $this->getProjectDB($project); $deploymentId = $document->getId(); - $functionId = $document->getAttribute('resourceId'); + $deploymentInternalId = $document->getInternalId(); /** * Delete deployment files @@ -668,16 +693,21 @@ class DeletesV1 extends Worker Console::info("Deleting builds for deployment " . $deploymentId); $storageBuilds = $this->getBuildsDevice($projectId); $this->deleteByGroup('builds', [ - Query::equal('deploymentId', [$deploymentId]) + Query::equal('deploymentInternalId', [$deploymentInternalId]) ], $dbForProject, function (Document $document) use ($storageBuilds) { - if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) { - Console::success('Deleted build files: ' . $document->getAttribute('outputPath', '')); + if ($storageBuilds->delete($document->getAttribute('path', ''), true)) { + Console::success('Deleted build files: ' . $document->getAttribute('path', '')); } else { - Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', '')); + Console::error('Failed to delete build files: ' . $document->getAttribute('path', '')); } }); - // TODO: Request executor to delete runtime + + /** + * Request executor to delete all deployment containers + */ + Console::info("Requesting executor to delete deployment container for deployment " . $deploymentId); + $this->deleteRuntimes($document, $project); } @@ -828,44 +858,18 @@ class DeletesV1 extends Worker } /** - * @param Document $document certificates document - * @throws \Utopia\Database\Exception\Authorization + * @param Document $document rule document + * @param Document $project project document */ - protected function deleteCertificates(Document $document): void + protected function deleteRule(Document $document, Document $project): void { $consoleDB = $this->getConsoleDB(); - // If domain has certificate generated - if (isset($document['certificateId'])) { - $domainUsingCertificate = $consoleDB->findOne('domains', [ - Query::equal('certificateId', [$document['certificateId']]) - ]); - - if (!$domainUsingCertificate) { - $mainDomain = App::getEnv('_APP_DOMAIN_TARGET', ''); - if ($mainDomain === $document->getAttribute('domain')) { - $domainUsingCertificate = $mainDomain; - } - } - - // If certificate is still used by some domain, mark we can't delete. - // Current domain should not be found, because we only have copy. Original domain is already deleted from database. - if ($domainUsingCertificate) { - Console::warning("Skipping certificate deletion, because a domain is still using it."); - return; - } - } - $domain = $document->getAttribute('domain'); $directory = APP_STORAGE_CERTIFICATES . '/' . $domain; $checkTraversal = realpath($directory) === $directory; - if ($domain && $checkTraversal && is_dir($directory)) { - // Delete certificate document, so Appwrite is aware of change - if (isset($document['certificateId'])) { - $consoleDB->deleteDocument('certificates', $document['certificateId']); - } - + if ($checkTraversal && is_dir($directory)) { // Delete files, so Traefik is aware of change array_map('unlink', glob($directory . '/*.*')); rmdir($directory); @@ -873,6 +877,11 @@ class DeletesV1 extends Worker } else { Console::info("No certificate files found for {$domain}"); } + + // Delete certificate document, so Appwrite is aware of change + if (isset($document['certificateId'])) { + $consoleDB->deleteDocument('certificates', $document['certificateId']); + } } protected function deleteBucket(Document $document, Document $project) @@ -885,4 +894,72 @@ class DeletesV1 extends Worker $device->deletePath($document->getId()); } + + protected function deleteInstallation(Document $document, Document $project) + { + $dbForProject = $this->getProjectDB($project); + $dbForConsole = $this->getConsoleDB(); + + $this->listByGroup('functions', [ + Query::equal('installationInternalId', [$document->getInternalId()]) + ], $dbForProject, function ($function) use ($dbForProject, $dbForConsole) { + $dbForConsole->deleteDocument('repositories', $function->getAttribute('repositoryId')); + + $function = $function + ->setAttribute('installationId', '') + ->setAttribute('installationInternalId', '') + ->setAttribute('providerRepositoryId', '') + ->setAttribute('providerBranch', '') + ->setAttribute('providerSilentMode', false) + ->setAttribute('providerRootDirectory', '') + ->setAttribute('repositoryId', '') + ->setAttribute('repositoryInternalId', ''); + $dbForProject->updateDocument('functions', $function->getId(), $function); + }); + } + + protected function deleteRuntimes(?Document $function, Document $project) + { + $executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST')); + + $deleteByFunction = function (Document $function) use ($project, $executor) { + $this->listByGroup( + 'deployments', + [ + Query::equal('resourceInternalId', [$function->getInternalId()]), + Query::equal('resourceType', ['functions']), + ], + $this->getProjectDB($project), + function (Document $deployment) use ($project, $executor) { + $deploymentId = $deployment->getId(); + + try { + $executor->deleteRuntime($project->getId(), $deploymentId); + Console::info("Runtime for deployment {$deploymentId} deleted."); + } catch (Throwable $th) { + Console::warning("Runtime for deployment {$deploymentId} skipped:"); + Console::error('[Error] Type: ' . get_class($th)); + Console::error('[Error] Message: ' . $th->getMessage()); + Console::error('[Error] File: ' . $th->getFile()); + Console::error('[Error] Line: ' . $th->getLine()); + } + } + ); + }; + + if ($function !== null) { + // Delete function runtimes + $deleteByFunction($function); + } else { + // Delete all project runtimes + $this->listByGroup( + 'functions', + [], + $this->getProjectDB($project), + function (Document $function) use ($deleteByFunction) { + $deleteByFunction($function); + } + ); + } + } } diff --git a/app/workers/functions.php b/app/workers/functions.php index 7dec0ce90c..cae3a73cc8 100644 --- a/app/workers/functions.php +++ b/app/workers/functions.php @@ -2,11 +2,12 @@ require_once __DIR__ . '/../worker.php'; -use Appwrite\Event\Usage; +use Domnikl\Statsd\Client; use Utopia\Queue\Message; use Appwrite\Event\Event; use Appwrite\Event\Func; use Appwrite\Messaging\Adapter\Realtime; +use Appwrite\Usage\Stats; use Appwrite\Utopia\Response\Model\Execution; use Executor\Executor; use Utopia\App; @@ -30,11 +31,14 @@ Server::setResource('execute', function () { Log $log, Func $queueForFunctions, Database $dbForProject, - Usage $queueForUsage, + Client $statsd, Document $project, Document $function, string $trigger, string $data = null, + string $path, + string $method, + array $headers, ?Document $user = null, string $jwt = null, string $event = null, @@ -43,7 +47,6 @@ Server::setResource('execute', function () { ) { $user ??= new Document(); $functionId = $function->getId(); - $functionInternalId = $function->getInternalId(); $deploymentId = $function->getAttribute('deployment', ''); $log->addTag('functionId', $functionId); @@ -51,7 +54,6 @@ Server::setResource('execute', function () { /** Check if deployment exists */ $deployment = $dbForProject->getDocument('deployments', $deploymentId); - $deploymentInternalId = $deployment->getInternalId(); if ($deployment->getAttribute('resourceId') !== $functionId) { throw new Exception('Deployment not found. Create deployment before trying to execute a function'); @@ -80,100 +82,146 @@ Server::setResource('execute', function () { $runtime = $runtimes[$function->getAttribute('runtime')]; + $headers['x-appwrite-trigger'] = $trigger; + $headers['x-appwrite-event'] = $event ?? ''; + $headers['x-appwrite-user-id'] = $user->getId() ?? ''; + $headers['x-appwrite-user-jwt'] = $jwt ?? ''; + /** Create execution or update execution status */ $execution = $dbForProject->getDocument('executions', $executionId ?? ''); if ($execution->isEmpty()) { + $headersFiltered = []; + foreach ($headers as $key => $value) { + if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_REQUEST)) { + $headersFiltered[] = [ 'name' => $key, 'value' => $value ]; + } + } + $executionId = ID::unique(); - $execution = $dbForProject->createDocument('executions', new Document([ + $execution = new Document([ '$id' => $executionId, '$permissions' => $user->isEmpty() ? [] : [Permission::read(Role::user($user->getId()))], - 'functionId' => $functionId, - 'functionInternalId' => $functionInternalId, - 'deploymentInternalId' => $deploymentInternalId, - 'deploymentId' => $deploymentId, - 'trigger' => $trigger, - 'status' => 'waiting', - 'statusCode' => 0, - 'response' => '', - 'stderr' => '', + 'functionInternalId' => $function->getInternalId(), + 'functionId' => $function->getId(), + 'deploymentInternalId' => $deployment->getInternalId(), + 'deploymentId' => $deployment->getId(), + 'trigger' => 'http', + 'status' => 'processing', + 'responseStatusCode' => 0, + 'responseHeaders' => [], + 'requestPath' => $path, + 'requestMethod' => $method, + 'requestHeaders' => $headersFiltered, + 'errors' => '', + 'logs' => '', 'duration' => 0.0, - 'search' => implode(' ', [$function->getId(), $executionId]), - ])); + 'search' => implode(' ', [$functionId, $executionId]), + ]); + + if ($function->getAttribute('logging')) { + $execution = $dbForProject->createDocument('executions', $execution); + } // TODO: @Meldiron Trigger executions.create event here if ($execution->isEmpty()) { throw new Exception('Failed to create or read execution'); } - - /** - * Usage - */ - - $queueForUsage - ->addMetric(METRIC_EXECUTIONS, 1) // per project - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1); // per function } - $execution->setAttribute('status', 'processing'); - $execution = $dbForProject->updateDocument('executions', $executionId, $execution); + if ($execution->getAttribute('status') !== 'processing') { + $execution->setAttribute('status', 'processing'); - $vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { + if ($function->getAttribute('logging')) { + $execution = $dbForProject->updateDocument('executions', $executionId, $execution); + } + } + + $durationStart = \microtime(true); + + $vars = []; + + // Shared vars + $varsShared = $project->getAttribute('variables', []); + $vars = \array_merge($vars, \array_reduce($varsShared, function (array $carry, Document $var) { + $carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? ''; + return $carry; + }, [])); + + // Function vars + $vars = \array_merge($vars, array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) { $carry[$var->getAttribute('key')] = $var->getAttribute('value'); return $carry; - }, []); + }, [])); - /** Collect environment variables */ + // Appwrite vars $vars = \array_merge($vars, [ 'APPWRITE_FUNCTION_ID' => $functionId, 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'), 'APPWRITE_FUNCTION_DEPLOYMENT' => $deploymentId, - 'APPWRITE_FUNCTION_TRIGGER' => $trigger, 'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(), 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '', 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '', - 'APPWRITE_FUNCTION_EVENT' => $event ?? '', - 'APPWRITE_FUNCTION_EVENT_DATA' => $eventData ?? '', - 'APPWRITE_FUNCTION_DATA' => $data ?? '', - 'APPWRITE_FUNCTION_USER_ID' => $user->getId() ?? '', - 'APPWRITE_FUNCTION_JWT' => $jwt ?? '', ]); + $body = $eventData ?? ''; + if (empty($body)) { + $body = $data ?? ''; + } + /** Execute function */ try { - $client = new Executor(App::getEnv('_APP_EXECUTOR_HOST')); - $executionResponse = $client->createExecution( + $command = $runtime['startCommand']; + $executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST')); + $executionResponse = $executor->createExecution( projectId: $project->getId(), deploymentId: $deploymentId, - payload: $vars['APPWRITE_FUNCTION_DATA'] ?? '', + body: \strlen($body) > 0 ? $body : null, variables: $vars, timeout: $function->getAttribute('timeout', 0), image: $runtime['image'], - source: $build->getAttribute('outputPath', ''), + source: $build->getAttribute('path', ''), entrypoint: $deployment->getAttribute('entrypoint', ''), + version: $function->getAttribute('version'), + path: $path, + method: $method, + headers: $headers, + runtimeEntrypoint: 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $command . '"' ); + $status = $executionResponse['statusCode'] >= 400 ? 'failed' : 'completed'; + + $headersFiltered = []; + foreach ($executionResponse['headers'] as $key => $value) { + if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) { + $headersFiltered[] = [ 'name' => $key, 'value' => $value ]; + } + } + /** Update execution status */ $execution - ->setAttribute('status', $executionResponse['status']) - ->setAttribute('statusCode', $executionResponse['statusCode']) - ->setAttribute('response', $executionResponse['response']) - ->setAttribute('stdout', $executionResponse['stdout']) - ->setAttribute('stderr', $executionResponse['stderr']) + ->setAttribute('status', $status) + ->setAttribute('responseStatusCode', $executionResponse['statusCode']) + ->setAttribute('responseHeaders', $headersFiltered) + ->setAttribute('logs', $executionResponse['logs']) + ->setAttribute('errors', $executionResponse['errors']) ->setAttribute('duration', $executionResponse['duration']); } catch (\Throwable $th) { - $interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt())); + $durationEnd = \microtime(true); + $execution - ->setAttribute('duration', (float)$interval->format('%s.%f')) + ->setAttribute('duration', $durationEnd - $durationStart) ->setAttribute('status', 'failed') - ->setAttribute('statusCode', $th->getCode()) - ->setAttribute('stderr', $th->getMessage()); + ->setAttribute('responseStatusCode', 500) + ->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode()); $error = $th->getMessage(); $errorCode = $th->getCode(); } - $execution = $dbForProject->updateDocument('executions', $executionId, $execution); + if ($function->getAttribute('logging')) { + $execution = $dbForProject->updateDocument('executions', $executionId, $execution); + } /** Trigger Webhook */ $executionModel = new Execution(); @@ -217,13 +265,24 @@ Server::setResource('execute', function () { roles: $target['roles'] ); - /** Trigger usage queue */ - $queueForUsage - ->setProject($project) - ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000))// per project - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) - ->trigger() - ; + /** Update usage stats */ + if (App::getEnv('_APP_USAGE_STATS', 'enabled') === 'enabled') { + $usage = new Stats($statsd); + $usage + ->setParam('projectId', $project->getId()) + ->setParam('projectInternalId', $project->getInternalId()) + ->setParam('functionId', $function->getId()) // TODO: We should use functionInternalId in usage stats + ->setParam('executions.{scope}.compute', 1) + ->setParam('executionStatus', $execution->getAttribute('status', '')) + ->setParam('executionTime', $execution->getAttribute('duration')) + ->setParam('networkRequestSize', 0) + ->setParam('networkResponseSize', 0) + ->submit(); + } + + if (!empty($error)) { + throw new Exception($error, $errorCode); + } }; }); @@ -231,10 +290,10 @@ $server->job() ->inject('message') ->inject('dbForProject') ->inject('queueForFunctions') - ->inject('queueForUsage') + ->inject('statsd') ->inject('execute') ->inject('log') - ->action(function (Message $message, Database $dbForProject, Func $queueForFunctions, Usage $queueForUsage, callable $execute, Log $log) { + ->action(function (Message $message, Database $dbForProject, Func $queueForFunctions, Client $statsd, callable $execute, Log $log) { $payload = $message->getPayload() ?? []; if (empty($payload)) { @@ -243,7 +302,7 @@ $server->job() $type = $payload['type'] ?? ''; $events = $payload['events'] ?? []; - $data = $payload['data'] ?? ''; + $data = $payload['body'] ?? ''; $eventData = $payload['payload'] ?? ''; $project = new Document($payload['project'] ?? []); $function = new Document($payload['function'] ?? []); @@ -275,26 +334,26 @@ $server->job() continue; } Console::success('Iterating function: ' . $function->getAttribute('name')); - try { - $execute( - log: $log, - queueForUsage: $queueForUsage, - dbForProject: $dbForProject, - project: $project, - function: $function, - queueForFunctions: $queueForFunctions, - trigger: 'event', - event: $events[0], - eventData: \is_string($eventData) ? $eventData : \json_encode($eventData), - user: $user, - data: null, - executionId: null, - jwt: null - ); - Console::success('Triggered function: ' . $events[0]); - } catch (\Throwable $th) { - Console::error("Failed to execute " . $function->getId() . " with error: " . $th->getMessage()); - } + $execute( + statsd: $statsd, + dbForProject: $dbForProject, + project: $project, + function: $function, + queueForFunctions: $queueForFunctions, + trigger: 'event', + event: $events[0], + eventData: \is_string($eventData) ? $eventData : \json_encode($eventData), + user: $user, + data: null, + executionId: null, + jwt: null, + path: '/', + method: 'POST', + headers: [ + 'user-agent' => 'Appwrite/' . APP_VERSION_STABLE + ], + ); + Console::success('Triggered function: ' . $events[0]); } } return; @@ -321,7 +380,10 @@ $server->job() data: $data, user: $user, jwt: $jwt, - queueForUsage: $queueForUsage, + path: $payload['path'], + method: $payload['method'], + headers: $payload['headers'], + statsd: $statsd, ); break; case 'schedule': @@ -338,7 +400,10 @@ $server->job() data: null, user: null, jwt: null, - queueForUsage: $queueForUsage, + path: $payload['path'], + method: $payload['method'], + headers: $payload['headers'], + statsd: $statsd, ); break; } diff --git a/app/workers/mails.php b/app/workers/mails.php index e1ce8307ac..56676b4aed 100644 --- a/app/workers/mails.php +++ b/app/workers/mails.php @@ -1,6 +1,7 @@ args['recipient']; $subject = $this->args['subject']; - $name = $this->args['name']; $body = $this->args['body']; - $from = $this->args['from']; + $variables = $this->args['variables']; + $name = $this->args['name']; - /** @var \PHPMailer\PHPMailer\PHPMailer $mail */ - $mail = empty($smtp) ? $register->get('smtp') : $this->getMailer($smtp); + $body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl'); + + foreach ($variables as $key => $value) { + $body->setParam('{{' . $key . '}}', $value); + } + + $body = $body->render(); + + /** @var PHPMailer $mail */ + $mail = empty($smtp) + ? $register->get('smtp') + : $this->getMailer($smtp); $mail->clearAddresses(); $mail->clearAllRecipients(); @@ -48,12 +58,7 @@ class MailsV1 extends Worker $mail->clearAttachments(); $mail->clearBCCs(); $mail->clearCCs(); - - $mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from)); $mail->addAddress($recipient, $name); - if (isset($smtp['replyTo'])) { - $mail->addReplyTo($smtp['replyTo']); - } $mail->Subject = $subject; $mail->Body = $body; $mail->AltBody = \strip_tags($body); @@ -80,17 +85,17 @@ class MailsV1 extends Worker $mail->SMTPAuth = (!empty($username) && !empty($password)); $mail->Username = $username; $mail->Password = $password; - $mail->SMTPSecure = $smtp['secure'] === 'tls'; + $mail->SMTPSecure = $smtp['secure']; $mail->SMTPAutoTLS = false; $mail->CharSet = 'UTF-8'; - $from = \urldecode($smtp['senderName'] ?? App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')); - $email = $smtp['senderEmail'] ?? App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); + $mail->setFrom($smtp['senderEmail'], $smtp['senderName']); - $mail->setFrom($email, $from); - $mail->addReplyTo($email, $from); + if (!empty($smtp['replyTo'])) { + $mail->addReplyTo($smtp['replyTo'], $smtp['senderName']); + } - $mail->isHTML(true); + $mail->isHTML(); return $mail; } diff --git a/app/workers/migrations.php b/app/workers/migrations.php new file mode 100644 index 0000000000..0f8194acf8 --- /dev/null +++ b/app/workers/migrations.php @@ -0,0 +1,308 @@ +args['type'] ?? ''; + $events = $this->args['events'] ?? []; + $project = new Document($this->args['project'] ?? []); + $user = new Document($this->args['user'] ?? []); + $payload = json_encode($this->args['payload'] ?? []); + + if ($project->getId() === 'console') { + return; + } + + /** + * Handle Event execution. + */ + if (! empty($events)) { + return; + } + + $this->dbForProject = $this->getProjectDB($project); + + $this->processMigration(); + } + + /** + * Process Source + * + * @return Source + * + * @throws \Exception + */ + protected function processSource(string $source, array $credentials): Source + { + switch ($source) { + case Firebase::getName(): + return new Firebase( + json_decode($credentials['serviceAccount'], true), + ); + break; + case Supabase::getName(): + return new Supabase( + $credentials['endpoint'], + $credentials['apiKey'], + $credentials['databaseHost'], + 'postgres', + $credentials['username'], + $credentials['password'], + $credentials['port'], + ); + break; + case NHost::getName(): + return new NHost( + $credentials['subdomain'], + $credentials['region'], + $credentials['adminSecret'], + $credentials['database'], + $credentials['username'], + $credentials['password'], + $credentials['port'], + ); + break; + case Appwrite::getName(): + return new Appwrite($credentials['projectId'], str_starts_with($credentials['endpoint'], 'http://localhost/v1') ? 'http://appwrite/v1' : $credentials['endpoint'], $credentials['apiKey']); + break; + default: + throw new \Exception('Invalid source type'); + break; + } + } + + protected function updateMigrationDocument(Document $migration, Document $project): Document + { + /** Trigger Realtime */ + $allEvents = Event::generateEvents('migrations.[migrationId].update', [ + 'migrationId' => $migration->getId(), + ]); + + $target = Realtime::fromPayload( + event: $allEvents[0], + payload: $migration, + project: $project + ); + + Realtime::send( + projectId: 'console', + payload: $migration->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'], + ); + + Realtime::send( + projectId: $project->getId(), + payload: $migration->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'], + ); + + return $this->dbForProject->updateDocument('migrations', $migration->getId(), $migration); + } + + protected function removeAPIKey(Document $apiKey) + { + $consoleDB = $this->getConsoleDB(); + + $consoleDB->deleteDocument('keys', $apiKey->getId()); + } + + protected function generateAPIKey(Document $project): Document + { + $consoleDB = $this->getConsoleDB(); + $generatedSecret = bin2hex(\random_bytes(128)); + + $key = new Document([ + '$id' => ID::unique(), + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'projectInternalId' => $project->getInternalId(), + 'projectId' => $project->getId(), + 'name' => 'Transfer API Key', + 'scopes' => [ + 'users.read', + 'users.write', + 'teams.read', + 'teams.write', + 'databases.read', + 'databases.write', + 'collections.read', + 'collections.write', + 'documents.read', + 'documents.write', + 'buckets.read', + 'buckets.write', + 'files.read', + 'files.write', + 'functions.read', + 'functions.write', + ], + 'expire' => null, + 'sdks' => [], + 'accessedAt' => null, + 'secret' => $generatedSecret, + ]); + + $consoleDB->createDocument('keys', $key); + $consoleDB->deleteCachedDocument('projects', $project->getId()); + + return $key; + } + + /** + * Process Migration + * + * @return void + */ + protected function processMigration(): void + { + /** + * @var Document $migrationDocument + * @var Transfer $transfer + */ + $migrationDocument = null; + $transfer = null; + $projectDocument = $this->getConsoleDB()->getDocument('projects', $this->args['project']['$id']); + $tempAPIKey = $this->generateAPIKey($projectDocument); + + try { + $migrationDocument = $this->dbForProject->getDocument('migrations', $this->args['migration']['$id']); + $migrationDocument->setAttribute('stage', 'processing'); + $migrationDocument->setAttribute('status', 'processing'); + $this->updateMigrationDocument($migrationDocument, $projectDocument); + + $source = $this->processSource($migrationDocument->getAttribute('source'), $migrationDocument->getAttribute('credentials')); + + $source->report(); + + $destination = new DestinationsAppwrite( + $projectDocument->getId(), + 'http://appwrite/v1', + $tempAPIKey['secret'], + ); + + $transfer = new Transfer( + $source, + $destination + ); + + /** Start Transfer */ + $migrationDocument->setAttribute('stage', 'migrating'); + $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())); + + $this->updateMigrationDocument($migrationDocument, $projectDocument); + }); + + $errors = $transfer->getReport(Resource::STATUS_ERROR); + + if (count($errors) > 0) { + $migrationDocument->setAttribute('status', 'failed'); + $migrationDocument->setAttribute('stage', 'finished'); + + $errorMessages = []; + foreach ($errors as $error) { + $errorMessages[] = "Failed to transfer resource '{$error['id']}:{$error['resource']}' with message '{$error['message']}'"; + } + + $migrationDocument->setAttribute('errors', $errorMessages); + $this->updateMigrationDocument($migrationDocument, $projectDocument); + + return; + } + + $migrationDocument->setAttribute('status', 'completed'); + $migrationDocument->setAttribute('stage', 'finished'); + } catch (\Throwable $th) { + Console::error($th->getMessage()); + + if ($migrationDocument) { + Console::error($th->getMessage()); + Console::error($th->getTraceAsString()); + $migrationDocument->setAttribute('status', 'failed'); + $migrationDocument->setAttribute('stage', 'finished'); + $migrationDocument->setAttribute('errors', [$th->getMessage()]); + + return; + } + + if ($transfer) { + $errors = $transfer->getReport(Resource::STATUS_ERROR); + + if (count($errors) > 0) { + $migrationDocument->setAttribute('status', 'failed'); + $migrationDocument->setAttribute('stage', 'finished'); + $migrationDocument->setAttribute('errors', $errors); + } + } + } finally { + if ($migrationDocument) { + $this->updateMigrationDocument($migrationDocument, $projectDocument); + } + if ($tempAPIKey) { + $this->removeAPIKey($tempAPIKey); + } + } + } + + /** + * Process Verification + * + * @return void + */ + protected function processVerification(): void + { + } + + public function shutdown(): void + { + } +} diff --git a/app/workers/usage.php b/app/workers/usage.php deleted file mode 100644 index 0c9dcbc5aa..0000000000 --- a/app/workers/usage.php +++ /dev/null @@ -1,288 +0,0 @@ -deployments>build || documents>collection>database || buckets>files. - * When we remove a parent document we need to deduct his children aggregation from the project scope. - */ -Server::setResource('reduce', function (Cache $cache, Registry $register, $pools) { - return function ($database, $projectInternalId, Document $document, array &$metrics) use ($pools, $cache, $register): void { - try { - $dbForProject = new Database( - $pools - ->get($database) - ->pop() - ->getResource(), - $cache - ); - - $dbForProject->setNamespace('_' . $projectInternalId); - - switch (true) { - case $document->getCollection() === 'users': // users - $sessions = count($document->getAttribute(METRIC_SESSIONS, 0)); - if (!empty($sessions)) { - $metrics[] = [ - 'key' => METRIC_SESSIONS, - 'value' => ($sessions * -1), - ]; - } - break; - case $document->getCollection() === 'databases': // databases - $collections = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS))); - $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS))); - if (!empty($collections['value'])) { - $metrics[] = [ - 'key' => METRIC_COLLECTIONS, - 'value' => ($collections['value'] * -1), - ]; - } - - if (!empty($documents['value'])) { - $metrics[] = [ - 'key' => METRIC_DOCUMENTS, - 'value' => ($documents['value'] * -1), - ]; - } - break; - case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections - $parts = explode('_', $document->getCollection()); - $databaseInternalId = $parts[1] ?? 0; - $documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $document->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS))); - - if (!empty($documents['value'])) { - $metrics[] = [ - 'key' => METRIC_DOCUMENTS, - 'value' => ($documents['value'] * -1), - ]; - $metrics[] = [ - 'key' => str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_DOCUMENTS), - 'value' => ($documents['value'] * -1), - ]; - } - break; - - case $document->getCollection() === 'buckets': - $files = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES))); - $storage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE))); - - if (!empty($files['value'])) { - $metrics[] = [ - 'key' => METRIC_FILES, - 'value' => ($files['value'] * -1), - ]; - } - - if (!empty($storage['value'])) { - $metrics[] = [ - 'key' => METRIC_FILES_STORAGE, - 'value' => ($storage['value'] * -1), - ]; - } - break; - - case $document->getCollection() === 'functions': - $deployments = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS))); - $deploymentsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE))); - $builds = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS))); - $buildsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE))); - $buildsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE))); - $executions = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS))); - $executionsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE))); - - if (!empty($deployments['value'])) { - $metrics[] = [ - 'key' => METRIC_DEPLOYMENTS, - 'value' => ($deployments['value'] * -1), - ]; - } - - if (!empty($deploymentsStorage['value'])) { - $metrics[] = [ - 'key' => METRIC_DEPLOYMENTS_STORAGE, - 'value' => ($deploymentsStorage['value'] * -1), - ]; - } - - if (!empty($builds['value'])) { - $metrics[] = [ - 'key' => METRIC_BUILDS, - 'value' => ($builds['value'] * -1), - ]; - } - - if (!empty($buildsStorage['value'])) { - $metrics[] = [ - 'key' => METRIC_BUILDS_STORAGE, - 'value' => ($buildsStorage['value'] * -1), - ]; - } - - if (!empty($buildsCompute['value'])) { - $metrics[] = [ - 'key' => METRIC_BUILDS_COMPUTE, - 'value' => ($buildsCompute['value'] * -1), - ]; - } - - if (!empty($executions['value'])) { - $metrics[] = [ - 'key' => METRIC_EXECUTIONS, - 'value' => ($executions['value'] * -1), - ]; - } - - if (!empty($executionsCompute['value'])) { - $metrics[] = [ - 'key' => METRIC_EXECUTIONS_COMPUTE, - 'value' => ($executionsCompute['value'] * -1), - ]; - } - break; - default: - break; - } - } catch (\Exception $e) { - console::error("[reducer] " . " {DateTime::now()} " . " {$projectInternalId} " . " {$e->getMessage()}"); - } finally { - $pools->reclaim(); - } - }; -}, ['cache', 'register', 'pools']); - - -$server->job() - ->inject('message') - ->inject('reduce') - - ->action(function (Message $message, callable $reduce) use (&$stats) { - - $payload = $message->getPayload() ?? []; - $project = new Document($payload['project'] ?? []); - $projectId = $project->getInternalId(); - foreach ($payload['reduce'] ?? [] as $document) { - if (empty($document)) { - continue; - } - - $reduce( - database: $project->getAttribute('database'), - projectInternalId: $project->getInternalId(), - document: new Document($document), - metrics: $payload['metrics'], - ); - } - - $stats[$projectId]['database'] = $project->getAttribute('database'); - foreach ($payload['metrics'] ?? [] as $metric) { - if (!isset($stats[$projectId]['keys'][$metric['key']])) { - $stats[$projectId]['keys'][$metric['key']] = $metric['value']; - continue; - } - $stats[$projectId]['keys'][$metric['key']] += $metric['value']; - } - }); - -$server - ->workerStart() - ->inject('register') - ->inject('cache') - ->inject('pools') - ->action(function ($register, $cache, $pools) use ($periods, &$stats) { - Timer::tick(30000, function () use ($register, $cache, $pools, $periods, &$stats) { - - $offset = count($stats); - $projects = array_slice($stats, 0, $offset, true); - array_splice($stats, 0, $offset); - - foreach ($projects as $projectInternalId => $project) { - try { - $dbForProject = new Database( - $pools - ->get($project['database']) - ->pop() - ->getResource(), - $cache - ); - - $dbForProject->setNamespace('_' . $projectInternalId); - - foreach ($project['keys'] ?? [] as $key => $value) { - if ($value == 0) { - continue; - } - - foreach ($periods as $period => $format) { - $time = 'inf' === $period ? null : date($format, time()); - $id = \md5("{$time}_{$period}_{$key}"); - - try { - $dbForProject->createDocument('stats', new Document([ - '$id' => $id, - 'period' => $period, - 'time' => $time, - 'metric' => $key, - 'value' => $value, - 'region' => App::getEnv('_APP_REGION', 'default'), - ])); - } catch (Duplicate $th) { - if ($value < 0) { - $dbForProject->decreaseDocumentAttribute( - 'stats', - $id, - 'value', - abs($value) - ); - } else { - $dbForProject->increaseDocumentAttribute( - 'stats', - $id, - 'value', - $value - ); - } - } - } - } - if (!empty($project['keys'])) { - $dbForProject->createDocument('statsLogger', new Document([ - 'time' => DateTime::now(), - 'metrics' => $project['keys'], - ])); - } - } catch (\Exception $e) { - $now = DateTime::now(); - console::error("[Error] " . " Time: {$now} " . " projectInternalId: {$projectInternalId}" . " File: {$e->getFile()}" . " Line: {$e->getLine()} " . " message: {$e->getMessage()}"); - } finally { - $pools->reclaim(); - } - } - }); - }); -$server->start(); diff --git a/bin/upgrade b/bin/upgrade new file mode 100755 index 0000000000..ce32b9ca30 --- /dev/null +++ b/bin/upgrade @@ -0,0 +1,3 @@ +#!/bin/sh + +php /usr/src/code/app/cli.php upgrade $@ \ No newline at end of file diff --git a/bin/usage b/bin/usage new file mode 100644 index 0000000000..2709200ae4 --- /dev/null +++ b/bin/usage @@ -0,0 +1,3 @@ +#!/bin/sh + +php /usr/src/code/app/cli.php usage $@ \ No newline at end of file diff --git a/bin/worker-migrations b/bin/worker-migrations new file mode 100644 index 0000000000..54e57001b0 --- /dev/null +++ b/bin/worker-migrations @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ] +then + REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}" +else + REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}" +fi + +INTERVAL=0.1 QUEUE='v1-migrations' APP_INCLUDE='/usr/src/code/app/workers/migrations.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php \ No newline at end of file diff --git a/bin/worker-usage b/bin/worker-usage deleted file mode 100644 index 9d325ac46e..0000000000 --- a/bin/worker-usage +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -QUEUE=v1-usage php /usr/src/code/app/workers/usage.php $@ \ No newline at end of file diff --git a/composer.json b/composer.json index 1edb6d0e1c..fba885f951 100644 --- a/composer.json +++ b/composer.json @@ -41,22 +41,23 @@ "ext-openssl": "*", "ext-zlib": "*", "ext-sockets": "*", + "appwrite/php-runtimes": "0.12.0", "appwrite/php-clamav": "2.0.*", - "appwrite/php-runtimes": "0.11.*", "utopia-php/abuse": "0.31.*", "utopia-php/analytics": "0.10.*", "utopia-php/audit": "0.33.*", "utopia-php/cache": "0.8.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.42.*", - "utopia-php/domains": "1.1.*", + "utopia-php/database": "0.43.*", + "utopia-php/domains": "0.3.*", "utopia-php/dsn": "0.1.*", - "utopia-php/framework": "0.28.*", + "utopia-php/framework": "0.31.0", "utopia-php/image": "0.5.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.3.*", "utopia-php/messaging": "0.1.*", + "utopia-php/migration": "0.3.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.4.*", "utopia-php/pools": "0.4.*", @@ -64,11 +65,13 @@ "utopia-php/queue": "0.5.*", "utopia-php/registry": "0.5.*", "utopia-php/storage": "0.14.*", - "utopia-php/swoole": "0.8.*", + "utopia-php/swoole": "0.5.*", + "utopia-php/vcs": "0.4.*", "utopia-php/websocket": "0.1.*", "resque/php-resque": "1.3.6", "matomo/device-detector": "6.1.*", "dragonmantank/cron-expression": "3.3.2", + "influxdb/influxdb-php": "1.15.2", "phpmailer/phpmailer": "6.8.0", "chillerlan/php-qrcode": "4.3.4", "adhocore/jwt": "1.1.2", @@ -83,7 +86,7 @@ } ], "require-dev": { - "appwrite/sdk-generator": "0.33.*", + "appwrite/sdk-generator": "0.34.*", "ext-fileinfo": "*", "phpunit/phpunit": "9.5.20", "squizlabs/php_codesniffer": "^3.7", @@ -98,4 +101,4 @@ "php": "8.0" } } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index 0e72c867d2..8a3bf6d014 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": "2098172fc4b71eb0d41dcdbfea2f5061", + "content-hash": "bc47430e5cb3430f354b4eee6fd8c9c7", "packages": [ { "name": "adhocore/jwt", @@ -63,6 +63,47 @@ ], "time": "2021-02-20T09:56:44+00:00" }, + { + "name": "appwrite/appwrite", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/appwrite/sdk-for-php.git", + "reference": "2b9e966edf35c4061179ed98ea364698ab30de8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/2b9e966edf35c4061179ed98ea364698ab30de8b", + "reference": "2b9e966edf35c4061179ed98ea364698ab30de8b", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "php": ">=7.1.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "Appwrite\\": "src/Appwrite" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API", + "support": { + "email": "team@appwrite.io", + "issues": "https://github.com/appwrite/sdk-for-php/issues", + "source": "https://github.com/appwrite/sdk-for-php/tree/8.0.0", + "url": "https://appwrite.io/support" + }, + "time": "2023-04-12T10:16:28+00:00" + }, { "name": "appwrite/php-clamav", "version": "2.0.0", @@ -115,15 +156,15 @@ }, { "name": "appwrite/php-runtimes", - "version": "0.11.1", + "version": "0.12.0", "source": { "type": "git", "url": "https://github.com/appwrite/runtimes.git", - "reference": "9d74a477ba3333cbcfac565c46fcf19606b7b603" + "reference": "5aa672ae744be0d7a3d4bf4c93455c65e9a23b4f" }, "require": { "php": ">=8.0", - "utopia-php/system": "0.6.*" + "utopia-php/system": "0.7.*" }, "require-dev": { "phpunit/phpunit": "^9.3", @@ -154,7 +195,7 @@ "php", "runtimes" ], - "time": "2022-11-07T16:45:52+00:00" + "time": "2023-08-07T09:56:11+00:00" }, { "name": "chillerlan/php-qrcode", @@ -479,6 +520,398 @@ ], "time": "2022-09-10T18:51:20+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "7.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1110f66a6530a40fe7aea0378fe608ee2b2248f9", + "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.1", + "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "ext-curl": "*", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.8.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2023-08-27T10:20:53+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d", + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2023-08-03T15:11:55+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-08-27T10:13:57+00:00" + }, + { + "name": "influxdb/influxdb-php", + "version": "1.15.2", + "source": { + "type": "git", + "url": "https://github.com/influxdata/influxdb-php.git", + "reference": "d6e59f4f04ab9107574fda69c2cbe36671253d03" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/influxdata/influxdb-php/zipball/d6e59f4f04ab9107574fda69c2cbe36671253d03", + "reference": "d6e59f4f04ab9107574fda69c2cbe36671253d03", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0|^7.0", + "php": "^5.5 || ^7.0 || ^8.0" + }, + "require-dev": { + "dms/phpunit-arraysubset-asserts": "^0.2.1", + "phpunit/phpunit": "^9.5" + }, + "suggest": { + "ext-curl": "Curl extension, needed for Curl driver", + "stefanotorresi/influxdb-php-async": "An asyncronous client for InfluxDB, implemented via ReactPHP." + }, + "type": "library", + "autoload": { + "psr-4": { + "InfluxDB\\": "src/InfluxDB" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stephen Hoogendijk", + "email": "stephen@tca0.nl" + }, + { + "name": "Daniel Martinez", + "email": "danimartcas@hotmail.com" + }, + { + "name": "Gianluca Arbezzano", + "email": "gianarb92@gmail.com" + } + ], + "description": "InfluxDB client library for PHP", + "keywords": [ + "client", + "influxdata", + "influxdb", + "influxdb class", + "influxdb client", + "influxdb library", + "time series" + ], + "support": { + "issues": "https://github.com/influxdata/influxdb-php/issues", + "source": "https://github.com/influxdata/influxdb-php/tree/1.15.2" + }, + "abandoned": true, + "time": "2020-12-26T17:45:17+00:00" + }, { "name": "jean85/pretty-package-versions", "version": "1.6.0", @@ -686,16 +1119,16 @@ }, { "name": "matomo/device-detector", - "version": "6.1.4", + "version": "6.1.5", "source": { "type": "git", "url": "https://github.com/matomo-org/device-detector.git", - "reference": "74f6c4f6732b3ad6cdf25560746841d522969112" + "reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/74f6c4f6732b3ad6cdf25560746841d522969112", - "reference": "74f6c4f6732b3ad6cdf25560746841d522969112", + "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/40ca2990dba2c1719e5c62168e822e0b86c167d4", + "reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4", "shasum": "" }, "require": { @@ -751,7 +1184,7 @@ "source": "https://github.com/matomo-org/matomo", "wiki": "https://dev.matomo.org/" }, - "time": "2023-08-02T08:48:53+00:00" + "time": "2023-08-17T16:17:41+00:00" }, { "name": "mongodb/mongodb", @@ -951,6 +1384,166 @@ ], "time": "2023-03-06T14:43:22+00:00" }, + { + "name": "psr/http-client", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/1.0.2" + }, + "time": "2023-04-10T20:12:12+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "e616d01114759c4c489f93b099585439f795fe35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + }, + "time": "2023-04-10T20:10:41+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, { "name": "psr/log", "version": "1.1.4", @@ -1001,6 +1594,50 @@ }, "time": "2021-05-03T11:20:27+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "resque/php-resque", "version": "v1.3.6", @@ -1141,17 +1778,84 @@ "time": "2021-06-04T20:33:46+00:00" }, { - "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "name": "symfony/deprecation-contracts", + "version": "v3.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { @@ -1160,7 +1864,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1205,7 +1909,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" }, "funding": [ { @@ -1221,27 +1925,27 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "utopia-php/abuse", - "version": "0.31.0", + "version": "0.31.1", "source": { "type": "git", "url": "https://github.com/utopia-php/abuse.git", - "reference": "d771c2c8d7d1237b1d04b5bf57b07a9b4736e627" + "reference": "b2ad372d1070f55f9545cb811b6ed2d40094e6dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/abuse/zipball/d771c2c8d7d1237b1d04b5bf57b07a9b4736e627", - "reference": "d771c2c8d7d1237b1d04b5bf57b07a9b4736e627", + "url": "https://api.github.com/repos/utopia-php/abuse/zipball/b2ad372d1070f55f9545cb811b6ed2d40094e6dd", + "reference": "b2ad372d1070f55f9545cb811b6ed2d40094e6dd", "shasum": "" }, "require": { "ext-curl": "*", "ext-pdo": "*", "php": ">=8.0", - "utopia-php/database": "0.42.*" + "utopia-php/database": "0.43.*" }, "require-dev": { "laravel/pint": "1.5.*", @@ -1268,9 +1972,9 @@ ], "support": { "issues": "https://github.com/utopia-php/abuse/issues", - "source": "https://github.com/utopia-php/abuse/tree/0.31.0" + "source": "https://github.com/utopia-php/abuse/tree/0.31.1" }, - "time": "2023-08-11T01:17:15+00:00" + "time": "2023-08-29T11:07:46+00:00" }, { "name": "utopia-php/analytics", @@ -1320,21 +2024,21 @@ }, { "name": "utopia-php/audit", - "version": "0.33.0", + "version": "0.33.1", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "6fb82331c58c66cbdb8a419314a687fcb18a1d22" + "reference": "c117e8e9ce4e3e1b369e8b5b55b2d6ab3138eadd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/6fb82331c58c66cbdb8a419314a687fcb18a1d22", - "reference": "6fb82331c58c66cbdb8a419314a687fcb18a1d22", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/c117e8e9ce4e3e1b369e8b5b55b2d6ab3138eadd", + "reference": "c117e8e9ce4e3e1b369e8b5b55b2d6ab3138eadd", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/database": "0.42.*" + "utopia-php/database": "0.43.*" }, "require-dev": { "laravel/pint": "1.5.*", @@ -1361,9 +2065,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/0.33.0" + "source": "https://github.com/utopia-php/audit/tree/0.33.1" }, - "time": "2023-08-11T01:17:28+00:00" + "time": "2023-08-29T11:07:40+00:00" }, { "name": "utopia-php/cache", @@ -1516,19 +2220,20 @@ }, { "name": "utopia-php/database", - "version": "0.42.1", + "version": "0.43.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "9ff69a9b9eadc581771798833d423829c9d8cc90" + "reference": "fb96fc6c94d5efcd43913c34bece62daba76a5e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/9ff69a9b9eadc581771798833d423829c9d8cc90", - "reference": "9ff69a9b9eadc581771798833d423829c9d8cc90", + "url": "https://api.github.com/repos/utopia-php/database/zipball/fb96fc6c94d5efcd43913c34bece62daba76a5e9", + "reference": "fb96fc6c94d5efcd43913c34bece62daba76a5e9", "shasum": "" }, "require": { + "ext-mbstring": "*", "ext-pdo": "*", "php": ">=8.0", "utopia-php/cache": "0.8.*", @@ -1566,29 +2271,31 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.42.1" + "source": "https://github.com/utopia-php/database/tree/0.43.0" }, - "time": "2023-08-14T16:09:09+00:00" + "time": "2023-08-29T10:18:39+00:00" }, { "name": "utopia-php/domains", - "version": "v1.1.0", + "version": "0.3.2", "source": { "type": "git", "url": "https://github.com/utopia-php/domains.git", - "reference": "1665e1d9932afa3be63b5c1e0dcfe01fe77d8e73" + "reference": "aaa8c9a96c69ccb397997b1f4f2299c66f77eefb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/domains/zipball/1665e1d9932afa3be63b5c1e0dcfe01fe77d8e73", - "reference": "1665e1d9932afa3be63b5c1e0dcfe01fe77d8e73", + "url": "https://api.github.com/repos/utopia-php/domains/zipball/aaa8c9a96c69ccb397997b1f4f2299c66f77eefb", + "reference": "aaa8c9a96c69ccb397997b1f4f2299c66f77eefb", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.0", + "utopia-php/framework": "0.*.*" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3" }, "type": "library", "autoload": { @@ -1604,6 +2311,10 @@ { "name": "Eldad Fux", "email": "eldad@appwrite.io" + }, + { + "name": "Wess Cope", + "email": "wess@appwrite.io" } ], "description": "Utopia Domains library is simple and lite library for parsing web domains. This library is aiming to be as simple and easy to learn and use.", @@ -1620,9 +2331,9 @@ ], "support": { "issues": "https://github.com/utopia-php/domains/issues", - "source": "https://github.com/utopia-php/domains/tree/master" + "source": "https://github.com/utopia-php/domains/tree/0.3.2" }, - "time": "2020-02-23T07:40:02+00:00" + "time": "2023-07-19T16:39:24+00:00" }, { "name": "utopia-php/dsn", @@ -1673,16 +2384,16 @@ }, { "name": "utopia-php/framework", - "version": "0.28.4", + "version": "0.31.0", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "98c5469efe195aeecc63745dbf8e2f357f8cedac" + "reference": "207f77378965fca9a9bc3783ea379d3549f86bc0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/98c5469efe195aeecc63745dbf8e2f357f8cedac", - "reference": "98c5469efe195aeecc63745dbf8e2f357f8cedac", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/207f77378965fca9a9bc3783ea379d3549f86bc0", + "reference": "207f77378965fca9a9bc3783ea379d3549f86bc0", "shasum": "" }, "require": { @@ -1690,9 +2401,9 @@ }, "require-dev": { "laravel/pint": "^1.2", - "phpstan/phpstan": "1.9.x-dev", - "phpunit/phpunit": "^9.5.25", - "vimeo/psalm": "4.27.0" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.25" }, "type": "library", "autoload": { @@ -1712,9 +2423,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.28.4" + "source": "https://github.com/utopia-php/framework/tree/0.31.0" }, - "time": "2023-06-03T14:09:22+00:00" + "time": "2023-08-30T16:10:04+00:00" }, { "name": "utopia-php/image", @@ -1920,6 +2631,64 @@ }, "time": "2023-02-07T05:42:46+00:00" }, + { + "name": "utopia-php/migration", + "version": "0.3.2", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/migration.git", + "reference": "49a28adfbb781f0c08f1eaf459a8fbb8ab9fcc70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/49a28adfbb781f0c08f1eaf459a8fbb8ab9fcc70", + "reference": "49a28adfbb781f0c08f1eaf459a8fbb8ab9fcc70", + "shasum": "" + }, + "require": { + "appwrite/appwrite": "^8.0", + "php": ">=8.0", + "utopia-php/cli": "^0.15.0" + }, + "require-dev": { + "laravel/pint": "^1.10", + "phpunit/phpunit": "^9.3", + "vlucas/phpdotenv": "^5.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Migration\\": "src/Migration" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eldad Fux", + "email": "eldad@appwrite.io" + }, + { + "name": "Bradley Schofield", + "email": "bradley@appwrite.io" + } + ], + "description": "A simple library to migrate resources between services.", + "keywords": [ + "framework", + "migration", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/migration/issues", + "source": "https://github.com/utopia-php/migration/tree/0.3.2" + }, + "time": "2023-08-31T04:11:35+00:00" + }, { "name": "utopia-php/mongo", "version": "0.2.0", @@ -2032,16 +2801,16 @@ }, { "name": "utopia-php/platform", - "version": "0.4.0", + "version": "0.4.2", "source": { "type": "git", "url": "https://github.com/utopia-php/platform.git", - "reference": "a2a91940314dc7e23ae0b487be456ca508920e7f" + "reference": "6e3d6db9ee8f99e36c2df331b58de2e6e3e37eb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/platform/zipball/a2a91940314dc7e23ae0b487be456ca508920e7f", - "reference": "a2a91940314dc7e23ae0b487be456ca508920e7f", + "url": "https://api.github.com/repos/utopia-php/platform/zipball/6e3d6db9ee8f99e36c2df331b58de2e6e3e37eb9", + "reference": "6e3d6db9ee8f99e36c2df331b58de2e6e3e37eb9", "shasum": "" }, "require": { @@ -2049,7 +2818,7 @@ "ext-redis": "*", "php": ">=8.0", "utopia-php/cli": "0.15.*", - "utopia-php/framework": "0.28.*" + "utopia-php/framework": "0.31.*" }, "require-dev": { "laravel/pint": "1.2.*", @@ -2075,9 +2844,9 @@ ], "support": { "issues": "https://github.com/utopia-php/platform/issues", - "source": "https://github.com/utopia-php/platform/tree/0.4.0" + "source": "https://github.com/utopia-php/platform/tree/0.4.2" }, - "time": "2023-05-30T07:18:41+00:00" + "time": "2023-08-30T16:28:31+00:00" }, { "name": "utopia-php/pools", @@ -2351,28 +3120,28 @@ }, { "name": "utopia-php/swoole", - "version": "0.8.0", + "version": "0.5.0", "source": { "type": "git", "url": "https://github.com/utopia-php/swoole.git", - "reference": "5b60e7f730641cc182bc36b1f9939d4a76d3439b" + "reference": "c2a3a4f944a2f22945af3cbcb95b13f0769628b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/swoole/zipball/5b60e7f730641cc182bc36b1f9939d4a76d3439b", - "reference": "5b60e7f730641cc182bc36b1f9939d4a76d3439b", + "url": "https://api.github.com/repos/utopia-php/swoole/zipball/c2a3a4f944a2f22945af3cbcb95b13f0769628b1", + "reference": "c2a3a4f944a2f22945af3cbcb95b13f0769628b1", "shasum": "" }, "require": { "ext-swoole": "*", "php": ">=8.0", - "utopia-php/framework": "0.28.*" + "utopia-php/framework": "0.*.*" }, "require-dev": { "laravel/pint": "1.2.*", - "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.3", - "swoole/ide-helper": "5.0.2" + "swoole/ide-helper": "4.8.3", + "vimeo/psalm": "4.15.0" }, "type": "library", "autoload": { @@ -2396,27 +3165,27 @@ ], "support": { "issues": "https://github.com/utopia-php/swoole/issues", - "source": "https://github.com/utopia-php/swoole/tree/0.8.0" + "source": "https://github.com/utopia-php/swoole/tree/0.5.0" }, - "time": "2023-07-25T10:29:58+00:00" + "time": "2022-10-19T22:19:07+00:00" }, { "name": "utopia-php/system", - "version": "0.6.0", + "version": "0.7.1", "source": { "type": "git", "url": "https://github.com/utopia-php/system.git", - "reference": "289c4327713deadc9c748b5317d248133a02f245" + "reference": "01bf0d283aded0ee0a7a6e5ff540acf64270ab27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/system/zipball/289c4327713deadc9c748b5317d248133a02f245", - "reference": "289c4327713deadc9c748b5317d248133a02f245", + "url": "https://api.github.com/repos/utopia-php/system/zipball/01bf0d283aded0ee0a7a6e5ff540acf64270ab27", + "reference": "01bf0d283aded0ee0a7a6e5ff540acf64270ab27", "shasum": "" }, "require": { "laravel/pint": "1.2.*", - "php": ">=7.4" + "php": ">=8.0.0" }, "require-dev": { "phpunit/phpunit": "^9.3", @@ -2453,9 +3222,58 @@ ], "support": { "issues": "https://github.com/utopia-php/system/issues", - "source": "https://github.com/utopia-php/system/tree/0.6.0" + "source": "https://github.com/utopia-php/system/tree/0.7.1" }, - "time": "2022-11-07T13:51:59+00:00" + "time": "2023-08-30T09:14:37+00:00" + }, + { + "name": "utopia-php/vcs", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/vcs.git", + "reference": "08078af30865827adb8aafb32929c968ce541a28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/08078af30865827adb8aafb32929c968ce541a28", + "reference": "08078af30865827adb8aafb32929c968ce541a28", + "shasum": "" + }, + "require": { + "adhocore/jwt": "^1.1", + "php": ">=8.0", + "utopia-php/cache": "^0.8.0", + "utopia-php/framework": "0.31.*" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpstan/phpstan": "1.8.*", + "phpunit/phpunit": "^9.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\VCS\\": "src/VCS", + "Utopia\\Detector\\": "src/Detector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple library to integrate version control systems like GitHub, GitLab etc. to receive webhook events", + "keywords": [ + "framework", + "php", + "utopia", + "vcs" + ], + "support": { + "issues": "https://github.com/utopia-php/vcs/issues", + "source": "https://github.com/utopia-php/vcs/tree/0.4.0" + }, + "time": "2023-08-30T16:17:03+00:00" }, { "name": "utopia-php/websocket", @@ -2642,16 +3460,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.33.7", + "version": "0.34.1", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "9f5db4a637b23879ceacea9ed2d33b0486771ffc" + "reference": "81538d10abacd81350c265b516c72ef315116013" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/9f5db4a637b23879ceacea9ed2d33b0486771ffc", - "reference": "9f5db4a637b23879ceacea9ed2d33b0486771ffc", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/81538d10abacd81350c265b516c72ef315116013", + "reference": "81538d10abacd81350c265b516c72ef315116013", "shasum": "" }, "require": { @@ -2687,9 +3505,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.33.7" + "source": "https://github.com/appwrite/sdk-generator/tree/0.34.1" }, - "time": "2023-07-12T12:15:43+00:00" + "time": "2023-08-30T07:57:31+00:00" }, { "name": "doctrine/deprecations", @@ -4918,16 +5736,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -4942,7 +5760,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4980,7 +5798,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" }, "funding": [ { @@ -4996,20 +5814,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { @@ -5024,7 +5842,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5063,7 +5881,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" }, "funding": [ { @@ -5079,7 +5897,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-07-28T09:04:16+00:00" }, { "name": "textalk/websocket", @@ -5182,16 +6000,16 @@ }, { "name": "twig/twig", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "5cf942bbab3df42afa918caeba947f1b690af64b" + "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/5cf942bbab3df42afa918caeba947f1b690af64b", - "reference": "5cf942bbab3df42afa918caeba947f1b690af64b", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", + "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", "shasum": "" }, "require": { @@ -5201,7 +6019,7 @@ }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" + "symfony/phpunit-bridge": "^5.4.9|^6.3" }, "type": "library", "autoload": { @@ -5237,7 +6055,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.7.0" + "source": "https://github.com/twigphp/Twig/tree/v3.7.1" }, "funding": [ { @@ -5249,7 +6067,7 @@ "type": "tidelift" } ], - "time": "2023-07-26T07:16:09+00:00" + "time": "2023-08-28T11:09:02+00:00" } ], "aliases": [], diff --git a/docker-compose.yml b/docker-compose.yml index 7b37f9fed7..b27c3581af 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,7 +53,6 @@ services: DEBUG: false TESTING: true VERSION: dev - VITE_CONSOLE_MODE: cloud ports: - 9501:80 networks: @@ -97,14 +96,10 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_SERVER_MULTIPROCESS=enabled - _APP_LOCALE - _APP_CONSOLE_WHITELIST_ROOT - _APP_CONSOLE_WHITELIST_EMAILS - - _APP_CONSOLE_WHITELIST_CODES - _APP_CONSOLE_WHITELIST_IPS - - _APP_CONSOLE_INVITES - - _APP_CONSOLE_ROOT_SESSION - _APP_SYSTEM_EMAIL_NAME - _APP_SYSTEM_EMAIL_ADDRESS - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS @@ -114,35 +109,50 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET + - _APP_DOMAIN_FUNCTIONS + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - - _APP_CONNECTIONS_PUBSUB - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE - _APP_SMTP_USERNAME - _APP_SMTP_PASSWORD - - _APP_USERS_STATS_RECIPIENTS - _APP_USAGE_STATS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT - _APP_STORAGE_LIMIT - _APP_STORAGE_PREVIEW_LIMIT - _APP_STORAGE_ANTIVIRUS - _APP_STORAGE_ANTIVIRUS_HOST - _APP_STORAGE_ANTIVIRUS_PORT - - _APP_CONNECTIONS_STORAGE + - _APP_STORAGE_DEVICE + - _APP_STORAGE_S3_ACCESS_KEY + - _APP_STORAGE_S3_SECRET + - _APP_STORAGE_S3_REGION + - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_DO_SPACES_ACCESS_KEY + - _APP_STORAGE_DO_SPACES_SECRET + - _APP_STORAGE_DO_SPACES_REGION + - _APP_STORAGE_DO_SPACES_BUCKET + - _APP_STORAGE_BACKBLAZE_ACCESS_KEY + - _APP_STORAGE_BACKBLAZE_SECRET + - _APP_STORAGE_BACKBLAZE_REGION + - _APP_STORAGE_BACKBLAZE_BUCKET + - _APP_STORAGE_LINODE_ACCESS_KEY + - _APP_STORAGE_LINODE_SECRET + - _APP_STORAGE_LINODE_REGION + - _APP_STORAGE_LINODE_BUCKET + - _APP_STORAGE_WASABI_ACCESS_KEY + - _APP_STORAGE_WASABI_SECRET + - _APP_STORAGE_WASABI_REGION + - _APP_STORAGE_WASABI_BUCKET - _APP_FUNCTIONS_SIZE_LIMIT - _APP_FUNCTIONS_TIMEOUT - _APP_FUNCTIONS_BUILD_TIMEOUT @@ -153,6 +163,8 @@ services: - _APP_EXECUTOR_HOST - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG + - _APP_STATSD_HOST + - _APP_STATSD_PORT - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -161,12 +173,18 @@ services: - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY - _APP_SMS_PROVIDER - _APP_SMS_FROM - - _APP_REGION - _APP_GRAPHQL_MAX_BATCH_SIZE - _APP_GRAPHQL_MAX_COMPLEXITY - _APP_GRAPHQL_MAX_DEPTH - - _APP_CONSOLE_GITHUB_APP_ID - - _APP_CONSOLE_GITHUB_SECRET + - _APP_VCS_GITHUB_APP_NAME + - _APP_VCS_GITHUB_PRIVATE_KEY + - _APP_VCS_GITHUB_APP_ID + - _APP_VCS_GITHUB_WEBHOOK_SECRET + - _APP_VCS_GITHUB_CLIENT_SECRET + - _APP_VCS_GITHUB_CLIENT_ID + - _APP_MIGRATIONS_FIREBASE_CLIENT_ID + - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET + - _APP_ASSISTANT_OPENAI_API_KEY appwrite-realtime: entrypoint: realtime @@ -202,25 +220,17 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_SERVER_MULTIPROCESS=enabled - _APP_OPTIONS_ABUSE - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_PUBSUB - - _APP_CONNECTIONS_QUEUE - _APP_USAGE_STATS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -242,19 +252,15 @@ services: - _APP_ENV - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -275,15 +281,12 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_OPENSSL_KEY_V1 - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -308,23 +311,37 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - - _APP_CONNECTIONS_STORAGE + - _APP_STORAGE_DEVICE + - _APP_STORAGE_S3_ACCESS_KEY + - _APP_STORAGE_S3_SECRET + - _APP_STORAGE_S3_REGION + - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_DO_SPACES_ACCESS_KEY + - _APP_STORAGE_DO_SPACES_SECRET + - _APP_STORAGE_DO_SPACES_REGION + - _APP_STORAGE_DO_SPACES_BUCKET + - _APP_STORAGE_BACKBLAZE_ACCESS_KEY + - _APP_STORAGE_BACKBLAZE_SECRET + - _APP_STORAGE_BACKBLAZE_REGION + - _APP_STORAGE_BACKBLAZE_BUCKET + - _APP_STORAGE_LINODE_ACCESS_KEY + - _APP_STORAGE_LINODE_SECRET + - _APP_STORAGE_LINODE_REGION + - _APP_STORAGE_LINODE_BUCKET + - _APP_STORAGE_WASABI_ACCESS_KEY + - _APP_STORAGE_WASABI_SECRET + - _APP_STORAGE_WASABI_REGION + - _APP_STORAGE_WASABI_BUCKET - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG - _APP_EXECUTOR_SECRET @@ -346,22 +363,16 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -372,7 +383,9 @@ services: image: appwrite-dev networks: - appwrite - volumes: + volumes: + - appwrite-functions:/storage/functions:rw + - appwrite-builds:/storage/builds:rw - ./app:/usr/src/code/app - ./src:/usr/src/code/src depends_on: @@ -381,27 +394,29 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_OPENSSL_KEY_V1 - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - - _APP_CONNECTIONS_STORAGE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG + - _APP_VCS_GITHUB_APP_NAME + - _APP_VCS_GITHUB_PRIVATE_KEY + - _APP_VCS_GITHUB_APP_ID + - _APP_FUNCTIONS_TIMEOUT + - _APP_FUNCTIONS_BUILD_TIMEOUT + - _APP_FUNCTIONS_CPUS + - _APP_FUNCTIONS_MEMORY + - _APP_OPTIONS_FORCE_HTTPS + - _APP_DOMAIN appwrite-worker-certificates: entrypoint: worker-certificates @@ -421,25 +436,20 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET + - _APP_DOMAIN_FUNCTIONS - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -460,23 +470,20 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_FUNCTIONS_TIMEOUT + - _APP_FUNCTIONS_BUILD_TIMEOUT + - _APP_FUNCTIONS_CPUS + - _APP_FUNCTIONS_MEMORY - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST - _APP_USAGE_STATS @@ -502,8 +509,6 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_OPENSSL_KEY_V1 - _APP_SYSTEM_EMAIL_NAME - _APP_SYSTEM_EMAIL_ADDRESS @@ -511,7 +516,6 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_QUEUE - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -536,51 +540,49 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_QUEUE - _APP_SMS_PROVIDER - _APP_SMS_FROM - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG - appwrite-hamster: - entrypoint: hamster + appwrite-worker-migrations: + entrypoint: worker-migrations <<: *x-logging - container_name: appwrite-hamster + container_name: appwrite-worker-migrations + restart: unless-stopped image: appwrite-dev networks: - appwrite volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src + - ./tests:/usr/src/code/tests depends_on: - - redis + - mariadb environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_OPENSSL_KEY_V1 + - _APP_DOMAIN + - _APP_DOMAIN_TARGET + - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_HAMSTER_INTERVAL - - _APP_HAMSTER_TIME - - _APP_MIXPANEL_TOKEN + - _APP_LOGGING_PROVIDER + - _APP_LOGGING_CONFIG + - _APP_MIGRATIONS_FIREBASE_CLIENT_ID + - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET appwrite-maintenance: entrypoint: maintenance @@ -597,62 +599,57 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_DOMAIN - _APP_DOMAIN_TARGET + - _APP_DOMAIN_FUNCTIONS - _APP_OPENSSL_KEY_V1 + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE - _APP_MAINTENANCE_RETENTION_ABUSE - _APP_MAINTENANCE_RETENTION_AUDIT + - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY - _APP_MAINTENANCE_RETENTION_SCHEDULES - appwrite-worker-usage: - entrypoint: worker-usage + appwrite-usage: + entrypoint: usage <<: *x-logging - container_name: appwrite-worker-usage + container_name: appwrite-usage image: appwrite-dev networks: - appwrite volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src + - ./dev:/usr/local/dev depends_on: - - redis + - influxdb - mariadb environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_OPENSSL_KEY_V1 - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT + - _APP_USAGE_AGGREGATION_INTERVAL - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_USAGE_STATS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -673,8 +670,6 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE - - _APP_CONNECTIONS_MAX - - _APP_POOL_CLIENTS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -684,26 +679,21 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - - _APP_REGION appwrite-assistant: container_name: appwrite-assistant - image: appwrite/assistant:0.1.0 + image: appwrite/assistant:0.2.0 networks: - appwrite environment: - - OPENAI_API_KEY + - _APP_ASSISTANT_OPENAI_API_KEY openruntimes-executor: container_name: openruntimes-executor - hostname: exc1 + hostname: executor <<: *x-logging stop_signal: SIGINT - image: openruntimes/executor:0.1.6 + image: openruntimes/executor:0.3.5 networks: - appwrite - runtimes @@ -711,9 +701,10 @@ services: - /var/run/docker.sock:/var/run/docker.sock - appwrite-builds:/storage/builds:rw - appwrite-functions:/storage/functions:rw + # Host mount nessessary to share files between executor and runtimes. + # It's not possible to share mount file between 2 containers without host mount (copying is too slow) - /tmp:/tmp:rw environment: - - OPR_EXECUTOR_CONNECTION_STORAGE=$_APP_CONNECTIONS_STORAGE - OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_FUNCTIONS_INACTIVE_THRESHOLD - OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_FUNCTIONS_MAINTENANCE_INTERVAL - OPR_EXECUTOR_NETWORK=$_APP_FUNCTIONS_RUNTIMES_NETWORK @@ -724,6 +715,49 @@ services: - OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET - OPR_EXECUTOR_LOGGING_PROVIDER=$_APP_LOGGING_PROVIDER - OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG + - OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE + - OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET + - OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION + - OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET + - OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET + - OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION + - OPR_EXECUTOR_STORAGE_DO_SPACES_BUCKET=$_APP_STORAGE_DO_SPACES_BUCKET + - OPR_EXECUTOR_STORAGE_BACKBLAZE_ACCESS_KEY=$_APP_STORAGE_BACKBLAZE_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_BACKBLAZE_SECRET=$_APP_STORAGE_BACKBLAZE_SECRET + - OPR_EXECUTOR_STORAGE_BACKBLAZE_REGION=$_APP_STORAGE_BACKBLAZE_REGION + - OPR_EXECUTOR_STORAGE_BACKBLAZE_BUCKET=$_APP_STORAGE_BACKBLAZE_BUCKET + - OPR_EXECUTOR_STORAGE_LINODE_ACCESS_KEY=$_APP_STORAGE_LINODE_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_LINODE_SECRET=$_APP_STORAGE_LINODE_SECRET + - OPR_EXECUTOR_STORAGE_LINODE_REGION=$_APP_STORAGE_LINODE_REGION + - OPR_EXECUTOR_STORAGE_LINODE_BUCKET=$_APP_STORAGE_LINODE_BUCKET + - OPR_EXECUTOR_STORAGE_WASABI_ACCESS_KEY=$_APP_STORAGE_WASABI_ACCESS_KEY + - OPR_EXECUTOR_STORAGE_WASABI_SECRET=$_APP_STORAGE_WASABI_SECRET + - OPR_EXECUTOR_STORAGE_WASABI_REGION=$_APP_STORAGE_WASABI_REGION + - OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET + + openruntimes-proxy: + container_name: openruntimes-proxy + hostname: proxy + <<: *x-logging + stop_signal: SIGINT + image: openruntimes/proxy:0.3.0 + networks: + - appwrite + - runtimes + environment: + - OPR_PROXY_WORKER_PER_CORE=$_APP_WORKER_PER_CORE + - OPR_PROXY_ENV=$_APP_ENV + - OPR_PROXY_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET + - OPR_PROXY_SECRET=$_APP_EXECUTOR_SECRET + - OPR_PROXY_LOGGING_PROVIDER=$_APP_LOGGING_PROVIDER + - OPR_PROXY_LOGGING_CONFIG=$_APP_LOGGING_CONFIG + - OPR_PROXY_ALGORITHM=random + - OPR_PROXY_EXECUTORS=executor + - OPR_PROXY_HEALTHCHECK_INTERVAL=10000 + - OPR_PROXY_MAX_TIMEOUT=600 + - OPR_PROXY_HEALTHCHECK=enabled mariadb: image: mariadb:10.7 # fix issues when upgrading using: mysql_upgrade -u root -p @@ -740,11 +774,13 @@ services: - MYSQL_DATABASE=${_APP_DB_SCHEMA} - MYSQL_USER=${_APP_DB_USER} - MYSQL_PASSWORD=${_APP_DB_PASS} - command: 'mysqld --innodb-flush-method=fsync --max_connections=${_APP_CONNECTIONS_MAX}' + command: 'mysqld --innodb-flush-method=fsync' # add ' --query_cache_size=0' for DB tests + # command: mv /var/lib/mysql/ib_logfile0 /var/lib/mysql/ib_logfile0.bu && mv /var/lib/mysql/ib_logfile1 /var/lib/mysql/ib_logfile1.bu # smtp: # image: appwrite/smtp:1.2.0 # container_name: appwrite-smtp + # restart: unless-stopped # networks: # - appwrite # environment: @@ -776,6 +812,26 @@ services: # - appwrite # volumes: # - appwrite-uploads:/storage/uploads + + influxdb: + image: appwrite/influxdb:1.5.0 + container_name: appwrite-influxdb + <<: *x-logging + networks: + - appwrite + volumes: + - appwrite-influxdb:/var/lib/influxdb:rw + + telegraf: + image: appwrite/telegraf:1.4.0 + container_name: appwrite-telegraf + <<: *x-logging + networks: + - appwrite + environment: + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT + # Dev Tools Start ------------------------------------------------------------------------------------------ # # The Appwrite Team uses the following tools to help debug, monitor and diagnose the Appwrite stack @@ -786,6 +842,7 @@ services: # RequestCatcher - An HTTP server. Catches all system https calls and displays them using a simple HTTP API. Used to debug & tests webhooks and HTTP tasks # RedisCommander - A nice UI for exploring Redis data # Resque - A nice UI for exploring Redis pub/sub, view the different queues workloads, pending and failed tasks + # Chronograf - A nice UI for exploring InfluxDB data # Webgrind - A nice UI for exploring and debugging code-level stuff maildev: # used mainly for dev tests @@ -810,26 +867,15 @@ services: image: adminer container_name: appwrite-adminer <<: *x-logging + restart: always ports: - 9506:8080 networks: - appwrite - - # appwrite-volume-sync: - # entrypoint: volume-sync - # <<: *x-logging - # container_name: appwrite-volume-sync - # image: appwrite-dev - # command: - # - --source=/data/src/ --destination=/data/dest/ --interval=10 - # networks: - # - appwrite - # # volumes: # Mount the rsync source and destination directories - # # - /nfs/config:/data/src - # # - /storage/config:/data/dest # redis-commander: # image: rediscommander/redis-commander:latest + # restart: unless-stopped # networks: # - appwrite # environment: @@ -839,6 +885,7 @@ services: # resque: # image: appwrite/resque-web:1.1.0 + # restart: unless-stopped # networks: # - appwrite # ports: @@ -848,6 +895,26 @@ services: # - RESQUE_WEB_PORT=6379 # - RESQUE_WEB_HTTP_BASIC_AUTH_USER=user # - RESQUE_WEB_HTTP_BASIC_AUTH_PASSWORD=password + + # chronograf: + # image: chronograf:1.6 + # container_name: appwrite-chronograf + # restart: unless-stopped + # networks: + # - appwrite + # volumes: + # - appwrite-chronograf:/var/lib/chronograf + # ports: + # - "8888:8888" + # environment: + # - INFLUXDB_URL=http://influxdb:8086 + # - KAPACITOR_URL=http://kapacitor:9092 + # - AUTH_DURATION=48h + # - TOKEN_SECRET=duperduper5674829!jwt + # - GH_CLIENT_ID=d86f7145a41eacfc52cc + # - GH_CLIENT_SECRET=9e0081062367a2134e7f2ea95ba1a32d08b6c8ab + # - GH_ORGS=appwrite + # webgrind: # image: 'jokkedk/webgrind:latest' # volumes: @@ -885,4 +952,6 @@ volumes: appwrite-certificates: appwrite-functions: appwrite-builds: + appwrite-influxdb: appwrite-config: + # appwrite-chronograf: diff --git a/docs/examples/1.4.x/client-android/java/account/create-anonymous-session.md b/docs/examples/1.4.x/client-android/java/account/create-anonymous-session.md new file mode 100644 index 0000000000..59c76309e7 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create-anonymous-session.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.createAnonymousSession(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/account/create-email-session.md b/docs/examples/1.4.x/client-android/java/account/create-email-session.md new file mode 100644 index 0000000000..e3e6fdd007 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create-email-session.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.createEmailSession( + "email@example.com", + "password" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/create-j-w-t.md b/docs/examples/1.4.x/client-android/java/account/create-j-w-t.md new file mode 100644 index 0000000000..c312386018 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create-j-w-t.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.createJWT(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/account/create-magic-u-r-l-session.md b/docs/examples/1.4.x/client-android/java/account/create-magic-u-r-l-session.md new file mode 100644 index 0000000000..0ed43dc286 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create-magic-u-r-l-session.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.createMagicURLSession( + "[USER_ID]", + "email@example.com", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/create-o-auth2session.md b/docs/examples/1.4.x/client-android/java/account/create-o-auth2session.md new file mode 100644 index 0000000000..cb9386a848 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create-o-auth2session.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.createOAuth2Session( + "amazon", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/create-phone-session.md b/docs/examples/1.4.x/client-android/java/account/create-phone-session.md new file mode 100644 index 0000000000..df5bc86891 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create-phone-session.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.createPhoneSession( + "[USER_ID]", + "+12065550100" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/create-phone-verification.md b/docs/examples/1.4.x/client-android/java/account/create-phone-verification.md new file mode 100644 index 0000000000..1545d0f82d --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create-phone-verification.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.createPhoneVerification(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/account/create-recovery.md b/docs/examples/1.4.x/client-android/java/account/create-recovery.md new file mode 100644 index 0000000000..5e8584fc35 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create-recovery.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.createRecovery( + "email@example.com", + "https://example.com" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/create-verification.md b/docs/examples/1.4.x/client-android/java/account/create-verification.md new file mode 100644 index 0000000000..fcea98f66c --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create-verification.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.createVerification( + "https://example.com" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/create.md b/docs/examples/1.4.x/client-android/java/account/create.md new file mode 100644 index 0000000000..e08731fd7c --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/create.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.create( + "[USER_ID]", + "email@example.com", + "", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/delete-identity.md b/docs/examples/1.4.x/client-android/java/account/delete-identity.md new file mode 100644 index 0000000000..0d92d04616 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/delete-identity.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.deleteIdentity( + "[IDENTITY_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/delete-session.md b/docs/examples/1.4.x/client-android/java/account/delete-session.md new file mode 100644 index 0000000000..28009d014d --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/delete-session.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.deleteSession( + "[SESSION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/delete-sessions.md b/docs/examples/1.4.x/client-android/java/account/delete-sessions.md new file mode 100644 index 0000000000..6bdc840cff --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/delete-sessions.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.deleteSessions(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/account/get-prefs.md b/docs/examples/1.4.x/client-android/java/account/get-prefs.md new file mode 100644 index 0000000000..9911ad30a4 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/get-prefs.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.getPrefs(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/account/get-session.md b/docs/examples/1.4.x/client-android/java/account/get-session.md new file mode 100644 index 0000000000..fecb543782 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/get-session.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.getSession( + "[SESSION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/get.md b/docs/examples/1.4.x/client-android/java/account/get.md new file mode 100644 index 0000000000..2e5f40ad24 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/get.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.get(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/account/list-identities.md b/docs/examples/1.4.x/client-android/java/account/list-identities.md new file mode 100644 index 0000000000..d1f6a48dee --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/list-identities.md @@ -0,0 +1,20 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.listIdentities( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/list-logs.md b/docs/examples/1.4.x/client-android/java/account/list-logs.md new file mode 100644 index 0000000000..d2ce790bfe --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/list-logs.md @@ -0,0 +1,20 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.listLogs( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/list-sessions.md b/docs/examples/1.4.x/client-android/java/account/list-sessions.md new file mode 100644 index 0000000000..7fd587e1ba --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/list-sessions.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.listSessions(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/account/update-email.md b/docs/examples/1.4.x/client-android/java/account/update-email.md new file mode 100644 index 0000000000..8034ada87d --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-email.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updateEmail( + "email@example.com", + "password" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-magic-u-r-l-session.md b/docs/examples/1.4.x/client-android/java/account/update-magic-u-r-l-session.md new file mode 100644 index 0000000000..0f8f2b3c5c --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-magic-u-r-l-session.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updateMagicURLSession( + "[USER_ID]", + "[SECRET]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-name.md b/docs/examples/1.4.x/client-android/java/account/update-name.md new file mode 100644 index 0000000000..5940f93ef2 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-name.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updateName( + "[NAME]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-password.md b/docs/examples/1.4.x/client-android/java/account/update-password.md new file mode 100644 index 0000000000..d9426322a4 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-password.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updatePassword( + "", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-phone-session.md b/docs/examples/1.4.x/client-android/java/account/update-phone-session.md new file mode 100644 index 0000000000..589e4ff509 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-phone-session.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updatePhoneSession( + "[USER_ID]", + "[SECRET]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-phone-verification.md b/docs/examples/1.4.x/client-android/java/account/update-phone-verification.md new file mode 100644 index 0000000000..81785f97c2 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-phone-verification.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updatePhoneVerification( + "[USER_ID]", + "[SECRET]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-phone.md b/docs/examples/1.4.x/client-android/java/account/update-phone.md new file mode 100644 index 0000000000..a8572f911c --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-phone.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updatePhone( + "+12065550100", + "password" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-prefs.md b/docs/examples/1.4.x/client-android/java/account/update-prefs.md new file mode 100644 index 0000000000..ffd5ef03b5 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-prefs.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updatePrefs( + mapOf( "a" to "b" ) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-recovery.md b/docs/examples/1.4.x/client-android/java/account/update-recovery.md new file mode 100644 index 0000000000..7b0f392176 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-recovery.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updateRecovery( + "[USER_ID]", + "[SECRET]", + "password", + "password" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-session.md b/docs/examples/1.4.x/client-android/java/account/update-session.md new file mode 100644 index 0000000000..27b8f00668 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-session.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updateSession( + "[SESSION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/account/update-status.md b/docs/examples/1.4.x/client-android/java/account/update-status.md new file mode 100644 index 0000000000..1e18ded540 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-status.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updateStatus(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/account/update-verification.md b/docs/examples/1.4.x/client-android/java/account/update-verification.md new file mode 100644 index 0000000000..d852dbf838 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/account/update-verification.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Account account = new Account(client); + +account.updateVerification( + "[USER_ID]", + "[SECRET]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/avatars/get-browser.md b/docs/examples/1.4.x/client-android/java/avatars/get-browser.md new file mode 100644 index 0000000000..f072110236 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/avatars/get-browser.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Avatars avatars = new Avatars(client); + +avatars.getBrowser( + "aa", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/avatars/get-credit-card.md b/docs/examples/1.4.x/client-android/java/avatars/get-credit-card.md new file mode 100644 index 0000000000..0a73312791 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/avatars/get-credit-card.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Avatars avatars = new Avatars(client); + +avatars.getCreditCard( + "amex", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/avatars/get-favicon.md b/docs/examples/1.4.x/client-android/java/avatars/get-favicon.md new file mode 100644 index 0000000000..e0c1cb6b8a --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/avatars/get-favicon.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Avatars avatars = new Avatars(client); + +avatars.getFavicon( + "https://example.com" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/avatars/get-flag.md b/docs/examples/1.4.x/client-android/java/avatars/get-flag.md new file mode 100644 index 0000000000..a5f4790640 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/avatars/get-flag.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Avatars avatars = new Avatars(client); + +avatars.getFlag( + "af", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/avatars/get-image.md b/docs/examples/1.4.x/client-android/java/avatars/get-image.md new file mode 100644 index 0000000000..cdc8ac722b --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/avatars/get-image.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Avatars avatars = new Avatars(client); + +avatars.getImage( + "https://example.com", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/avatars/get-initials.md b/docs/examples/1.4.x/client-android/java/avatars/get-initials.md new file mode 100644 index 0000000000..c02490c734 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/avatars/get-initials.md @@ -0,0 +1,20 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Avatars avatars = new Avatars(client); + +avatars.getInitials( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/avatars/get-q-r.md b/docs/examples/1.4.x/client-android/java/avatars/get-q-r.md new file mode 100644 index 0000000000..2532f204d8 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/avatars/get-q-r.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Avatars avatars = new Avatars(client); + +avatars.getQR( + "[TEXT]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/databases/create-document.md b/docs/examples/1.4.x/client-android/java/databases/create-document.md new file mode 100644 index 0000000000..715e4cdbbe --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/databases/create-document.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Databases databases = new Databases(client); + +databases.createDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[DOCUMENT_ID]", + mapOf( "a" to "b" ), + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/databases/delete-document.md b/docs/examples/1.4.x/client-android/java/databases/delete-document.md new file mode 100644 index 0000000000..1387f48687 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/databases/delete-document.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Databases databases = new Databases(client); + +databases.deleteDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[DOCUMENT_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/databases/get-document.md b/docs/examples/1.4.x/client-android/java/databases/get-document.md new file mode 100644 index 0000000000..b1a7161971 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/databases/get-document.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Databases databases = new Databases(client); + +databases.getDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[DOCUMENT_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/databases/list-documents.md b/docs/examples/1.4.x/client-android/java/databases/list-documents.md new file mode 100644 index 0000000000..62dc2c7e29 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/databases/list-documents.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Databases databases = new Databases(client); + +databases.listDocuments( + "[DATABASE_ID]", + "[COLLECTION_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/databases/update-document.md b/docs/examples/1.4.x/client-android/java/databases/update-document.md new file mode 100644 index 0000000000..d1ed59de3b --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/databases/update-document.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Databases databases = new Databases(client); + +databases.updateDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[DOCUMENT_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/functions/create-execution.md b/docs/examples/1.4.x/client-android/java/functions/create-execution.md new file mode 100644 index 0000000000..3cce1c37be --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/functions/create-execution.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Functions functions = new Functions(client); + +functions.createExecution( + "[FUNCTION_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/functions/get-execution.md b/docs/examples/1.4.x/client-android/java/functions/get-execution.md new file mode 100644 index 0000000000..459d74394f --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/functions/get-execution.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Functions functions = new Functions(client); + +functions.getExecution( + "[FUNCTION_ID]", + "[EXECUTION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/functions/list-executions.md b/docs/examples/1.4.x/client-android/java/functions/list-executions.md new file mode 100644 index 0000000000..c1f982b707 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/functions/list-executions.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Functions functions = new Functions(client); + +functions.listExecutions( + "[FUNCTION_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/graphql/mutation.md b/docs/examples/1.4.x/client-android/java/graphql/mutation.md new file mode 100644 index 0000000000..262e513bed --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/graphql/mutation.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Graphql; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Graphql graphql = new Graphql(client); + +graphql.mutation( + mapOf( "a" to "b" ) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/graphql/query.md b/docs/examples/1.4.x/client-android/java/graphql/query.md new file mode 100644 index 0000000000..4291b4735f --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/graphql/query.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Graphql; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Graphql graphql = new Graphql(client); + +graphql.query( + mapOf( "a" to "b" ) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/locale/get.md b/docs/examples/1.4.x/client-android/java/locale/get.md new file mode 100644 index 0000000000..4d14be6d73 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/locale/get.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Locale locale = new Locale(client); + +locale.get(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/locale/list-codes.md b/docs/examples/1.4.x/client-android/java/locale/list-codes.md new file mode 100644 index 0000000000..599070ef77 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/locale/list-codes.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Locale locale = new Locale(client); + +locale.listCodes(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/locale/list-continents.md b/docs/examples/1.4.x/client-android/java/locale/list-continents.md new file mode 100644 index 0000000000..6abe97a0a0 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/locale/list-continents.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Locale locale = new Locale(client); + +locale.listContinents(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/locale/list-countries-e-u.md b/docs/examples/1.4.x/client-android/java/locale/list-countries-e-u.md new file mode 100644 index 0000000000..3c5ca3ae8c --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/locale/list-countries-e-u.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Locale locale = new Locale(client); + +locale.listCountriesEU(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/locale/list-countries-phones.md b/docs/examples/1.4.x/client-android/java/locale/list-countries-phones.md new file mode 100644 index 0000000000..81ef94d702 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/locale/list-countries-phones.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Locale locale = new Locale(client); + +locale.listCountriesPhones(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/locale/list-countries.md b/docs/examples/1.4.x/client-android/java/locale/list-countries.md new file mode 100644 index 0000000000..dc0d5f52c4 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/locale/list-countries.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Locale locale = new Locale(client); + +locale.listCountries(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/locale/list-currencies.md b/docs/examples/1.4.x/client-android/java/locale/list-currencies.md new file mode 100644 index 0000000000..7a327b38ae --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/locale/list-currencies.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Locale locale = new Locale(client); + +locale.listCurrencies(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/locale/list-languages.md b/docs/examples/1.4.x/client-android/java/locale/list-languages.md new file mode 100644 index 0000000000..0688614b6d --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/locale/list-languages.md @@ -0,0 +1,18 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Locale locale = new Locale(client); + +locale.listLanguages(new CoroutineCallback<>((result, error) -> { + if (error != null) + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); +})); diff --git a/docs/examples/1.4.x/client-android/java/storage/create-file.md b/docs/examples/1.4.x/client-android/java/storage/create-file.md new file mode 100644 index 0000000000..732b302f63 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/storage/create-file.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.models.InputFile; +import io.appwrite.services.Storage; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Storage storage = new Storage(client); + +storage.createFile( + "[BUCKET_ID]", + "[FILE_ID]", + InputFile.fromPath("file.png"), + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/storage/delete-file.md b/docs/examples/1.4.x/client-android/java/storage/delete-file.md new file mode 100644 index 0000000000..69a0f0f844 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/storage/delete-file.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Storage storage = new Storage(client); + +storage.deleteFile( + "[BUCKET_ID]", + "[FILE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/storage/get-file-download.md b/docs/examples/1.4.x/client-android/java/storage/get-file-download.md new file mode 100644 index 0000000000..2ab30dce5a --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/storage/get-file-download.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Storage storage = new Storage(client); + +storage.getFileDownload( + "[BUCKET_ID]", + "[FILE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/storage/get-file-preview.md b/docs/examples/1.4.x/client-android/java/storage/get-file-preview.md new file mode 100644 index 0000000000..483f2fca16 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/storage/get-file-preview.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Storage storage = new Storage(client); + +storage.getFilePreview( + "[BUCKET_ID]", + "[FILE_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/storage/get-file-view.md b/docs/examples/1.4.x/client-android/java/storage/get-file-view.md new file mode 100644 index 0000000000..5614b694a5 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/storage/get-file-view.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Storage storage = new Storage(client); + +storage.getFileView( + "[BUCKET_ID]", + "[FILE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/storage/get-file.md b/docs/examples/1.4.x/client-android/java/storage/get-file.md new file mode 100644 index 0000000000..4ae0de0d9a --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/storage/get-file.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Storage storage = new Storage(client); + +storage.getFile( + "[BUCKET_ID]", + "[FILE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/storage/list-files.md b/docs/examples/1.4.x/client-android/java/storage/list-files.md new file mode 100644 index 0000000000..dedfb6c100 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/storage/list-files.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Storage storage = new Storage(client); + +storage.listFiles( + "[BUCKET_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/storage/update-file.md b/docs/examples/1.4.x/client-android/java/storage/update-file.md new file mode 100644 index 0000000000..9b4dd92266 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/storage/update-file.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Storage storage = new Storage(client); + +storage.updateFile( + "[BUCKET_ID]", + "[FILE_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/create-membership.md b/docs/examples/1.4.x/client-android/java/teams/create-membership.md new file mode 100644 index 0000000000..6c8b383358 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/create-membership.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.createMembership( + "[TEAM_ID]", + listOf(), + "https://example.com", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/create.md b/docs/examples/1.4.x/client-android/java/teams/create.md new file mode 100644 index 0000000000..263fa57be7 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/create.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.create( + "[TEAM_ID]", + "[NAME]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/delete-membership.md b/docs/examples/1.4.x/client-android/java/teams/delete-membership.md new file mode 100644 index 0000000000..40f28f0c21 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/delete-membership.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.deleteMembership( + "[TEAM_ID]", + "[MEMBERSHIP_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/delete.md b/docs/examples/1.4.x/client-android/java/teams/delete.md new file mode 100644 index 0000000000..5b4c378b5e --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/delete.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.delete( + "[TEAM_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/get-membership.md b/docs/examples/1.4.x/client-android/java/teams/get-membership.md new file mode 100644 index 0000000000..f2f1d99ae0 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/get-membership.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.getMembership( + "[TEAM_ID]", + "[MEMBERSHIP_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/get-prefs.md b/docs/examples/1.4.x/client-android/java/teams/get-prefs.md new file mode 100644 index 0000000000..6963cb40ca --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/get-prefs.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.getPrefs( + "[TEAM_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/get.md b/docs/examples/1.4.x/client-android/java/teams/get.md new file mode 100644 index 0000000000..549af20d34 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/get.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.get( + "[TEAM_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/list-memberships.md b/docs/examples/1.4.x/client-android/java/teams/list-memberships.md new file mode 100644 index 0000000000..3da4e33d51 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/list-memberships.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.listMemberships( + "[TEAM_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/list.md b/docs/examples/1.4.x/client-android/java/teams/list.md new file mode 100644 index 0000000000..b20ad4a211 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/list.md @@ -0,0 +1,20 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.list( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/update-membership-status.md b/docs/examples/1.4.x/client-android/java/teams/update-membership-status.md new file mode 100644 index 0000000000..499251f21f --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/update-membership-status.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.updateMembershipStatus( + "[TEAM_ID]", + "[MEMBERSHIP_ID]", + "[USER_ID]", + "[SECRET]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/update-membership.md b/docs/examples/1.4.x/client-android/java/teams/update-membership.md new file mode 100644 index 0000000000..6cb334603a --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/update-membership.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.updateMembership( + "[TEAM_ID]", + "[MEMBERSHIP_ID]", + listOf() + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/update-name.md b/docs/examples/1.4.x/client-android/java/teams/update-name.md new file mode 100644 index 0000000000..170ee59015 --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/update-name.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.updateName( + "[TEAM_ID]", + "[NAME]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/java/teams/update-prefs.md b/docs/examples/1.4.x/client-android/java/teams/update-prefs.md new file mode 100644 index 0000000000..a19ad8207e --- /dev/null +++ b/docs/examples/1.4.x/client-android/java/teams/update-prefs.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2"); // Your project ID + +Teams teams = new Teams(client); + +teams.updatePrefs( + "[TEAM_ID]", + mapOf( "a" to "b" ) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create-anonymous-session.md b/docs/examples/1.4.x/client-android/kotlin/account/create-anonymous-session.md new file mode 100644 index 0000000000..cdcf401ed9 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create-anonymous-session.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.createAnonymousSession() diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create-email-session.md b/docs/examples/1.4.x/client-android/kotlin/account/create-email-session.md new file mode 100644 index 0000000000..ab8d581fd1 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create-email-session.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.createEmailSession( + email = "email@example.com", + password = "password" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create-j-w-t.md b/docs/examples/1.4.x/client-android/kotlin/account/create-j-w-t.md new file mode 100644 index 0000000000..35e7a6ffd4 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create-j-w-t.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.createJWT() diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create-magic-u-r-l-session.md b/docs/examples/1.4.x/client-android/kotlin/account/create-magic-u-r-l-session.md new file mode 100644 index 0000000000..51368b5392 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create-magic-u-r-l-session.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.createMagicURLSession( + userId = "[USER_ID]", + email = "email@example.com", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create-o-auth2session.md b/docs/examples/1.4.x/client-android/kotlin/account/create-o-auth2session.md new file mode 100644 index 0000000000..395bfada00 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create-o-auth2session.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +account.createOAuth2Session( + provider = "amazon", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create-phone-session.md b/docs/examples/1.4.x/client-android/kotlin/account/create-phone-session.md new file mode 100644 index 0000000000..eed6f7a2e2 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create-phone-session.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.createPhoneSession( + userId = "[USER_ID]", + phone = "+12065550100" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create-phone-verification.md b/docs/examples/1.4.x/client-android/kotlin/account/create-phone-verification.md new file mode 100644 index 0000000000..12fb9f74e8 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create-phone-verification.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.createPhoneVerification() diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create-recovery.md b/docs/examples/1.4.x/client-android/kotlin/account/create-recovery.md new file mode 100644 index 0000000000..7d73a671dd --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create-recovery.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.createRecovery( + email = "email@example.com", + url = "https://example.com" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create-verification.md b/docs/examples/1.4.x/client-android/kotlin/account/create-verification.md new file mode 100644 index 0000000000..b3dc43ac48 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create-verification.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.createVerification( + url = "https://example.com" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/create.md b/docs/examples/1.4.x/client-android/kotlin/account/create.md new file mode 100644 index 0000000000..c72ae90def --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/create.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.create( + userId = "[USER_ID]", + email = "email@example.com", + password = "", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/delete-identity.md b/docs/examples/1.4.x/client-android/kotlin/account/delete-identity.md new file mode 100644 index 0000000000..440333e1cb --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/delete-identity.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.deleteIdentity( + identityId = "[IDENTITY_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/delete-session.md b/docs/examples/1.4.x/client-android/kotlin/account/delete-session.md new file mode 100644 index 0000000000..a98a28661b --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/delete-session.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.deleteSession( + sessionId = "[SESSION_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/delete-sessions.md b/docs/examples/1.4.x/client-android/kotlin/account/delete-sessions.md new file mode 100644 index 0000000000..c9afbf1345 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/delete-sessions.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.deleteSessions() diff --git a/docs/examples/1.4.x/client-android/kotlin/account/get-prefs.md b/docs/examples/1.4.x/client-android/kotlin/account/get-prefs.md new file mode 100644 index 0000000000..bd3f81a23f --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/get-prefs.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.getPrefs() diff --git a/docs/examples/1.4.x/client-android/kotlin/account/get-session.md b/docs/examples/1.4.x/client-android/kotlin/account/get-session.md new file mode 100644 index 0000000000..d6d6c72eac --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/get-session.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.getSession( + sessionId = "[SESSION_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/get.md b/docs/examples/1.4.x/client-android/kotlin/account/get.md new file mode 100644 index 0000000000..4c8f0be9de --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/get.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.get() diff --git a/docs/examples/1.4.x/client-android/kotlin/account/list-identities.md b/docs/examples/1.4.x/client-android/kotlin/account/list-identities.md new file mode 100644 index 0000000000..3292b35ff1 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/list-identities.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.listIdentities( +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/list-logs.md b/docs/examples/1.4.x/client-android/kotlin/account/list-logs.md new file mode 100644 index 0000000000..eb337caec0 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/list-logs.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.listLogs( +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/list-sessions.md b/docs/examples/1.4.x/client-android/kotlin/account/list-sessions.md new file mode 100644 index 0000000000..cd9f63bc3c --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/list-sessions.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.listSessions() diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-email.md b/docs/examples/1.4.x/client-android/kotlin/account/update-email.md new file mode 100644 index 0000000000..85a0242591 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-email.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updateEmail( + email = "email@example.com", + password = "password" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-magic-u-r-l-session.md b/docs/examples/1.4.x/client-android/kotlin/account/update-magic-u-r-l-session.md new file mode 100644 index 0000000000..c7286ba6c8 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-magic-u-r-l-session.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updateMagicURLSession( + userId = "[USER_ID]", + secret = "[SECRET]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-name.md b/docs/examples/1.4.x/client-android/kotlin/account/update-name.md new file mode 100644 index 0000000000..574f4938d8 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-name.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updateName( + name = "[NAME]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-password.md b/docs/examples/1.4.x/client-android/kotlin/account/update-password.md new file mode 100644 index 0000000000..c5338b8694 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-password.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updatePassword( + password = "", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-phone-session.md b/docs/examples/1.4.x/client-android/kotlin/account/update-phone-session.md new file mode 100644 index 0000000000..d3b02e04ce --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-phone-session.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updatePhoneSession( + userId = "[USER_ID]", + secret = "[SECRET]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-phone-verification.md b/docs/examples/1.4.x/client-android/kotlin/account/update-phone-verification.md new file mode 100644 index 0000000000..0314f74223 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-phone-verification.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updatePhoneVerification( + userId = "[USER_ID]", + secret = "[SECRET]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-phone.md b/docs/examples/1.4.x/client-android/kotlin/account/update-phone.md new file mode 100644 index 0000000000..76eb8aac5e --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-phone.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updatePhone( + phone = "+12065550100", + password = "password" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-prefs.md b/docs/examples/1.4.x/client-android/kotlin/account/update-prefs.md new file mode 100644 index 0000000000..f16e40ba41 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-prefs.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updatePrefs( + prefs = mapOf( "a" to "b" ) +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-recovery.md b/docs/examples/1.4.x/client-android/kotlin/account/update-recovery.md new file mode 100644 index 0000000000..9682899bcb --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-recovery.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updateRecovery( + userId = "[USER_ID]", + secret = "[SECRET]", + password = "password", + passwordAgain = "password" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-session.md b/docs/examples/1.4.x/client-android/kotlin/account/update-session.md new file mode 100644 index 0000000000..e9e83d0cb0 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-session.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updateSession( + sessionId = "[SESSION_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-status.md b/docs/examples/1.4.x/client-android/kotlin/account/update-status.md new file mode 100644 index 0000000000..f7789ea237 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-status.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updateStatus() diff --git a/docs/examples/1.4.x/client-android/kotlin/account/update-verification.md b/docs/examples/1.4.x/client-android/kotlin/account/update-verification.md new file mode 100644 index 0000000000..af800c1fc5 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/account/update-verification.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val account = Account(client) + +val response = account.updateVerification( + userId = "[USER_ID]", + secret = "[SECRET]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/avatars/get-browser.md b/docs/examples/1.4.x/client-android/kotlin/avatars/get-browser.md new file mode 100644 index 0000000000..b1b2d08183 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/avatars/get-browser.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val avatars = Avatars(client) + +val result = avatars.getBrowser( + code = "aa", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/avatars/get-credit-card.md b/docs/examples/1.4.x/client-android/kotlin/avatars/get-credit-card.md new file mode 100644 index 0000000000..411e05ae51 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/avatars/get-credit-card.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val avatars = Avatars(client) + +val result = avatars.getCreditCard( + code = "amex", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/avatars/get-favicon.md b/docs/examples/1.4.x/client-android/kotlin/avatars/get-favicon.md new file mode 100644 index 0000000000..1a4b217fa4 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/avatars/get-favicon.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val avatars = Avatars(client) + +val result = avatars.getFavicon( + url = "https://example.com" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/avatars/get-flag.md b/docs/examples/1.4.x/client-android/kotlin/avatars/get-flag.md new file mode 100644 index 0000000000..5c882d6018 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/avatars/get-flag.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val avatars = Avatars(client) + +val result = avatars.getFlag( + code = "af", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/avatars/get-image.md b/docs/examples/1.4.x/client-android/kotlin/avatars/get-image.md new file mode 100644 index 0000000000..20d8dff13c --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/avatars/get-image.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val avatars = Avatars(client) + +val result = avatars.getImage( + url = "https://example.com", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/avatars/get-initials.md b/docs/examples/1.4.x/client-android/kotlin/avatars/get-initials.md new file mode 100644 index 0000000000..70ef9b2909 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/avatars/get-initials.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val avatars = Avatars(client) + +val result = avatars.getInitials( +) diff --git a/docs/examples/1.4.x/client-android/kotlin/avatars/get-q-r.md b/docs/examples/1.4.x/client-android/kotlin/avatars/get-q-r.md new file mode 100644 index 0000000000..92b17e1163 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/avatars/get-q-r.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val avatars = Avatars(client) + +val result = avatars.getQR( + text = "[TEXT]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/databases/create-document.md b/docs/examples/1.4.x/client-android/kotlin/databases/create-document.md new file mode 100644 index 0000000000..d7f1991d39 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/databases/create-document.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val databases = Databases(client) + +val response = databases.createDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = "[DOCUMENT_ID]", + data = mapOf( "a" to "b" ), +) diff --git a/docs/examples/1.4.x/client-android/kotlin/databases/delete-document.md b/docs/examples/1.4.x/client-android/kotlin/databases/delete-document.md new file mode 100644 index 0000000000..c5bf2a2707 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/databases/delete-document.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val databases = Databases(client) + +val response = databases.deleteDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = "[DOCUMENT_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/databases/get-document.md b/docs/examples/1.4.x/client-android/kotlin/databases/get-document.md new file mode 100644 index 0000000000..abdee36316 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/databases/get-document.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val databases = Databases(client) + +val response = databases.getDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = "[DOCUMENT_ID]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/databases/list-documents.md b/docs/examples/1.4.x/client-android/kotlin/databases/list-documents.md new file mode 100644 index 0000000000..f97d8787c9 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/databases/list-documents.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val databases = Databases(client) + +val response = databases.listDocuments( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/databases/update-document.md b/docs/examples/1.4.x/client-android/kotlin/databases/update-document.md new file mode 100644 index 0000000000..3820b8965c --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/databases/update-document.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val databases = Databases(client) + +val response = databases.updateDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = "[DOCUMENT_ID]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/functions/create-execution.md b/docs/examples/1.4.x/client-android/kotlin/functions/create-execution.md new file mode 100644 index 0000000000..77d4587755 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/functions/create-execution.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val functions = Functions(client) + +val response = functions.createExecution( + functionId = "[FUNCTION_ID]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/functions/get-execution.md b/docs/examples/1.4.x/client-android/kotlin/functions/get-execution.md new file mode 100644 index 0000000000..b57668679f --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/functions/get-execution.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val functions = Functions(client) + +val response = functions.getExecution( + functionId = "[FUNCTION_ID]", + executionId = "[EXECUTION_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/functions/list-executions.md b/docs/examples/1.4.x/client-android/kotlin/functions/list-executions.md new file mode 100644 index 0000000000..14b613f703 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/functions/list-executions.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val functions = Functions(client) + +val response = functions.listExecutions( + functionId = "[FUNCTION_ID]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/graphql/mutation.md b/docs/examples/1.4.x/client-android/kotlin/graphql/mutation.md new file mode 100644 index 0000000000..dc37a3e640 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/graphql/mutation.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Graphql + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val graphql = Graphql(client) + +val response = graphql.mutation( + query = mapOf( "a" to "b" ) +) diff --git a/docs/examples/1.4.x/client-android/kotlin/graphql/query.md b/docs/examples/1.4.x/client-android/kotlin/graphql/query.md new file mode 100644 index 0000000000..d821070922 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/graphql/query.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Graphql + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val graphql = Graphql(client) + +val response = graphql.query( + query = mapOf( "a" to "b" ) +) diff --git a/docs/examples/1.4.x/client-android/kotlin/locale/get.md b/docs/examples/1.4.x/client-android/kotlin/locale/get.md new file mode 100644 index 0000000000..a2044c7257 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/locale/get.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val locale = Locale(client) + +val response = locale.get() diff --git a/docs/examples/1.4.x/client-android/kotlin/locale/list-codes.md b/docs/examples/1.4.x/client-android/kotlin/locale/list-codes.md new file mode 100644 index 0000000000..b4e949bb0d --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/locale/list-codes.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val locale = Locale(client) + +val response = locale.listCodes() diff --git a/docs/examples/1.4.x/client-android/kotlin/locale/list-continents.md b/docs/examples/1.4.x/client-android/kotlin/locale/list-continents.md new file mode 100644 index 0000000000..610747ee13 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/locale/list-continents.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val locale = Locale(client) + +val response = locale.listContinents() diff --git a/docs/examples/1.4.x/client-android/kotlin/locale/list-countries-e-u.md b/docs/examples/1.4.x/client-android/kotlin/locale/list-countries-e-u.md new file mode 100644 index 0000000000..fa5483f0b0 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/locale/list-countries-e-u.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val locale = Locale(client) + +val response = locale.listCountriesEU() diff --git a/docs/examples/1.4.x/client-android/kotlin/locale/list-countries-phones.md b/docs/examples/1.4.x/client-android/kotlin/locale/list-countries-phones.md new file mode 100644 index 0000000000..6aba463a38 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/locale/list-countries-phones.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val locale = Locale(client) + +val response = locale.listCountriesPhones() diff --git a/docs/examples/1.4.x/client-android/kotlin/locale/list-countries.md b/docs/examples/1.4.x/client-android/kotlin/locale/list-countries.md new file mode 100644 index 0000000000..c58456b0f5 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/locale/list-countries.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val locale = Locale(client) + +val response = locale.listCountries() diff --git a/docs/examples/1.4.x/client-android/kotlin/locale/list-currencies.md b/docs/examples/1.4.x/client-android/kotlin/locale/list-currencies.md new file mode 100644 index 0000000000..2cf064402a --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/locale/list-currencies.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val locale = Locale(client) + +val response = locale.listCurrencies() diff --git a/docs/examples/1.4.x/client-android/kotlin/locale/list-languages.md b/docs/examples/1.4.x/client-android/kotlin/locale/list-languages.md new file mode 100644 index 0000000000..afc00b1e77 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/locale/list-languages.md @@ -0,0 +1,10 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val locale = Locale(client) + +val response = locale.listLanguages() diff --git a/docs/examples/1.4.x/client-android/kotlin/storage/create-file.md b/docs/examples/1.4.x/client-android/kotlin/storage/create-file.md new file mode 100644 index 0000000000..7bb79ac11e --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/storage/create-file.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.models.InputFile +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val storage = Storage(client) + +val response = storage.createFile( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]", + file = InputFile.fromPath("file.png"), +) diff --git a/docs/examples/1.4.x/client-android/kotlin/storage/delete-file.md b/docs/examples/1.4.x/client-android/kotlin/storage/delete-file.md new file mode 100644 index 0000000000..9430d7efe3 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/storage/delete-file.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val storage = Storage(client) + +val response = storage.deleteFile( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/storage/get-file-download.md b/docs/examples/1.4.x/client-android/kotlin/storage/get-file-download.md new file mode 100644 index 0000000000..85bd22c9c1 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/storage/get-file-download.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val storage = Storage(client) + +val result = storage.getFileDownload( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/storage/get-file-preview.md b/docs/examples/1.4.x/client-android/kotlin/storage/get-file-preview.md new file mode 100644 index 0000000000..c5bbdef419 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/storage/get-file-preview.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val storage = Storage(client) + +val result = storage.getFilePreview( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/storage/get-file-view.md b/docs/examples/1.4.x/client-android/kotlin/storage/get-file-view.md new file mode 100644 index 0000000000..7e7589c079 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/storage/get-file-view.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val storage = Storage(client) + +val result = storage.getFileView( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/storage/get-file.md b/docs/examples/1.4.x/client-android/kotlin/storage/get-file.md new file mode 100644 index 0000000000..8fb6e244e8 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/storage/get-file.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val storage = Storage(client) + +val response = storage.getFile( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/storage/list-files.md b/docs/examples/1.4.x/client-android/kotlin/storage/list-files.md new file mode 100644 index 0000000000..191a3cc97c --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/storage/list-files.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val storage = Storage(client) + +val response = storage.listFiles( + bucketId = "[BUCKET_ID]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/storage/update-file.md b/docs/examples/1.4.x/client-android/kotlin/storage/update-file.md new file mode 100644 index 0000000000..005270f3e4 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/storage/update-file.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val storage = Storage(client) + +val response = storage.updateFile( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/create-membership.md b/docs/examples/1.4.x/client-android/kotlin/teams/create-membership.md new file mode 100644 index 0000000000..afc93366be --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/create-membership.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.createMembership( + teamId = "[TEAM_ID]", + roles = listOf(), + url = "https://example.com", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/create.md b/docs/examples/1.4.x/client-android/kotlin/teams/create.md new file mode 100644 index 0000000000..5e70bd8df0 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/create.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.create( + teamId = "[TEAM_ID]", + name = "[NAME]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/delete-membership.md b/docs/examples/1.4.x/client-android/kotlin/teams/delete-membership.md new file mode 100644 index 0000000000..04ef5d3490 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/delete-membership.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.deleteMembership( + teamId = "[TEAM_ID]", + membershipId = "[MEMBERSHIP_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/delete.md b/docs/examples/1.4.x/client-android/kotlin/teams/delete.md new file mode 100644 index 0000000000..7d58960e7c --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/delete.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.delete( + teamId = "[TEAM_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/get-membership.md b/docs/examples/1.4.x/client-android/kotlin/teams/get-membership.md new file mode 100644 index 0000000000..653bd520fa --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/get-membership.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.getMembership( + teamId = "[TEAM_ID]", + membershipId = "[MEMBERSHIP_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/get-prefs.md b/docs/examples/1.4.x/client-android/kotlin/teams/get-prefs.md new file mode 100644 index 0000000000..bfd8f7597f --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/get-prefs.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.getPrefs( + teamId = "[TEAM_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/get.md b/docs/examples/1.4.x/client-android/kotlin/teams/get.md new file mode 100644 index 0000000000..72aea07f30 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/get.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.get( + teamId = "[TEAM_ID]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/list-memberships.md b/docs/examples/1.4.x/client-android/kotlin/teams/list-memberships.md new file mode 100644 index 0000000000..53bd6f3b65 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/list-memberships.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.listMemberships( + teamId = "[TEAM_ID]", +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/list.md b/docs/examples/1.4.x/client-android/kotlin/teams/list.md new file mode 100644 index 0000000000..57c5fe8354 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/list.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.list( +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/update-membership-status.md b/docs/examples/1.4.x/client-android/kotlin/teams/update-membership-status.md new file mode 100644 index 0000000000..33de006871 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/update-membership-status.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.updateMembershipStatus( + teamId = "[TEAM_ID]", + membershipId = "[MEMBERSHIP_ID]", + userId = "[USER_ID]", + secret = "[SECRET]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/update-membership.md b/docs/examples/1.4.x/client-android/kotlin/teams/update-membership.md new file mode 100644 index 0000000000..40005ed365 --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/update-membership.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.updateMembership( + teamId = "[TEAM_ID]", + membershipId = "[MEMBERSHIP_ID]", + roles = listOf() +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/update-name.md b/docs/examples/1.4.x/client-android/kotlin/teams/update-name.md new file mode 100644 index 0000000000..59c681232d --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/update-name.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.updateName( + teamId = "[TEAM_ID]", + name = "[NAME]" +) diff --git a/docs/examples/1.4.x/client-android/kotlin/teams/update-prefs.md b/docs/examples/1.4.x/client-android/kotlin/teams/update-prefs.md new file mode 100644 index 0000000000..6a89ac768d --- /dev/null +++ b/docs/examples/1.4.x/client-android/kotlin/teams/update-prefs.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +val teams = Teams(client) + +val response = teams.updatePrefs( + teamId = "[TEAM_ID]", + prefs = mapOf( "a" to "b" ) +) diff --git a/docs/examples/1.4.x/client-apple/examples/account/create-anonymous-session.md b/docs/examples/1.4.x/client-apple/examples/account/create-anonymous-session.md new file mode 100644 index 0000000000..9904f6f222 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create-anonymous-session.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let session = try await account.createAnonymousSession() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/create-email-session.md b/docs/examples/1.4.x/client-apple/examples/account/create-email-session.md new file mode 100644 index 0000000000..311a3b6260 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create-email-session.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let session = try await account.createEmailSession( + email: "email@example.com", + password: "password" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/create-j-w-t.md b/docs/examples/1.4.x/client-apple/examples/account/create-j-w-t.md new file mode 100644 index 0000000000..c18c3c940a --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create-j-w-t.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let jwt = try await account.createJWT() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/create-magic-u-r-l-session.md b/docs/examples/1.4.x/client-apple/examples/account/create-magic-u-r-l-session.md new file mode 100644 index 0000000000..929396ddc6 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create-magic-u-r-l-session.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let token = try await account.createMagicURLSession( + userId: "[USER_ID]", + email: "email@example.com" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/create-o-auth2session.md b/docs/examples/1.4.x/client-apple/examples/account/create-o-auth2session.md new file mode 100644 index 0000000000..c84edfc6e7 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create-o-auth2session.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let success = try await account.createOAuth2Session( + provider: "amazon" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/create-phone-session.md b/docs/examples/1.4.x/client-apple/examples/account/create-phone-session.md new file mode 100644 index 0000000000..caa66c161a --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create-phone-session.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let token = try await account.createPhoneSession( + userId: "[USER_ID]", + phone: "+12065550100" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/create-phone-verification.md b/docs/examples/1.4.x/client-apple/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..b628897c60 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create-phone-verification.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let token = try await account.createPhoneVerification() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/create-recovery.md b/docs/examples/1.4.x/client-apple/examples/account/create-recovery.md new file mode 100644 index 0000000000..8d48938a87 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create-recovery.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let token = try await account.createRecovery( + email: "email@example.com", + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/create-verification.md b/docs/examples/1.4.x/client-apple/examples/account/create-verification.md new file mode 100644 index 0000000000..2c96d202d0 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create-verification.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let token = try await account.createVerification( + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/create.md b/docs/examples/1.4.x/client-apple/examples/account/create.md new file mode 100644 index 0000000000..a7836f8e37 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/create.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let user = try await account.create( + userId: "[USER_ID]", + email: "email@example.com", + password: "" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/delete-identity.md b/docs/examples/1.4.x/client-apple/examples/account/delete-identity.md new file mode 100644 index 0000000000..7cd37c9755 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/delete-identity.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let result = try await account.deleteIdentity( + identityId: "[IDENTITY_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/delete-session.md b/docs/examples/1.4.x/client-apple/examples/account/delete-session.md new file mode 100644 index 0000000000..316a27d8f7 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/delete-session.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let result = try await account.deleteSession( + sessionId: "[SESSION_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/delete-sessions.md b/docs/examples/1.4.x/client-apple/examples/account/delete-sessions.md new file mode 100644 index 0000000000..efb8c7cce1 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/delete-sessions.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let result = try await account.deleteSessions() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/get-prefs.md b/docs/examples/1.4.x/client-apple/examples/account/get-prefs.md new file mode 100644 index 0000000000..5a9fb2e356 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/get-prefs.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let preferences = try await account.getPrefs() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/get-session.md b/docs/examples/1.4.x/client-apple/examples/account/get-session.md new file mode 100644 index 0000000000..66b363574a --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/get-session.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let session = try await account.getSession( + sessionId: "[SESSION_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/get.md b/docs/examples/1.4.x/client-apple/examples/account/get.md new file mode 100644 index 0000000000..f29f83f8e8 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/get.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let user = try await account.get() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/list-identities.md b/docs/examples/1.4.x/client-apple/examples/account/list-identities.md new file mode 100644 index 0000000000..86d713c2d4 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/list-identities.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let identityList = try await account.listIdentities() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/list-logs.md b/docs/examples/1.4.x/client-apple/examples/account/list-logs.md new file mode 100644 index 0000000000..0c9725555e --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/list-logs.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let logList = try await account.listLogs() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/list-sessions.md b/docs/examples/1.4.x/client-apple/examples/account/list-sessions.md new file mode 100644 index 0000000000..b160c89f9c --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/list-sessions.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let sessionList = try await account.listSessions() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-email.md b/docs/examples/1.4.x/client-apple/examples/account/update-email.md new file mode 100644 index 0000000000..a8c37af946 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-email.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let user = try await account.updateEmail( + email: "email@example.com", + password: "password" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-magic-u-r-l-session.md b/docs/examples/1.4.x/client-apple/examples/account/update-magic-u-r-l-session.md new file mode 100644 index 0000000000..42a7f710b5 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-magic-u-r-l-session.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let session = try await account.updateMagicURLSession( + userId: "[USER_ID]", + secret: "[SECRET]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-name.md b/docs/examples/1.4.x/client-apple/examples/account/update-name.md new file mode 100644 index 0000000000..a9d76812b5 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-name.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let user = try await account.updateName( + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-password.md b/docs/examples/1.4.x/client-apple/examples/account/update-password.md new file mode 100644 index 0000000000..bb3c3b0bea --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-password.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let user = try await account.updatePassword( + password: "" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-phone-session.md b/docs/examples/1.4.x/client-apple/examples/account/update-phone-session.md new file mode 100644 index 0000000000..41e26c3935 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-phone-session.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let session = try await account.updatePhoneSession( + userId: "[USER_ID]", + secret: "[SECRET]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-phone-verification.md b/docs/examples/1.4.x/client-apple/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..1c88595dc2 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-phone-verification.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let token = try await account.updatePhoneVerification( + userId: "[USER_ID]", + secret: "[SECRET]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-phone.md b/docs/examples/1.4.x/client-apple/examples/account/update-phone.md new file mode 100644 index 0000000000..306e8f5a93 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-phone.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let user = try await account.updatePhone( + phone: "+12065550100", + password: "password" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-prefs.md b/docs/examples/1.4.x/client-apple/examples/account/update-prefs.md new file mode 100644 index 0000000000..cc765480c5 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-prefs.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let user = try await account.updatePrefs( + prefs: [:] +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-recovery.md b/docs/examples/1.4.x/client-apple/examples/account/update-recovery.md new file mode 100644 index 0000000000..335dd6aeef --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-recovery.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let token = try await account.updateRecovery( + userId: "[USER_ID]", + secret: "[SECRET]", + password: "password", + passwordAgain: "password" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-session.md b/docs/examples/1.4.x/client-apple/examples/account/update-session.md new file mode 100644 index 0000000000..b71826246d --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-session.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let session = try await account.updateSession( + sessionId: "[SESSION_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-status.md b/docs/examples/1.4.x/client-apple/examples/account/update-status.md new file mode 100644 index 0000000000..3f2d823641 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-status.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let user = try await account.updateStatus() + diff --git a/docs/examples/1.4.x/client-apple/examples/account/update-verification.md b/docs/examples/1.4.x/client-apple/examples/account/update-verification.md new file mode 100644 index 0000000000..36af6b99da --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/account/update-verification.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let account = Account(client) + +let token = try await account.updateVerification( + userId: "[USER_ID]", + secret: "[SECRET]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/avatars/get-browser.md b/docs/examples/1.4.x/client-apple/examples/avatars/get-browser.md new file mode 100644 index 0000000000..19c8d02b6d --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/avatars/get-browser.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getBrowser( + code: "aa" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/client-apple/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..d7a680f35e --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/avatars/get-credit-card.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getCreditCard( + code: "amex" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/avatars/get-favicon.md b/docs/examples/1.4.x/client-apple/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..01a7ec1344 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/avatars/get-favicon.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getFavicon( + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/avatars/get-flag.md b/docs/examples/1.4.x/client-apple/examples/avatars/get-flag.md new file mode 100644 index 0000000000..eb33c906b6 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/avatars/get-flag.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getFlag( + code: "af" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/avatars/get-image.md b/docs/examples/1.4.x/client-apple/examples/avatars/get-image.md new file mode 100644 index 0000000000..ef0cd36920 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/avatars/get-image.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getImage( + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/avatars/get-initials.md b/docs/examples/1.4.x/client-apple/examples/avatars/get-initials.md new file mode 100644 index 0000000000..1bdd6f058a --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/avatars/get-initials.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getInitials() + diff --git a/docs/examples/1.4.x/client-apple/examples/avatars/get-q-r.md b/docs/examples/1.4.x/client-apple/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..5c801d40bb --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/avatars/get-q-r.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getQR( + text: "[TEXT]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/databases/create-document.md b/docs/examples/1.4.x/client-apple/examples/databases/create-document.md new file mode 100644 index 0000000000..533bbd534c --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/databases/create-document.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let databases = Databases(client) + +let document = try await databases.createDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]", + data: [:] +) + diff --git a/docs/examples/1.4.x/client-apple/examples/databases/delete-document.md b/docs/examples/1.4.x/client-apple/examples/databases/delete-document.md new file mode 100644 index 0000000000..c9a751294d --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/databases/delete-document.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let databases = Databases(client) + +let result = try await databases.deleteDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/databases/get-document.md b/docs/examples/1.4.x/client-apple/examples/databases/get-document.md new file mode 100644 index 0000000000..53b71fb4f5 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/databases/get-document.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let databases = Databases(client) + +let document = try await databases.getDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/databases/list-documents.md b/docs/examples/1.4.x/client-apple/examples/databases/list-documents.md new file mode 100644 index 0000000000..0b375df67a --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/databases/list-documents.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let databases = Databases(client) + +let documentList = try await databases.listDocuments( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/databases/update-document.md b/docs/examples/1.4.x/client-apple/examples/databases/update-document.md new file mode 100644 index 0000000000..5a943af8c1 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/databases/update-document.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let databases = Databases(client) + +let document = try await databases.updateDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/functions/create-execution.md b/docs/examples/1.4.x/client-apple/examples/functions/create-execution.md new file mode 100644 index 0000000000..93702bfdbc --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/functions/create-execution.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let functions = Functions(client) + +let execution = try await functions.createExecution( + functionId: "[FUNCTION_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/functions/get-execution.md b/docs/examples/1.4.x/client-apple/examples/functions/get-execution.md new file mode 100644 index 0000000000..f1e53cb570 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/functions/get-execution.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let functions = Functions(client) + +let execution = try await functions.getExecution( + functionId: "[FUNCTION_ID]", + executionId: "[EXECUTION_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/functions/list-executions.md b/docs/examples/1.4.x/client-apple/examples/functions/list-executions.md new file mode 100644 index 0000000000..0f182950ee --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/functions/list-executions.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let functions = Functions(client) + +let executionList = try await functions.listExecutions( + functionId: "[FUNCTION_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/graphql/mutation.md b/docs/examples/1.4.x/client-apple/examples/graphql/mutation.md new file mode 100644 index 0000000000..d58b881df4 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/graphql/mutation.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let graphql = Graphql(client) + +let any = try await graphql.mutation( + query: [:] +) + diff --git a/docs/examples/1.4.x/client-apple/examples/graphql/query.md b/docs/examples/1.4.x/client-apple/examples/graphql/query.md new file mode 100644 index 0000000000..0aba98aeb8 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/graphql/query.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let graphql = Graphql(client) + +let any = try await graphql.query( + query: [:] +) + diff --git a/docs/examples/1.4.x/client-apple/examples/locale/get.md b/docs/examples/1.4.x/client-apple/examples/locale/get.md new file mode 100644 index 0000000000..d12470d66a --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/locale/get.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let locale = Locale(client) + +let locale = try await locale.get() + diff --git a/docs/examples/1.4.x/client-apple/examples/locale/list-codes.md b/docs/examples/1.4.x/client-apple/examples/locale/list-codes.md new file mode 100644 index 0000000000..5832aa4ced --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/locale/list-codes.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let locale = Locale(client) + +let localeCodeList = try await locale.listCodes() + diff --git a/docs/examples/1.4.x/client-apple/examples/locale/list-continents.md b/docs/examples/1.4.x/client-apple/examples/locale/list-continents.md new file mode 100644 index 0000000000..4853f77212 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/locale/list-continents.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let locale = Locale(client) + +let continentList = try await locale.listContinents() + diff --git a/docs/examples/1.4.x/client-apple/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/client-apple/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..6e0a4d31d0 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/locale/list-countries-e-u.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let locale = Locale(client) + +let countryList = try await locale.listCountriesEU() + diff --git a/docs/examples/1.4.x/client-apple/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/client-apple/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..b4752eb469 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/locale/list-countries-phones.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let locale = Locale(client) + +let phoneList = try await locale.listCountriesPhones() + diff --git a/docs/examples/1.4.x/client-apple/examples/locale/list-countries.md b/docs/examples/1.4.x/client-apple/examples/locale/list-countries.md new file mode 100644 index 0000000000..75369d0606 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/locale/list-countries.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let locale = Locale(client) + +let countryList = try await locale.listCountries() + diff --git a/docs/examples/1.4.x/client-apple/examples/locale/list-currencies.md b/docs/examples/1.4.x/client-apple/examples/locale/list-currencies.md new file mode 100644 index 0000000000..92eea81275 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/locale/list-currencies.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let locale = Locale(client) + +let currencyList = try await locale.listCurrencies() + diff --git a/docs/examples/1.4.x/client-apple/examples/locale/list-languages.md b/docs/examples/1.4.x/client-apple/examples/locale/list-languages.md new file mode 100644 index 0000000000..2184812b1e --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/locale/list-languages.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let locale = Locale(client) + +let languageList = try await locale.listLanguages() + diff --git a/docs/examples/1.4.x/client-apple/examples/storage/create-file.md b/docs/examples/1.4.x/client-apple/examples/storage/create-file.md new file mode 100644 index 0000000000..f882420882 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/storage/create-file.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let storage = Storage(client) + +let file = try await storage.createFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]", + file: InputFile.fromPath("file.png") +) + diff --git a/docs/examples/1.4.x/client-apple/examples/storage/delete-file.md b/docs/examples/1.4.x/client-apple/examples/storage/delete-file.md new file mode 100644 index 0000000000..27624b4bc2 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/storage/delete-file.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let storage = Storage(client) + +let result = try await storage.deleteFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/storage/get-file-download.md b/docs/examples/1.4.x/client-apple/examples/storage/get-file-download.md new file mode 100644 index 0000000000..ca96b31d93 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/storage/get-file-download.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let storage = Storage(client) + +let byteBuffer = try await storage.getFileDownload( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/storage/get-file-preview.md b/docs/examples/1.4.x/client-apple/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..71c0f31f27 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/storage/get-file-preview.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let storage = Storage(client) + +let byteBuffer = try await storage.getFilePreview( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/storage/get-file-view.md b/docs/examples/1.4.x/client-apple/examples/storage/get-file-view.md new file mode 100644 index 0000000000..85631efc83 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/storage/get-file-view.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let storage = Storage(client) + +let byteBuffer = try await storage.getFileView( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/storage/get-file.md b/docs/examples/1.4.x/client-apple/examples/storage/get-file.md new file mode 100644 index 0000000000..fa28b48d64 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/storage/get-file.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let storage = Storage(client) + +let file = try await storage.getFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/storage/list-files.md b/docs/examples/1.4.x/client-apple/examples/storage/list-files.md new file mode 100644 index 0000000000..51f7fe8f05 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/storage/list-files.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let storage = Storage(client) + +let fileList = try await storage.listFiles( + bucketId: "[BUCKET_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/storage/update-file.md b/docs/examples/1.4.x/client-apple/examples/storage/update-file.md new file mode 100644 index 0000000000..13bf635ec6 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/storage/update-file.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let storage = Storage(client) + +let file = try await storage.updateFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/create-membership.md b/docs/examples/1.4.x/client-apple/examples/teams/create-membership.md new file mode 100644 index 0000000000..1936f9d113 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/create-membership.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let membership = try await teams.createMembership( + teamId: "[TEAM_ID]", + roles: [], + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/create.md b/docs/examples/1.4.x/client-apple/examples/teams/create.md new file mode 100644 index 0000000000..c28eec416d --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/create.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let team = try await teams.create( + teamId: "[TEAM_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/delete-membership.md b/docs/examples/1.4.x/client-apple/examples/teams/delete-membership.md new file mode 100644 index 0000000000..186f6ad6fb --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/delete-membership.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let result = try await teams.deleteMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/delete.md b/docs/examples/1.4.x/client-apple/examples/teams/delete.md new file mode 100644 index 0000000000..e7585ec387 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/delete.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let result = try await teams.delete( + teamId: "[TEAM_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/get-membership.md b/docs/examples/1.4.x/client-apple/examples/teams/get-membership.md new file mode 100644 index 0000000000..02ee3dab42 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/get-membership.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let membership = try await teams.getMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/get-prefs.md b/docs/examples/1.4.x/client-apple/examples/teams/get-prefs.md new file mode 100644 index 0000000000..bcd65b68c4 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/get-prefs.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let preferences = try await teams.getPrefs( + teamId: "[TEAM_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/get.md b/docs/examples/1.4.x/client-apple/examples/teams/get.md new file mode 100644 index 0000000000..c8630adaac --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/get.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let team = try await teams.get( + teamId: "[TEAM_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/list-memberships.md b/docs/examples/1.4.x/client-apple/examples/teams/list-memberships.md new file mode 100644 index 0000000000..1f8a0ccb73 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/list-memberships.md @@ -0,0 +1,12 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let membershipList = try await teams.listMemberships( + teamId: "[TEAM_ID]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/list.md b/docs/examples/1.4.x/client-apple/examples/teams/list.md new file mode 100644 index 0000000000..72226d4f5b --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/list.md @@ -0,0 +1,10 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let teamList = try await teams.list() + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/update-membership-status.md b/docs/examples/1.4.x/client-apple/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..65a899cb1c --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/update-membership-status.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let membership = try await teams.updateMembershipStatus( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + userId: "[USER_ID]", + secret: "[SECRET]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/update-membership.md b/docs/examples/1.4.x/client-apple/examples/teams/update-membership.md new file mode 100644 index 0000000000..1ac7d78f55 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/update-membership.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let membership = try await teams.updateMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + roles: [] +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/update-name.md b/docs/examples/1.4.x/client-apple/examples/teams/update-name.md new file mode 100644 index 0000000000..357182b103 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/update-name.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let team = try await teams.updateName( + teamId: "[TEAM_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/client-apple/examples/teams/update-prefs.md b/docs/examples/1.4.x/client-apple/examples/teams/update-prefs.md new file mode 100644 index 0000000000..6cfe79e3a8 --- /dev/null +++ b/docs/examples/1.4.x/client-apple/examples/teams/update-prefs.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + +let teams = Teams(client) + +let preferences = try await teams.updatePrefs( + teamId: "[TEAM_ID]", + prefs: [:] +) + diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create-anonymous-session.md b/docs/examples/1.4.x/client-flutter/examples/account/create-anonymous-session.md new file mode 100644 index 0000000000..2f3e7a606c --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create-anonymous-session.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createAnonymousSession(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create-email-session.md b/docs/examples/1.4.x/client-flutter/examples/account/create-email-session.md new file mode 100644 index 0000000000..52b6b91f19 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create-email-session.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createEmailSession( + email: 'email@example.com', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create-j-w-t.md b/docs/examples/1.4.x/client-flutter/examples/account/create-j-w-t.md new file mode 100644 index 0000000000..c4a61f7c34 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create-j-w-t.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createJWT(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create-magic-u-r-l-session.md b/docs/examples/1.4.x/client-flutter/examples/account/create-magic-u-r-l-session.md new file mode 100644 index 0000000000..d1b89bf176 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create-magic-u-r-l-session.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createMagicURLSession( + userId: '[USER_ID]', + email: 'email@example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create-o-auth2session.md b/docs/examples/1.4.x/client-flutter/examples/account/create-o-auth2session.md new file mode 100644 index 0000000000..e985a92ae0 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create-o-auth2session.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createOAuth2Session( + provider: 'amazon', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create-phone-session.md b/docs/examples/1.4.x/client-flutter/examples/account/create-phone-session.md new file mode 100644 index 0000000000..fcb705c938 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create-phone-session.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createPhoneSession( + userId: '[USER_ID]', + phone: '+12065550100', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create-phone-verification.md b/docs/examples/1.4.x/client-flutter/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..76e724d829 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create-phone-verification.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createPhoneVerification(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create-recovery.md b/docs/examples/1.4.x/client-flutter/examples/account/create-recovery.md new file mode 100644 index 0000000000..361a9f0459 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create-recovery.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createRecovery( + email: 'email@example.com', + url: 'https://example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create-verification.md b/docs/examples/1.4.x/client-flutter/examples/account/create-verification.md new file mode 100644 index 0000000000..d66c3b1a0a --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create-verification.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createVerification( + url: 'https://example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/create.md b/docs/examples/1.4.x/client-flutter/examples/account/create.md new file mode 100644 index 0000000000..1ff2ae91cb --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/create.md @@ -0,0 +1,23 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.create( + userId: '[USER_ID]', + email: 'email@example.com', + password: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/delete-identity.md b/docs/examples/1.4.x/client-flutter/examples/account/delete-identity.md new file mode 100644 index 0000000000..c5ea2b39f3 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/delete-identity.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.deleteIdentity( + identityId: '[IDENTITY_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/delete-session.md b/docs/examples/1.4.x/client-flutter/examples/account/delete-session.md new file mode 100644 index 0000000000..9146561070 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/delete-session.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.deleteSession( + sessionId: '[SESSION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/delete-sessions.md b/docs/examples/1.4.x/client-flutter/examples/account/delete-sessions.md new file mode 100644 index 0000000000..4963de4442 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/delete-sessions.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.deleteSessions(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/get-prefs.md b/docs/examples/1.4.x/client-flutter/examples/account/get-prefs.md new file mode 100644 index 0000000000..81eb802d03 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/get-prefs.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.getPrefs(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/get-session.md b/docs/examples/1.4.x/client-flutter/examples/account/get-session.md new file mode 100644 index 0000000000..9e0f66ca3f --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/get-session.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.getSession( + sessionId: '[SESSION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/get.md b/docs/examples/1.4.x/client-flutter/examples/account/get.md new file mode 100644 index 0000000000..21192de279 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/get.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.get(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/list-identities.md b/docs/examples/1.4.x/client-flutter/examples/account/list-identities.md new file mode 100644 index 0000000000..2f2eed0da3 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/list-identities.md @@ -0,0 +1,20 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.listIdentities( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/list-logs.md b/docs/examples/1.4.x/client-flutter/examples/account/list-logs.md new file mode 100644 index 0000000000..9f7088a0d8 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/list-logs.md @@ -0,0 +1,20 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.listLogs( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/list-sessions.md b/docs/examples/1.4.x/client-flutter/examples/account/list-sessions.md new file mode 100644 index 0000000000..6f2d5dc18d --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/list-sessions.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.listSessions(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-email.md b/docs/examples/1.4.x/client-flutter/examples/account/update-email.md new file mode 100644 index 0000000000..1fb9a3fe7a --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-email.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updateEmail( + email: 'email@example.com', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-magic-u-r-l-session.md b/docs/examples/1.4.x/client-flutter/examples/account/update-magic-u-r-l-session.md new file mode 100644 index 0000000000..3c7ef8f0f2 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-magic-u-r-l-session.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updateMagicURLSession( + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-name.md b/docs/examples/1.4.x/client-flutter/examples/account/update-name.md new file mode 100644 index 0000000000..ae5d6235d1 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-name.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updateName( + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-password.md b/docs/examples/1.4.x/client-flutter/examples/account/update-password.md new file mode 100644 index 0000000000..b5e86de273 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-password.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updatePassword( + password: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-phone-session.md b/docs/examples/1.4.x/client-flutter/examples/account/update-phone-session.md new file mode 100644 index 0000000000..1f979265b5 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-phone-session.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updatePhoneSession( + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-phone-verification.md b/docs/examples/1.4.x/client-flutter/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..86d9b0fdfc --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-phone-verification.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updatePhoneVerification( + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-phone.md b/docs/examples/1.4.x/client-flutter/examples/account/update-phone.md new file mode 100644 index 0000000000..edfe47850b --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-phone.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updatePhone( + phone: '+12065550100', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-prefs.md b/docs/examples/1.4.x/client-flutter/examples/account/update-prefs.md new file mode 100644 index 0000000000..9769708147 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-prefs.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updatePrefs( + prefs: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-recovery.md b/docs/examples/1.4.x/client-flutter/examples/account/update-recovery.md new file mode 100644 index 0000000000..f499b18770 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-recovery.md @@ -0,0 +1,24 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updateRecovery( + userId: '[USER_ID]', + secret: '[SECRET]', + password: 'password', + passwordAgain: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-session.md b/docs/examples/1.4.x/client-flutter/examples/account/update-session.md new file mode 100644 index 0000000000..fb1afcc526 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-session.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updateSession( + sessionId: '[SESSION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-status.md b/docs/examples/1.4.x/client-flutter/examples/account/update-status.md new file mode 100644 index 0000000000..8e734647fb --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-status.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updateStatus(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/account/update-verification.md b/docs/examples/1.4.x/client-flutter/examples/account/update-verification.md new file mode 100644 index 0000000000..fba8ed65bb --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/account/update-verification.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updateVerification( + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/avatars/get-browser.md b/docs/examples/1.4.x/client-flutter/examples/avatars/get-browser.md new file mode 100644 index 0000000000..70af56659b --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/avatars/get-browser.md @@ -0,0 +1,34 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = avatars.getBrowser( + code: 'aa', + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: avatars.getBrowser( + code: 'aa', + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/client-flutter/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..6a29dc8173 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/avatars/get-credit-card.md @@ -0,0 +1,34 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = avatars.getCreditCard( + code: 'amex', + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: avatars.getCreditCard( + code: 'amex', + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/avatars/get-favicon.md b/docs/examples/1.4.x/client-flutter/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..2da0f2e056 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/avatars/get-favicon.md @@ -0,0 +1,34 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = avatars.getFavicon( + url: 'https://example.com', + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: avatars.getFavicon( + url: 'https://example.com', + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/avatars/get-flag.md b/docs/examples/1.4.x/client-flutter/examples/avatars/get-flag.md new file mode 100644 index 0000000000..13367885d0 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/avatars/get-flag.md @@ -0,0 +1,34 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = avatars.getFlag( + code: 'af', + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: avatars.getFlag( + code: 'af', + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/avatars/get-image.md b/docs/examples/1.4.x/client-flutter/examples/avatars/get-image.md new file mode 100644 index 0000000000..debbf1e290 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/avatars/get-image.md @@ -0,0 +1,34 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = avatars.getImage( + url: 'https://example.com', + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: avatars.getImage( + url: 'https://example.com', + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/avatars/get-initials.md b/docs/examples/1.4.x/client-flutter/examples/avatars/get-initials.md new file mode 100644 index 0000000000..b0f49c6213 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/avatars/get-initials.md @@ -0,0 +1,32 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = avatars.getInitials( + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: avatars.getInitials( + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/avatars/get-q-r.md b/docs/examples/1.4.x/client-flutter/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..8df729379e --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/avatars/get-q-r.md @@ -0,0 +1,34 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = avatars.getQR( + text: '[TEXT]', + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: avatars.getQR( + text: '[TEXT]', + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/databases/create-document.md b/docs/examples/1.4.x/client-flutter/examples/databases/create-document.md new file mode 100644 index 0000000000..6a031738d5 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/databases/create-document.md @@ -0,0 +1,24 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = databases.createDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: '[DOCUMENT_ID]', + data: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/databases/delete-document.md b/docs/examples/1.4.x/client-flutter/examples/databases/delete-document.md new file mode 100644 index 0000000000..a377b02747 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/databases/delete-document.md @@ -0,0 +1,23 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = databases.deleteDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: '[DOCUMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/databases/get-document.md b/docs/examples/1.4.x/client-flutter/examples/databases/get-document.md new file mode 100644 index 0000000000..b2cf89a3fc --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/databases/get-document.md @@ -0,0 +1,23 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = databases.getDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: '[DOCUMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/databases/list-documents.md b/docs/examples/1.4.x/client-flutter/examples/databases/list-documents.md new file mode 100644 index 0000000000..4cd69e301a --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/databases/list-documents.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = databases.listDocuments( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/databases/update-document.md b/docs/examples/1.4.x/client-flutter/examples/databases/update-document.md new file mode 100644 index 0000000000..595099bcb1 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/databases/update-document.md @@ -0,0 +1,23 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = databases.updateDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: '[DOCUMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/functions/create-execution.md b/docs/examples/1.4.x/client-flutter/examples/functions/create-execution.md new file mode 100644 index 0000000000..b188c32f47 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/functions/create-execution.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = functions.createExecution( + functionId: '[FUNCTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/functions/get-execution.md b/docs/examples/1.4.x/client-flutter/examples/functions/get-execution.md new file mode 100644 index 0000000000..f30b4b4495 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/functions/get-execution.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = functions.getExecution( + functionId: '[FUNCTION_ID]', + executionId: '[EXECUTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/functions/list-executions.md b/docs/examples/1.4.x/client-flutter/examples/functions/list-executions.md new file mode 100644 index 0000000000..1840f50d7f --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/functions/list-executions.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = functions.listExecutions( + functionId: '[FUNCTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/graphql/mutation.md b/docs/examples/1.4.x/client-flutter/examples/graphql/mutation.md new file mode 100644 index 0000000000..c0bffce70a --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/graphql/mutation.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Graphql graphql = Graphql(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = graphql.mutation( + query: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/graphql/query.md b/docs/examples/1.4.x/client-flutter/examples/graphql/query.md new file mode 100644 index 0000000000..455cb0bd22 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/graphql/query.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Graphql graphql = Graphql(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = graphql.query( + query: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/locale/get.md b/docs/examples/1.4.x/client-flutter/examples/locale/get.md new file mode 100644 index 0000000000..9e9fa96b22 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/locale/get.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = locale.get(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/locale/list-codes.md b/docs/examples/1.4.x/client-flutter/examples/locale/list-codes.md new file mode 100644 index 0000000000..d11cb7bd35 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/locale/list-codes.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = locale.listCodes(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/locale/list-continents.md b/docs/examples/1.4.x/client-flutter/examples/locale/list-continents.md new file mode 100644 index 0000000000..0ab2a4aba1 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/locale/list-continents.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = locale.listContinents(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/client-flutter/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..caa32e8562 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/locale/list-countries-e-u.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = locale.listCountriesEU(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/client-flutter/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..b122eee7d4 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/locale/list-countries-phones.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = locale.listCountriesPhones(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/locale/list-countries.md b/docs/examples/1.4.x/client-flutter/examples/locale/list-countries.md new file mode 100644 index 0000000000..e6a367ddb8 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/locale/list-countries.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = locale.listCountries(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/locale/list-currencies.md b/docs/examples/1.4.x/client-flutter/examples/locale/list-currencies.md new file mode 100644 index 0000000000..fcd1e825e3 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/locale/list-currencies.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = locale.listCurrencies(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/locale/list-languages.md b/docs/examples/1.4.x/client-flutter/examples/locale/list-languages.md new file mode 100644 index 0000000000..1fb68aa84f --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/locale/list-languages.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = locale.listLanguages(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/storage/create-file.md b/docs/examples/1.4.x/client-flutter/examples/storage/create-file.md new file mode 100644 index 0000000000..0f5e44f5e8 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/storage/create-file.md @@ -0,0 +1,24 @@ +import 'dart:io'; +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = storage.createFile( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + file: InputFile(path: './path-to-files/image.jpg', filename: 'image.jpg'), + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/storage/delete-file.md b/docs/examples/1.4.x/client-flutter/examples/storage/delete-file.md new file mode 100644 index 0000000000..230b73a9ac --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/storage/delete-file.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = storage.deleteFile( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/storage/get-file-download.md b/docs/examples/1.4.x/client-flutter/examples/storage/get-file-download.md new file mode 100644 index 0000000000..883b7d69c4 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/storage/get-file-download.md @@ -0,0 +1,36 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = storage.getFileDownload( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: storage.getFileDownload( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/storage/get-file-preview.md b/docs/examples/1.4.x/client-flutter/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..f42138bd03 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/storage/get-file-preview.md @@ -0,0 +1,36 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = storage.getFilePreview( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: storage.getFilePreview( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/storage/get-file-view.md b/docs/examples/1.4.x/client-flutter/examples/storage/get-file-view.md new file mode 100644 index 0000000000..4f7c4d962b --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/storage/get-file-view.md @@ -0,0 +1,36 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + // downloading file + Future result = storage.getFileView( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ).then((bytes) { + final file = File('path_to_file/filename.ext'); + file.writeAsBytesSync(bytes) + }).catchError((error) { + print(error.response); + }) +} + +//displaying image preview +FutureBuilder( + future: storage.getFileView( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ), //works for both public file and private file, for private files you need to be logged in + builder: (context, snapshot) { + return snapshot.hasData && snapshot.data != null + ? Image.memory( + snapshot.data, + ) + : CircularProgressIndicator(); + }, +); diff --git a/docs/examples/1.4.x/client-flutter/examples/storage/get-file.md b/docs/examples/1.4.x/client-flutter/examples/storage/get-file.md new file mode 100644 index 0000000000..681aca41e0 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/storage/get-file.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = storage.getFile( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/storage/list-files.md b/docs/examples/1.4.x/client-flutter/examples/storage/list-files.md new file mode 100644 index 0000000000..e574f7bdaa --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/storage/list-files.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = storage.listFiles( + bucketId: '[BUCKET_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/storage/update-file.md b/docs/examples/1.4.x/client-flutter/examples/storage/update-file.md new file mode 100644 index 0000000000..1170f05cf3 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/storage/update-file.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = storage.updateFile( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/create-membership.md b/docs/examples/1.4.x/client-flutter/examples/teams/create-membership.md new file mode 100644 index 0000000000..ac58c5064f --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/create-membership.md @@ -0,0 +1,23 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.createMembership( + teamId: '[TEAM_ID]', + roles: [], + url: 'https://example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/create.md b/docs/examples/1.4.x/client-flutter/examples/teams/create.md new file mode 100644 index 0000000000..bd62ce32ab --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/create.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.create( + teamId: '[TEAM_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/delete-membership.md b/docs/examples/1.4.x/client-flutter/examples/teams/delete-membership.md new file mode 100644 index 0000000000..0febe42121 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/delete-membership.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.deleteMembership( + teamId: '[TEAM_ID]', + membershipId: '[MEMBERSHIP_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/delete.md b/docs/examples/1.4.x/client-flutter/examples/teams/delete.md new file mode 100644 index 0000000000..b45d971bf6 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/delete.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.delete( + teamId: '[TEAM_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/get-membership.md b/docs/examples/1.4.x/client-flutter/examples/teams/get-membership.md new file mode 100644 index 0000000000..28d95a201b --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/get-membership.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.getMembership( + teamId: '[TEAM_ID]', + membershipId: '[MEMBERSHIP_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/get-prefs.md b/docs/examples/1.4.x/client-flutter/examples/teams/get-prefs.md new file mode 100644 index 0000000000..e9ae94eb3f --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/get-prefs.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.getPrefs( + teamId: '[TEAM_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/get.md b/docs/examples/1.4.x/client-flutter/examples/teams/get.md new file mode 100644 index 0000000000..0ec7027f89 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/get.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.get( + teamId: '[TEAM_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/list-memberships.md b/docs/examples/1.4.x/client-flutter/examples/teams/list-memberships.md new file mode 100644 index 0000000000..cbbc525dc4 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/list-memberships.md @@ -0,0 +1,21 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.listMemberships( + teamId: '[TEAM_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/list.md b/docs/examples/1.4.x/client-flutter/examples/teams/list.md new file mode 100644 index 0000000000..80aa3016c2 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/list.md @@ -0,0 +1,20 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.list( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/update-membership-status.md b/docs/examples/1.4.x/client-flutter/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..ed31f54b20 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/update-membership-status.md @@ -0,0 +1,24 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.updateMembershipStatus( + teamId: '[TEAM_ID]', + membershipId: '[MEMBERSHIP_ID]', + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/update-membership.md b/docs/examples/1.4.x/client-flutter/examples/teams/update-membership.md new file mode 100644 index 0000000000..669568bd81 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/update-membership.md @@ -0,0 +1,23 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.updateMembership( + teamId: '[TEAM_ID]', + membershipId: '[MEMBERSHIP_ID]', + roles: [], + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/update-name.md b/docs/examples/1.4.x/client-flutter/examples/teams/update-name.md new file mode 100644 index 0000000000..5c794bd99b --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/update-name.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.updateName( + teamId: '[TEAM_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-flutter/examples/teams/update-prefs.md b/docs/examples/1.4.x/client-flutter/examples/teams/update-prefs.md new file mode 100644 index 0000000000..c29cbb9eb1 --- /dev/null +++ b/docs/examples/1.4.x/client-flutter/examples/teams/update-prefs.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = teams.updatePrefs( + teamId: '[TEAM_ID]', + prefs: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/create-anonymous-session.md b/docs/examples/1.4.x/client-graphql/examples/account/create-anonymous-session.md new file mode 100644 index 0000000000..369c487278 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/create-anonymous-session.md @@ -0,0 +1,29 @@ +mutation { + accountCreateAnonymousSession { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/create-email-session.md b/docs/examples/1.4.x/client-graphql/examples/account/create-email-session.md new file mode 100644 index 0000000000..a19d331a02 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/create-email-session.md @@ -0,0 +1,32 @@ +mutation { + accountCreateEmailSession( + email: "email@example.com", + password: "password" + ) { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/create-j-w-t.md b/docs/examples/1.4.x/client-graphql/examples/account/create-j-w-t.md new file mode 100644 index 0000000000..a5204f1256 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/create-j-w-t.md @@ -0,0 +1,5 @@ +mutation { + accountCreateJWT { + jwt + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/create-magic-u-r-l-session.md b/docs/examples/1.4.x/client-graphql/examples/account/create-magic-u-r-l-session.md new file mode 100644 index 0000000000..18418aecb9 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/create-magic-u-r-l-session.md @@ -0,0 +1,12 @@ +mutation { + accountCreateMagicURLSession( + userId: "[USER_ID]", + email: "email@example.com" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/create-phone-session.md b/docs/examples/1.4.x/client-graphql/examples/account/create-phone-session.md new file mode 100644 index 0000000000..9897de7651 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/create-phone-session.md @@ -0,0 +1,12 @@ +mutation { + accountCreatePhoneSession( + userId: "[USER_ID]", + phone: "+12065550100" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/create-phone-verification.md b/docs/examples/1.4.x/client-graphql/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..200e1c6d3a --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/create-phone-verification.md @@ -0,0 +1,9 @@ +mutation { + accountCreatePhoneVerification { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/create-recovery.md b/docs/examples/1.4.x/client-graphql/examples/account/create-recovery.md new file mode 100644 index 0000000000..865add6cc5 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/create-recovery.md @@ -0,0 +1,12 @@ +mutation { + accountCreateRecovery( + email: "email@example.com", + url: "https://example.com" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/create-verification.md b/docs/examples/1.4.x/client-graphql/examples/account/create-verification.md new file mode 100644 index 0000000000..22490be6b0 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/create-verification.md @@ -0,0 +1,11 @@ +mutation { + accountCreateVerification( + url: "https://example.com" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/create.md b/docs/examples/1.4.x/client-graphql/examples/account/create.md new file mode 100644 index 0000000000..d9c13bf901 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/create.md @@ -0,0 +1,24 @@ +mutation { + accountCreate( + userId: "[USER_ID]", + email: "email@example.com", + password: "" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/delete-identity.md b/docs/examples/1.4.x/client-graphql/examples/account/delete-identity.md new file mode 100644 index 0000000000..9bd9f0fa80 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/delete-identity.md @@ -0,0 +1,7 @@ +mutation { + accountDeleteIdentity( + identityId: "[IDENTITY_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/delete-session.md b/docs/examples/1.4.x/client-graphql/examples/account/delete-session.md new file mode 100644 index 0000000000..013bfa5946 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/delete-session.md @@ -0,0 +1,7 @@ +mutation { + accountDeleteSession( + sessionId: "[SESSION_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/delete-sessions.md b/docs/examples/1.4.x/client-graphql/examples/account/delete-sessions.md new file mode 100644 index 0000000000..b0d61daa81 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/delete-sessions.md @@ -0,0 +1,5 @@ +mutation { + accountDeleteSessions { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/get-prefs.md b/docs/examples/1.4.x/client-graphql/examples/account/get-prefs.md new file mode 100644 index 0000000000..6cb48d2b58 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/get-prefs.md @@ -0,0 +1,5 @@ +query { + accountGetPrefs { + data + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/get-session.md b/docs/examples/1.4.x/client-graphql/examples/account/get-session.md new file mode 100644 index 0000000000..2bf4e28c77 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/get-session.md @@ -0,0 +1,31 @@ +query { + accountGetSession( + sessionId: "[SESSION_ID]" + ) { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/get.md b/docs/examples/1.4.x/client-graphql/examples/account/get.md new file mode 100644 index 0000000000..39d06b1e1f --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/get.md @@ -0,0 +1,20 @@ +query { + accountGet { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/list-identities.md b/docs/examples/1.4.x/client-graphql/examples/account/list-identities.md new file mode 100644 index 0000000000..25c7e71462 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/list-identities.md @@ -0,0 +1,17 @@ +query { + accountListIdentities { + total + identities { + _id + _createdAt + _updatedAt + userId + provider + providerUid + providerEmail + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/list-logs.md b/docs/examples/1.4.x/client-graphql/examples/account/list-logs.md new file mode 100644 index 0000000000..95fd3bd7f3 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/list-logs.md @@ -0,0 +1,28 @@ +query { + accountListLogs { + total + logs { + event + userId + userEmail + userName + mode + ip + time + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/list-sessions.md b/docs/examples/1.4.x/client-graphql/examples/account/list-sessions.md new file mode 100644 index 0000000000..a089bf0b99 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/list-sessions.md @@ -0,0 +1,32 @@ +query { + accountListSessions { + total + sessions { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-email.md b/docs/examples/1.4.x/client-graphql/examples/account/update-email.md new file mode 100644 index 0000000000..1c11d65eae --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-email.md @@ -0,0 +1,23 @@ +mutation { + accountUpdateEmail( + email: "email@example.com", + password: "password" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-magic-u-r-l-session.md b/docs/examples/1.4.x/client-graphql/examples/account/update-magic-u-r-l-session.md new file mode 100644 index 0000000000..17c128b93e --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-magic-u-r-l-session.md @@ -0,0 +1,32 @@ +mutation { + accountUpdateMagicURLSession( + userId: "[USER_ID]", + secret: "[SECRET]" + ) { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-name.md b/docs/examples/1.4.x/client-graphql/examples/account/update-name.md new file mode 100644 index 0000000000..0bfa34f84f --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-name.md @@ -0,0 +1,22 @@ +mutation { + accountUpdateName( + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-password.md b/docs/examples/1.4.x/client-graphql/examples/account/update-password.md new file mode 100644 index 0000000000..35e1db66ec --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-password.md @@ -0,0 +1,22 @@ +mutation { + accountUpdatePassword( + password: "" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-phone-session.md b/docs/examples/1.4.x/client-graphql/examples/account/update-phone-session.md new file mode 100644 index 0000000000..a24a6094b4 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-phone-session.md @@ -0,0 +1,32 @@ +mutation { + accountUpdatePhoneSession( + userId: "[USER_ID]", + secret: "[SECRET]" + ) { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-phone-verification.md b/docs/examples/1.4.x/client-graphql/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..103c2faf18 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-phone-verification.md @@ -0,0 +1,12 @@ +mutation { + accountUpdatePhoneVerification( + userId: "[USER_ID]", + secret: "[SECRET]" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-phone.md b/docs/examples/1.4.x/client-graphql/examples/account/update-phone.md new file mode 100644 index 0000000000..e1870ed451 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-phone.md @@ -0,0 +1,23 @@ +mutation { + accountUpdatePhone( + phone: "+12065550100", + password: "password" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-prefs.md b/docs/examples/1.4.x/client-graphql/examples/account/update-prefs.md new file mode 100644 index 0000000000..11e500c343 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-prefs.md @@ -0,0 +1,22 @@ +mutation { + accountUpdatePrefs( + prefs: "{}" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-recovery.md b/docs/examples/1.4.x/client-graphql/examples/account/update-recovery.md new file mode 100644 index 0000000000..a0c985d7db --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-recovery.md @@ -0,0 +1,14 @@ +mutation { + accountUpdateRecovery( + userId: "[USER_ID]", + secret: "[SECRET]", + password: "password", + passwordAgain: "password" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-session.md b/docs/examples/1.4.x/client-graphql/examples/account/update-session.md new file mode 100644 index 0000000000..0358f49588 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-session.md @@ -0,0 +1,31 @@ +mutation { + accountUpdateSession( + sessionId: "[SESSION_ID]" + ) { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-status.md b/docs/examples/1.4.x/client-graphql/examples/account/update-status.md new file mode 100644 index 0000000000..6f68c7d054 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-status.md @@ -0,0 +1,20 @@ +mutation { + accountUpdateStatus { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/account/update-verification.md b/docs/examples/1.4.x/client-graphql/examples/account/update-verification.md new file mode 100644 index 0000000000..47abb20d34 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/account/update-verification.md @@ -0,0 +1,12 @@ +mutation { + accountUpdateVerification( + userId: "[USER_ID]", + secret: "[SECRET]" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/avatars/get-browser.md b/docs/examples/1.4.x/client-graphql/examples/avatars/get-browser.md new file mode 100644 index 0000000000..a76df8a6a2 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/avatars/get-browser.md @@ -0,0 +1,7 @@ +query { + avatarsGetBrowser( + code: "aa" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/client-graphql/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..84a56c1eaa --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/avatars/get-credit-card.md @@ -0,0 +1,7 @@ +query { + avatarsGetCreditCard( + code: "amex" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/avatars/get-favicon.md b/docs/examples/1.4.x/client-graphql/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..bfea71f498 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/avatars/get-favicon.md @@ -0,0 +1,7 @@ +query { + avatarsGetFavicon( + url: "https://example.com" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/avatars/get-flag.md b/docs/examples/1.4.x/client-graphql/examples/avatars/get-flag.md new file mode 100644 index 0000000000..6f3b6b5421 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/avatars/get-flag.md @@ -0,0 +1,7 @@ +query { + avatarsGetFlag( + code: "af" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/avatars/get-image.md b/docs/examples/1.4.x/client-graphql/examples/avatars/get-image.md new file mode 100644 index 0000000000..3371036d31 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/avatars/get-image.md @@ -0,0 +1,7 @@ +query { + avatarsGetImage( + url: "https://example.com" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/avatars/get-initials.md b/docs/examples/1.4.x/client-graphql/examples/avatars/get-initials.md new file mode 100644 index 0000000000..a1d8bef89c --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/avatars/get-initials.md @@ -0,0 +1,5 @@ +query { + avatarsGetInitials { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/avatars/get-q-r.md b/docs/examples/1.4.x/client-graphql/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..d2cc1f7f2c --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/avatars/get-q-r.md @@ -0,0 +1,7 @@ +query { + avatarsGetQR( + text: "[TEXT]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/databases/create-document.md b/docs/examples/1.4.x/client-graphql/examples/databases/create-document.md new file mode 100644 index 0000000000..6ef546c0de --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/databases/create-document.md @@ -0,0 +1,16 @@ +mutation { + databasesCreateDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]", + data: "{}" + ) { + _id + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/databases/delete-document.md b/docs/examples/1.4.x/client-graphql/examples/databases/delete-document.md new file mode 100644 index 0000000000..74954bb61b --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/databases/delete-document.md @@ -0,0 +1,9 @@ +mutation { + databasesDeleteDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/databases/get-document.md b/docs/examples/1.4.x/client-graphql/examples/databases/get-document.md new file mode 100644 index 0000000000..94b30290a2 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/databases/get-document.md @@ -0,0 +1,15 @@ +query { + databasesGetDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" + ) { + _id + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/databases/list-documents.md b/docs/examples/1.4.x/client-graphql/examples/databases/list-documents.md new file mode 100644 index 0000000000..62d799ad91 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/databases/list-documents.md @@ -0,0 +1,17 @@ +query { + databasesListDocuments( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" + ) { + total + documents { + _id + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/databases/update-document.md b/docs/examples/1.4.x/client-graphql/examples/databases/update-document.md new file mode 100644 index 0000000000..0476c4ce40 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/databases/update-document.md @@ -0,0 +1,15 @@ +mutation { + databasesUpdateDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" + ) { + _id + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/functions/create-execution.md b/docs/examples/1.4.x/client-graphql/examples/functions/create-execution.md new file mode 100644 index 0000000000..56e58db014 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/functions/create-execution.md @@ -0,0 +1,28 @@ +mutation { + functionsCreateExecution( + functionId: "[FUNCTION_ID]" + ) { + _id + _createdAt + _updatedAt + _permissions + functionId + trigger + status + requestMethod + requestPath + requestHeaders { + name + value + } + responseStatusCode + responseBody + responseHeaders { + name + value + } + logs + errors + duration + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/functions/get-execution.md b/docs/examples/1.4.x/client-graphql/examples/functions/get-execution.md new file mode 100644 index 0000000000..bf19fca107 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/functions/get-execution.md @@ -0,0 +1,29 @@ +query { + functionsGetExecution( + functionId: "[FUNCTION_ID]", + executionId: "[EXECUTION_ID]" + ) { + _id + _createdAt + _updatedAt + _permissions + functionId + trigger + status + requestMethod + requestPath + requestHeaders { + name + value + } + responseStatusCode + responseBody + responseHeaders { + name + value + } + logs + errors + duration + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/functions/list-executions.md b/docs/examples/1.4.x/client-graphql/examples/functions/list-executions.md new file mode 100644 index 0000000000..86b656d428 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/functions/list-executions.md @@ -0,0 +1,31 @@ +query { + functionsListExecutions( + functionId: "[FUNCTION_ID]" + ) { + total + executions { + _id + _createdAt + _updatedAt + _permissions + functionId + trigger + status + requestMethod + requestPath + requestHeaders { + name + value + } + responseStatusCode + responseBody + responseHeaders { + name + value + } + logs + errors + duration + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/locale/get.md b/docs/examples/1.4.x/client-graphql/examples/locale/get.md new file mode 100644 index 0000000000..2b2bbcc1f1 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/locale/get.md @@ -0,0 +1,11 @@ +query { + localeGet { + ip + countryCode + country + continentCode + continent + eu + currency + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/locale/list-codes.md b/docs/examples/1.4.x/client-graphql/examples/locale/list-codes.md new file mode 100644 index 0000000000..0164cc3782 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/locale/list-codes.md @@ -0,0 +1,9 @@ +query { + localeListCodes { + total + localeCodes { + code + name + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/locale/list-continents.md b/docs/examples/1.4.x/client-graphql/examples/locale/list-continents.md new file mode 100644 index 0000000000..41f672c565 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/locale/list-continents.md @@ -0,0 +1,9 @@ +query { + localeListContinents { + total + continents { + name + code + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/client-graphql/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..00cd4652f9 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/locale/list-countries-e-u.md @@ -0,0 +1,9 @@ +query { + localeListCountriesEU { + total + countries { + name + code + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/client-graphql/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..33d2296850 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/locale/list-countries-phones.md @@ -0,0 +1,10 @@ +query { + localeListCountriesPhones { + total + phones { + code + countryCode + countryName + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/locale/list-countries.md b/docs/examples/1.4.x/client-graphql/examples/locale/list-countries.md new file mode 100644 index 0000000000..9312bc94b1 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/locale/list-countries.md @@ -0,0 +1,9 @@ +query { + localeListCountries { + total + countries { + name + code + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/locale/list-currencies.md b/docs/examples/1.4.x/client-graphql/examples/locale/list-currencies.md new file mode 100644 index 0000000000..cde3ab488a --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/locale/list-currencies.md @@ -0,0 +1,14 @@ +query { + localeListCurrencies { + total + currencies { + symbol + name + symbolNative + decimalDigits + rounding + code + namePlural + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/locale/list-languages.md b/docs/examples/1.4.x/client-graphql/examples/locale/list-languages.md new file mode 100644 index 0000000000..b0d76c522b --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/locale/list-languages.md @@ -0,0 +1,10 @@ +query { + localeListLanguages { + total + languages { + name + code + nativeName + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/storage/create-file.md b/docs/examples/1.4.x/client-graphql/examples/storage/create-file.md new file mode 100644 index 0000000000..31d50ffbc2 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/storage/create-file.md @@ -0,0 +1,24 @@ +POST /v1/storage/buckets/{bucketId}/files HTTP/1.1 +Host: HOSTNAME +Content-Type: multipart/form-data; boundary="cec8e8123c05ba25" +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... +Content-Length: *Length of your entity body in bytes* + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="operations" + +{ "query": "mutation { storageCreateFile(bucketId: $bucketId, fileId: $fileId, file: $file) { id }" }, "variables": { "bucketId": "[BUCKET_ID]", "fileId": "[FILE_ID]", "file": null } } + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="map" + +{ "0": ["variables.file"] } + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="0"; filename="file.ext" + +File contents + +--cec8e8123c05ba25-- diff --git a/docs/examples/1.4.x/client-graphql/examples/storage/delete-file.md b/docs/examples/1.4.x/client-graphql/examples/storage/delete-file.md new file mode 100644 index 0000000000..7ec3757a8c --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/storage/delete-file.md @@ -0,0 +1,8 @@ +mutation { + storageDeleteFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/storage/get-file-download.md b/docs/examples/1.4.x/client-graphql/examples/storage/get-file-download.md new file mode 100644 index 0000000000..845547f09b --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/storage/get-file-download.md @@ -0,0 +1,8 @@ +query { + storageGetFileDownload( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/storage/get-file-preview.md b/docs/examples/1.4.x/client-graphql/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..c26e90dac2 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/storage/get-file-preview.md @@ -0,0 +1,8 @@ +query { + storageGetFilePreview( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/storage/get-file-view.md b/docs/examples/1.4.x/client-graphql/examples/storage/get-file-view.md new file mode 100644 index 0000000000..72e9ec20d2 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/storage/get-file-view.md @@ -0,0 +1,8 @@ +query { + storageGetFileView( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/storage/get-file.md b/docs/examples/1.4.x/client-graphql/examples/storage/get-file.md new file mode 100644 index 0000000000..61182e1f02 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/storage/get-file.md @@ -0,0 +1,18 @@ +query { + storageGetFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + _id + bucketId + _createdAt + _updatedAt + _permissions + name + signature + mimeType + sizeOriginal + chunksTotal + chunksUploaded + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/storage/list-files.md b/docs/examples/1.4.x/client-graphql/examples/storage/list-files.md new file mode 100644 index 0000000000..430fc1dbdf --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/storage/list-files.md @@ -0,0 +1,20 @@ +query { + storageListFiles( + bucketId: "[BUCKET_ID]" + ) { + total + files { + _id + bucketId + _createdAt + _updatedAt + _permissions + name + signature + mimeType + sizeOriginal + chunksTotal + chunksUploaded + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/storage/update-file.md b/docs/examples/1.4.x/client-graphql/examples/storage/update-file.md new file mode 100644 index 0000000000..0a4c98d087 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/storage/update-file.md @@ -0,0 +1,18 @@ +mutation { + storageUpdateFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + _id + bucketId + _createdAt + _updatedAt + _permissions + name + signature + mimeType + sizeOriginal + chunksTotal + chunksUploaded + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/create-membership.md b/docs/examples/1.4.x/client-graphql/examples/teams/create-membership.md new file mode 100644 index 0000000000..045a0ae7a8 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/create-membership.md @@ -0,0 +1,20 @@ +mutation { + teamsCreateMembership( + teamId: "[TEAM_ID]", + roles: [], + url: "https://example.com" + ) { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/create.md b/docs/examples/1.4.x/client-graphql/examples/teams/create.md new file mode 100644 index 0000000000..2dd3ca74fb --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/create.md @@ -0,0 +1,15 @@ +mutation { + teamsCreate( + teamId: "[TEAM_ID]", + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + name + total + prefs { + data + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/delete-membership.md b/docs/examples/1.4.x/client-graphql/examples/teams/delete-membership.md new file mode 100644 index 0000000000..b8a5252fcf --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/delete-membership.md @@ -0,0 +1,8 @@ +mutation { + teamsDeleteMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/delete.md b/docs/examples/1.4.x/client-graphql/examples/teams/delete.md new file mode 100644 index 0000000000..161f8a3454 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/delete.md @@ -0,0 +1,7 @@ +mutation { + teamsDelete( + teamId: "[TEAM_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/get-membership.md b/docs/examples/1.4.x/client-graphql/examples/teams/get-membership.md new file mode 100644 index 0000000000..d28ef798fa --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/get-membership.md @@ -0,0 +1,19 @@ +query { + teamsGetMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]" + ) { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/get-prefs.md b/docs/examples/1.4.x/client-graphql/examples/teams/get-prefs.md new file mode 100644 index 0000000000..ce6b851e9e --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/get-prefs.md @@ -0,0 +1,7 @@ +query { + teamsGetPrefs( + teamId: "[TEAM_ID]" + ) { + data + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/get.md b/docs/examples/1.4.x/client-graphql/examples/teams/get.md new file mode 100644 index 0000000000..aa83e30e73 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/get.md @@ -0,0 +1,14 @@ +query { + teamsGet( + teamId: "[TEAM_ID]" + ) { + _id + _createdAt + _updatedAt + name + total + prefs { + data + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/list-memberships.md b/docs/examples/1.4.x/client-graphql/examples/teams/list-memberships.md new file mode 100644 index 0000000000..8ac82c1faf --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/list-memberships.md @@ -0,0 +1,21 @@ +query { + teamsListMemberships( + teamId: "[TEAM_ID]" + ) { + total + memberships { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/list.md b/docs/examples/1.4.x/client-graphql/examples/teams/list.md new file mode 100644 index 0000000000..47117c5627 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/list.md @@ -0,0 +1,15 @@ +query { + teamsList { + total + teams { + _id + _createdAt + _updatedAt + name + total + prefs { + data + } + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/update-membership-status.md b/docs/examples/1.4.x/client-graphql/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..ca6cec12e1 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/update-membership-status.md @@ -0,0 +1,21 @@ +mutation { + teamsUpdateMembershipStatus( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + userId: "[USER_ID]", + secret: "[SECRET]" + ) { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/update-membership.md b/docs/examples/1.4.x/client-graphql/examples/teams/update-membership.md new file mode 100644 index 0000000000..e56e0c46af --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/update-membership.md @@ -0,0 +1,20 @@ +mutation { + teamsUpdateMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + roles: [] + ) { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/update-name.md b/docs/examples/1.4.x/client-graphql/examples/teams/update-name.md new file mode 100644 index 0000000000..88e994b63a --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/update-name.md @@ -0,0 +1,15 @@ +mutation { + teamsUpdateName( + teamId: "[TEAM_ID]", + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + name + total + prefs { + data + } + } +} diff --git a/docs/examples/1.4.x/client-graphql/examples/teams/update-prefs.md b/docs/examples/1.4.x/client-graphql/examples/teams/update-prefs.md new file mode 100644 index 0000000000..55ed909fe3 --- /dev/null +++ b/docs/examples/1.4.x/client-graphql/examples/teams/update-prefs.md @@ -0,0 +1,8 @@ +mutation { + teamsUpdatePrefs( + teamId: "[TEAM_ID]", + prefs: "{}" + ) { + data + } +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/create-anonymous-session.md b/docs/examples/1.4.x/client-rest/examples/account/create-anonymous-session.md new file mode 100644 index 0000000000..33a349b754 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create-anonymous-session.md @@ -0,0 +1,6 @@ +POST /v1/account/sessions/anonymous HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 + diff --git a/docs/examples/1.4.x/client-rest/examples/account/create-email-session.md b/docs/examples/1.4.x/client-rest/examples/account/create-email-session.md new file mode 100644 index 0000000000..09661b0a28 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create-email-session.md @@ -0,0 +1,10 @@ +POST /v1/account/sessions/email HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 + +{ + "email": "email@example.com", + "password": "password" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/create-j-w-t.md b/docs/examples/1.4.x/client-rest/examples/account/create-j-w-t.md new file mode 100644 index 0000000000..382883d879 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create-j-w-t.md @@ -0,0 +1,6 @@ +POST /v1/account/jwt HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 + diff --git a/docs/examples/1.4.x/client-rest/examples/account/create-magic-u-r-l-session.md b/docs/examples/1.4.x/client-rest/examples/account/create-magic-u-r-l-session.md new file mode 100644 index 0000000000..99042b7110 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create-magic-u-r-l-session.md @@ -0,0 +1,11 @@ +POST /v1/account/sessions/magic-url HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "url": "https://example.com" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/create-o-auth2session.md b/docs/examples/1.4.x/client-rest/examples/account/create-o-auth2session.md new file mode 100644 index 0000000000..c890dbb194 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create-o-auth2session.md @@ -0,0 +1,6 @@ +GET /v1/account/sessions/oauth2/{provider} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 + diff --git a/docs/examples/1.4.x/client-rest/examples/account/create-phone-session.md b/docs/examples/1.4.x/client-rest/examples/account/create-phone-session.md new file mode 100644 index 0000000000..baf6f39e20 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create-phone-session.md @@ -0,0 +1,10 @@ +POST /v1/account/sessions/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 + +{ + "userId": "[USER_ID]", + "phone": "+12065550100" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/create-phone-verification.md b/docs/examples/1.4.x/client-rest/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..43512be67f --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create-phone-verification.md @@ -0,0 +1,7 @@ +POST /v1/account/verification/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/create-recovery.md b/docs/examples/1.4.x/client-rest/examples/account/create-recovery.md new file mode 100644 index 0000000000..2ef165d2d4 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create-recovery.md @@ -0,0 +1,11 @@ +POST /v1/account/recovery HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "email": "email@example.com", + "url": "https://example.com" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/create-verification.md b/docs/examples/1.4.x/client-rest/examples/account/create-verification.md new file mode 100644 index 0000000000..81e74312d9 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create-verification.md @@ -0,0 +1,10 @@ +POST /v1/account/verification HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "url": "https://example.com" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/create.md b/docs/examples/1.4.x/client-rest/examples/account/create.md new file mode 100644 index 0000000000..92d7be7edd --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/create.md @@ -0,0 +1,12 @@ +POST /v1/account HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "password": , + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/delete-identity.md b/docs/examples/1.4.x/client-rest/examples/account/delete-identity.md new file mode 100644 index 0000000000..25db38436b --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/delete-identity.md @@ -0,0 +1,7 @@ +DELETE /v1/account/identities/{identityId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/delete-session.md b/docs/examples/1.4.x/client-rest/examples/account/delete-session.md new file mode 100644 index 0000000000..4783c1983c --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/delete-session.md @@ -0,0 +1,7 @@ +DELETE /v1/account/sessions/{sessionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/delete-sessions.md b/docs/examples/1.4.x/client-rest/examples/account/delete-sessions.md new file mode 100644 index 0000000000..8632a92a29 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/delete-sessions.md @@ -0,0 +1,7 @@ +DELETE /v1/account/sessions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/get-prefs.md b/docs/examples/1.4.x/client-rest/examples/account/get-prefs.md new file mode 100644 index 0000000000..1de7705065 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/get-prefs.md @@ -0,0 +1,7 @@ +GET /v1/account/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/get-session.md b/docs/examples/1.4.x/client-rest/examples/account/get-session.md new file mode 100644 index 0000000000..2953bc7d5b --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/get-session.md @@ -0,0 +1,7 @@ +GET /v1/account/sessions/{sessionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/get.md b/docs/examples/1.4.x/client-rest/examples/account/get.md new file mode 100644 index 0000000000..2cf6ee6937 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/get.md @@ -0,0 +1,7 @@ +GET /v1/account HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/list-identities.md b/docs/examples/1.4.x/client-rest/examples/account/list-identities.md new file mode 100644 index 0000000000..f1fc54d32d --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/list-identities.md @@ -0,0 +1,7 @@ +GET /v1/account/identities HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/list-logs.md b/docs/examples/1.4.x/client-rest/examples/account/list-logs.md new file mode 100644 index 0000000000..811310b9a6 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/list-logs.md @@ -0,0 +1,7 @@ +GET /v1/account/logs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/list-sessions.md b/docs/examples/1.4.x/client-rest/examples/account/list-sessions.md new file mode 100644 index 0000000000..25d7a6247b --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/list-sessions.md @@ -0,0 +1,7 @@ +GET /v1/account/sessions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-email.md b/docs/examples/1.4.x/client-rest/examples/account/update-email.md new file mode 100644 index 0000000000..a9bec63172 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-email.md @@ -0,0 +1,11 @@ +PATCH /v1/account/email HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "email": "email@example.com", + "password": "password" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-magic-u-r-l-session.md b/docs/examples/1.4.x/client-rest/examples/account/update-magic-u-r-l-session.md new file mode 100644 index 0000000000..c5b9488d24 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-magic-u-r-l-session.md @@ -0,0 +1,10 @@ +PUT /v1/account/sessions/magic-url HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-name.md b/docs/examples/1.4.x/client-rest/examples/account/update-name.md new file mode 100644 index 0000000000..374f2c8642 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-name.md @@ -0,0 +1,10 @@ +PATCH /v1/account/name HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-password.md b/docs/examples/1.4.x/client-rest/examples/account/update-password.md new file mode 100644 index 0000000000..a15a7d3cde --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-password.md @@ -0,0 +1,11 @@ +PATCH /v1/account/password HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "password": , + "oldPassword": "password" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-phone-session.md b/docs/examples/1.4.x/client-rest/examples/account/update-phone-session.md new file mode 100644 index 0000000000..ae3ec67f97 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-phone-session.md @@ -0,0 +1,10 @@ +PUT /v1/account/sessions/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-phone-verification.md b/docs/examples/1.4.x/client-rest/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..a87f9cc404 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-phone-verification.md @@ -0,0 +1,11 @@ +PUT /v1/account/verification/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-phone.md b/docs/examples/1.4.x/client-rest/examples/account/update-phone.md new file mode 100644 index 0000000000..90faa9b9f5 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-phone.md @@ -0,0 +1,11 @@ +PATCH /v1/account/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "phone": "+12065550100", + "password": "password" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-prefs.md b/docs/examples/1.4.x/client-rest/examples/account/update-prefs.md new file mode 100644 index 0000000000..83f544e705 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-prefs.md @@ -0,0 +1,10 @@ +PATCH /v1/account/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "prefs": {} +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-recovery.md b/docs/examples/1.4.x/client-rest/examples/account/update-recovery.md new file mode 100644 index 0000000000..24cb547aa3 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-recovery.md @@ -0,0 +1,13 @@ +PUT /v1/account/recovery HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]", + "password": "password", + "passwordAgain": "password" +} diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-session.md b/docs/examples/1.4.x/client-rest/examples/account/update-session.md new file mode 100644 index 0000000000..880e5ba7e4 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-session.md @@ -0,0 +1,7 @@ +PATCH /v1/account/sessions/{sessionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-status.md b/docs/examples/1.4.x/client-rest/examples/account/update-status.md new file mode 100644 index 0000000000..5677d65736 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-status.md @@ -0,0 +1,7 @@ +PATCH /v1/account/status HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/account/update-verification.md b/docs/examples/1.4.x/client-rest/examples/account/update-verification.md new file mode 100644 index 0000000000..ed689bf02e --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/account/update-verification.md @@ -0,0 +1,11 @@ +PUT /v1/account/verification HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]" +} diff --git a/docs/examples/1.4.x/client-rest/examples/avatars/get-browser.md b/docs/examples/1.4.x/client-rest/examples/avatars/get-browser.md new file mode 100644 index 0000000000..b3d67e7a56 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/avatars/get-browser.md @@ -0,0 +1,7 @@ +GET /v1/avatars/browsers/{code} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/client-rest/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..a9c4ddbb55 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/avatars/get-credit-card.md @@ -0,0 +1,7 @@ +GET /v1/avatars/credit-cards/{code} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/avatars/get-favicon.md b/docs/examples/1.4.x/client-rest/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..b161830c6a --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/avatars/get-favicon.md @@ -0,0 +1,7 @@ +GET /v1/avatars/favicon HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/avatars/get-flag.md b/docs/examples/1.4.x/client-rest/examples/avatars/get-flag.md new file mode 100644 index 0000000000..e17e60f295 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/avatars/get-flag.md @@ -0,0 +1,7 @@ +GET /v1/avatars/flags/{code} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/avatars/get-image.md b/docs/examples/1.4.x/client-rest/examples/avatars/get-image.md new file mode 100644 index 0000000000..8cf57cd369 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/avatars/get-image.md @@ -0,0 +1,7 @@ +GET /v1/avatars/image HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/avatars/get-initials.md b/docs/examples/1.4.x/client-rest/examples/avatars/get-initials.md new file mode 100644 index 0000000000..06e8ce7854 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/avatars/get-initials.md @@ -0,0 +1,7 @@ +GET /v1/avatars/initials HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/avatars/get-q-r.md b/docs/examples/1.4.x/client-rest/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..4e80c30143 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/avatars/get-q-r.md @@ -0,0 +1,7 @@ +GET /v1/avatars/qr HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/databases/create-document.md b/docs/examples/1.4.x/client-rest/examples/databases/create-document.md new file mode 100644 index 0000000000..244360c038 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/databases/create-document.md @@ -0,0 +1,12 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/documents HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "documentId": "[DOCUMENT_ID]", + "data": {}, + "permissions": ["read(\"any\")"] +} diff --git a/docs/examples/1.4.x/client-rest/examples/databases/delete-document.md b/docs/examples/1.4.x/client-rest/examples/databases/delete-document.md new file mode 100644 index 0000000000..31e759d529 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/databases/delete-document.md @@ -0,0 +1,7 @@ +DELETE /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/databases/get-document.md b/docs/examples/1.4.x/client-rest/examples/databases/get-document.md new file mode 100644 index 0000000000..dcf91a0726 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/databases/get-document.md @@ -0,0 +1,7 @@ +GET /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/databases/list-documents.md b/docs/examples/1.4.x/client-rest/examples/databases/list-documents.md new file mode 100644 index 0000000000..ff2f114591 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/databases/list-documents.md @@ -0,0 +1,7 @@ +GET /v1/databases/{databaseId}/collections/{collectionId}/documents HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/databases/update-document.md b/docs/examples/1.4.x/client-rest/examples/databases/update-document.md new file mode 100644 index 0000000000..0f3323e276 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/databases/update-document.md @@ -0,0 +1,11 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "data": {}, + "permissions": ["read(\"any\")"] +} diff --git a/docs/examples/1.4.x/client-rest/examples/functions/create-execution.md b/docs/examples/1.4.x/client-rest/examples/functions/create-execution.md new file mode 100644 index 0000000000..26a61019cc --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/functions/create-execution.md @@ -0,0 +1,14 @@ +POST /v1/functions/{functionId}/executions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "body": "[BODY]", + "async": false, + "path": "[PATH]", + "method": "GET", + "headers": {} +} diff --git a/docs/examples/1.4.x/client-rest/examples/functions/get-execution.md b/docs/examples/1.4.x/client-rest/examples/functions/get-execution.md new file mode 100644 index 0000000000..13e1892d04 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/functions/get-execution.md @@ -0,0 +1,7 @@ +GET /v1/functions/{functionId}/executions/{executionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/functions/list-executions.md b/docs/examples/1.4.x/client-rest/examples/functions/list-executions.md new file mode 100644 index 0000000000..734c05f134 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/functions/list-executions.md @@ -0,0 +1,7 @@ +GET /v1/functions/{functionId}/executions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/graphql/mutation.md b/docs/examples/1.4.x/client-rest/examples/graphql/mutation.md new file mode 100644 index 0000000000..72be41e976 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/graphql/mutation.md @@ -0,0 +1,11 @@ +POST /v1/graphql/mutation HTTP/1.1 +Host: HOSTNAME +X-Sdk-Graphql: true +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "query": {} +} diff --git a/docs/examples/1.4.x/client-rest/examples/graphql/query.md b/docs/examples/1.4.x/client-rest/examples/graphql/query.md new file mode 100644 index 0000000000..7f3bbc0538 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/graphql/query.md @@ -0,0 +1,11 @@ +POST /v1/graphql HTTP/1.1 +Host: HOSTNAME +X-Sdk-Graphql: true +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "query": {} +} diff --git a/docs/examples/1.4.x/client-rest/examples/locale/get.md b/docs/examples/1.4.x/client-rest/examples/locale/get.md new file mode 100644 index 0000000000..19cf0f494e --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/locale/get.md @@ -0,0 +1,7 @@ +GET /v1/locale HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/locale/list-codes.md b/docs/examples/1.4.x/client-rest/examples/locale/list-codes.md new file mode 100644 index 0000000000..bd979ab3ad --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/locale/list-codes.md @@ -0,0 +1,7 @@ +GET /v1/locale/codes HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/locale/list-continents.md b/docs/examples/1.4.x/client-rest/examples/locale/list-continents.md new file mode 100644 index 0000000000..177852e4f5 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/locale/list-continents.md @@ -0,0 +1,7 @@ +GET /v1/locale/continents HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/client-rest/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..0fc99eaa59 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/locale/list-countries-e-u.md @@ -0,0 +1,7 @@ +GET /v1/locale/countries/eu HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/client-rest/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..e8767b50c7 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/locale/list-countries-phones.md @@ -0,0 +1,7 @@ +GET /v1/locale/countries/phones HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/locale/list-countries.md b/docs/examples/1.4.x/client-rest/examples/locale/list-countries.md new file mode 100644 index 0000000000..057ca4754c --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/locale/list-countries.md @@ -0,0 +1,7 @@ +GET /v1/locale/countries HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/locale/list-currencies.md b/docs/examples/1.4.x/client-rest/examples/locale/list-currencies.md new file mode 100644 index 0000000000..2cde64208e --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/locale/list-currencies.md @@ -0,0 +1,7 @@ +GET /v1/locale/currencies HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/locale/list-languages.md b/docs/examples/1.4.x/client-rest/examples/locale/list-languages.md new file mode 100644 index 0000000000..0046f8f611 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/locale/list-languages.md @@ -0,0 +1,7 @@ +GET /v1/locale/languages HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/storage/create-file.md b/docs/examples/1.4.x/client-rest/examples/storage/create-file.md new file mode 100644 index 0000000000..1fa06157c6 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/storage/create-file.md @@ -0,0 +1,25 @@ +POST /v1/storage/buckets/{bucketId}/files HTTP/1.1 +Host: HOSTNAME +Content-Type: multipart/form-data; boundary="cec8e8123c05ba25" +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... +Content-Length: *Length of your entity body in bytes* + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="fileId" + +"[FILE_ID]" + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="file" + +cf 94 84 24 8d c4 91 10 0f dc 54 26 6c 8e 4b bc +e8 ee 55 94 29 e7 94 89 19 26 28 01 26 29 3f 16... + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="permissions[]" + +["read(\"any\")"] + +--cec8e8123c05ba25-- diff --git a/docs/examples/1.4.x/client-rest/examples/storage/delete-file.md b/docs/examples/1.4.x/client-rest/examples/storage/delete-file.md new file mode 100644 index 0000000000..37d68d34e2 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/storage/delete-file.md @@ -0,0 +1,7 @@ +DELETE /v1/storage/buckets/{bucketId}/files/{fileId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/storage/get-file-download.md b/docs/examples/1.4.x/client-rest/examples/storage/get-file-download.md new file mode 100644 index 0000000000..d66d170ab7 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/storage/get-file-download.md @@ -0,0 +1,7 @@ +GET /v1/storage/buckets/{bucketId}/files/{fileId}/download HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/storage/get-file-preview.md b/docs/examples/1.4.x/client-rest/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..b6437f6a09 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/storage/get-file-preview.md @@ -0,0 +1,7 @@ +GET /v1/storage/buckets/{bucketId}/files/{fileId}/preview HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/storage/get-file-view.md b/docs/examples/1.4.x/client-rest/examples/storage/get-file-view.md new file mode 100644 index 0000000000..c64ec5ec3c --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/storage/get-file-view.md @@ -0,0 +1,7 @@ +GET /v1/storage/buckets/{bucketId}/files/{fileId}/view HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/storage/get-file.md b/docs/examples/1.4.x/client-rest/examples/storage/get-file.md new file mode 100644 index 0000000000..8c9673bd74 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/storage/get-file.md @@ -0,0 +1,7 @@ +GET /v1/storage/buckets/{bucketId}/files/{fileId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/storage/list-files.md b/docs/examples/1.4.x/client-rest/examples/storage/list-files.md new file mode 100644 index 0000000000..01b2d82eb3 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/storage/list-files.md @@ -0,0 +1,7 @@ +GET /v1/storage/buckets/{bucketId}/files HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/storage/update-file.md b/docs/examples/1.4.x/client-rest/examples/storage/update-file.md new file mode 100644 index 0000000000..36375259cb --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/storage/update-file.md @@ -0,0 +1,11 @@ +PUT /v1/storage/buckets/{bucketId}/files/{fileId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "name": "[NAME]", + "permissions": ["read(\"any\")"] +} diff --git a/docs/examples/1.4.x/client-rest/examples/teams/create-membership.md b/docs/examples/1.4.x/client-rest/examples/teams/create-membership.md new file mode 100644 index 0000000000..41909070a7 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/create-membership.md @@ -0,0 +1,15 @@ +POST /v1/teams/{teamId}/memberships HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "email": "email@example.com", + "userId": "[USER_ID]", + "phone": "+12065550100", + "roles": [], + "url": "https://example.com", + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/client-rest/examples/teams/create.md b/docs/examples/1.4.x/client-rest/examples/teams/create.md new file mode 100644 index 0000000000..87a82e2f28 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/create.md @@ -0,0 +1,12 @@ +POST /v1/teams HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "teamId": "[TEAM_ID]", + "name": "[NAME]", + "roles": [] +} diff --git a/docs/examples/1.4.x/client-rest/examples/teams/delete-membership.md b/docs/examples/1.4.x/client-rest/examples/teams/delete-membership.md new file mode 100644 index 0000000000..df46cd06a1 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/delete-membership.md @@ -0,0 +1,7 @@ +DELETE /v1/teams/{teamId}/memberships/{membershipId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/teams/delete.md b/docs/examples/1.4.x/client-rest/examples/teams/delete.md new file mode 100644 index 0000000000..31a9af862e --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/delete.md @@ -0,0 +1,7 @@ +DELETE /v1/teams/{teamId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/teams/get-membership.md b/docs/examples/1.4.x/client-rest/examples/teams/get-membership.md new file mode 100644 index 0000000000..27125f773a --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/get-membership.md @@ -0,0 +1,7 @@ +GET /v1/teams/{teamId}/memberships/{membershipId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/teams/get-prefs.md b/docs/examples/1.4.x/client-rest/examples/teams/get-prefs.md new file mode 100644 index 0000000000..bfa1c9c871 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/get-prefs.md @@ -0,0 +1,7 @@ +GET /v1/teams/{teamId}/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/teams/get.md b/docs/examples/1.4.x/client-rest/examples/teams/get.md new file mode 100644 index 0000000000..d6cd3de772 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/get.md @@ -0,0 +1,7 @@ +GET /v1/teams/{teamId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/teams/list-memberships.md b/docs/examples/1.4.x/client-rest/examples/teams/list-memberships.md new file mode 100644 index 0000000000..b9aeaad2d2 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/list-memberships.md @@ -0,0 +1,7 @@ +GET /v1/teams/{teamId}/memberships HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/teams/list.md b/docs/examples/1.4.x/client-rest/examples/teams/list.md new file mode 100644 index 0000000000..00c82bc180 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/list.md @@ -0,0 +1,7 @@ +GET /v1/teams HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/client-rest/examples/teams/update-membership-status.md b/docs/examples/1.4.x/client-rest/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..5b3a0e7414 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/update-membership-status.md @@ -0,0 +1,11 @@ +PATCH /v1/teams/{teamId}/memberships/{membershipId}/status HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]" +} diff --git a/docs/examples/1.4.x/client-rest/examples/teams/update-membership.md b/docs/examples/1.4.x/client-rest/examples/teams/update-membership.md new file mode 100644 index 0000000000..94fb6d0ed0 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/update-membership.md @@ -0,0 +1,10 @@ +PATCH /v1/teams/{teamId}/memberships/{membershipId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "roles": [] +} diff --git a/docs/examples/1.4.x/client-rest/examples/teams/update-name.md b/docs/examples/1.4.x/client-rest/examples/teams/update-name.md new file mode 100644 index 0000000000..4eaa1a3232 --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/update-name.md @@ -0,0 +1,10 @@ +PUT /v1/teams/{teamId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/client-rest/examples/teams/update-prefs.md b/docs/examples/1.4.x/client-rest/examples/teams/update-prefs.md new file mode 100644 index 0000000000..d04ee5aa7b --- /dev/null +++ b/docs/examples/1.4.x/client-rest/examples/teams/update-prefs.md @@ -0,0 +1,10 @@ +PUT /v1/teams/{teamId}/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "prefs": {} +} diff --git a/docs/examples/1.4.x/client-web/examples/account/create-anonymous-session.md b/docs/examples/1.4.x/client-web/examples/account/create-anonymous-session.md new file mode 100644 index 0000000000..c331fc8863 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create-anonymous-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createAnonymousSession(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/create-email-session.md b/docs/examples/1.4.x/client-web/examples/account/create-email-session.md new file mode 100644 index 0000000000..76e2e31665 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create-email-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createEmailSession('email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/create-j-w-t.md b/docs/examples/1.4.x/client-web/examples/account/create-j-w-t.md new file mode 100644 index 0000000000..f388a3da31 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create-j-w-t.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createJWT(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/create-magic-u-r-l-session.md b/docs/examples/1.4.x/client-web/examples/account/create-magic-u-r-l-session.md new file mode 100644 index 0000000000..d48f031ded --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create-magic-u-r-l-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createMagicURLSession('[USER_ID]', 'email@example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/create-o-auth2session.md b/docs/examples/1.4.x/client-web/examples/account/create-o-auth2session.md new file mode 100644 index 0000000000..3757a1c63f --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create-o-auth2session.md @@ -0,0 +1,14 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +// Go to OAuth provider login page +account.createOAuth2Session('amazon'); + diff --git a/docs/examples/1.4.x/client-web/examples/account/create-phone-session.md b/docs/examples/1.4.x/client-web/examples/account/create-phone-session.md new file mode 100644 index 0000000000..e5a23aafee --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create-phone-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createPhoneSession('[USER_ID]', '+12065550100'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/create-phone-verification.md b/docs/examples/1.4.x/client-web/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..a1cbd55277 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create-phone-verification.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createPhoneVerification(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/create-recovery.md b/docs/examples/1.4.x/client-web/examples/account/create-recovery.md new file mode 100644 index 0000000000..1838c0414c --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create-recovery.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createRecovery('email@example.com', 'https://example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/create-verification.md b/docs/examples/1.4.x/client-web/examples/account/create-verification.md new file mode 100644 index 0000000000..4d8446e6ef --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create-verification.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createVerification('https://example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/create.md b/docs/examples/1.4.x/client-web/examples/account/create.md new file mode 100644 index 0000000000..fda1d88e0f --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/create.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.create('[USER_ID]', 'email@example.com', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/delete-identity.md b/docs/examples/1.4.x/client-web/examples/account/delete-identity.md new file mode 100644 index 0000000000..b4230cef33 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/delete-identity.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.deleteIdentity('[IDENTITY_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/delete-session.md b/docs/examples/1.4.x/client-web/examples/account/delete-session.md new file mode 100644 index 0000000000..c342afb2c9 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/delete-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.deleteSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/delete-sessions.md b/docs/examples/1.4.x/client-web/examples/account/delete-sessions.md new file mode 100644 index 0000000000..82133e3845 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/delete-sessions.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.deleteSessions(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/get-prefs.md b/docs/examples/1.4.x/client-web/examples/account/get-prefs.md new file mode 100644 index 0000000000..b98776fd9d --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/get-prefs.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.getPrefs(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/get-session.md b/docs/examples/1.4.x/client-web/examples/account/get-session.md new file mode 100644 index 0000000000..43edd7d08a --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/get-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.getSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/get.md b/docs/examples/1.4.x/client-web/examples/account/get.md new file mode 100644 index 0000000000..878227f019 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/get.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.get(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/list-identities.md b/docs/examples/1.4.x/client-web/examples/account/list-identities.md new file mode 100644 index 0000000000..91e01e221f --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/list-identities.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.listIdentities(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/list-logs.md b/docs/examples/1.4.x/client-web/examples/account/list-logs.md new file mode 100644 index 0000000000..d710f7daa3 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/list-logs.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.listLogs(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/list-sessions.md b/docs/examples/1.4.x/client-web/examples/account/list-sessions.md new file mode 100644 index 0000000000..ce6ec74862 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/list-sessions.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.listSessions(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-email.md b/docs/examples/1.4.x/client-web/examples/account/update-email.md new file mode 100644 index 0000000000..baac3a0ab0 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-email.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateEmail('email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-magic-u-r-l-session.md b/docs/examples/1.4.x/client-web/examples/account/update-magic-u-r-l-session.md new file mode 100644 index 0000000000..c07fee2b14 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-magic-u-r-l-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateMagicURLSession('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-name.md b/docs/examples/1.4.x/client-web/examples/account/update-name.md new file mode 100644 index 0000000000..4af963d5fc --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-name.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateName('[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-password.md b/docs/examples/1.4.x/client-web/examples/account/update-password.md new file mode 100644 index 0000000000..2404a743e7 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-password.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePassword(''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-phone-session.md b/docs/examples/1.4.x/client-web/examples/account/update-phone-session.md new file mode 100644 index 0000000000..b3b29481a9 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-phone-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePhoneSession('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-phone-verification.md b/docs/examples/1.4.x/client-web/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..a274c9b07c --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-phone-verification.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePhoneVerification('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-phone.md b/docs/examples/1.4.x/client-web/examples/account/update-phone.md new file mode 100644 index 0000000000..a1017fc7f4 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-phone.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePhone('+12065550100', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-prefs.md b/docs/examples/1.4.x/client-web/examples/account/update-prefs.md new file mode 100644 index 0000000000..ecceff3158 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-prefs.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePrefs({}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-recovery.md b/docs/examples/1.4.x/client-web/examples/account/update-recovery.md new file mode 100644 index 0000000000..eb78a8a52d --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-recovery.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-session.md b/docs/examples/1.4.x/client-web/examples/account/update-session.md new file mode 100644 index 0000000000..a7a42c663a --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-status.md b/docs/examples/1.4.x/client-web/examples/account/update-status.md new file mode 100644 index 0000000000..9cbe78c5c4 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-status.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateStatus(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/account/update-verification.md b/docs/examples/1.4.x/client-web/examples/account/update-verification.md new file mode 100644 index 0000000000..73338da4df --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/account/update-verification.md @@ -0,0 +1,18 @@ +import { Client, Account } from "appwrite"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateVerification('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/avatars/get-browser.md b/docs/examples/1.4.x/client-web/examples/avatars/get-browser.md new file mode 100644 index 0000000000..0b4c2def00 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/avatars/get-browser.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "appwrite"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getBrowser('aa'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/client-web/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..082ed92b67 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/avatars/get-credit-card.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "appwrite"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getCreditCard('amex'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/avatars/get-favicon.md b/docs/examples/1.4.x/client-web/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..7ee6bd3da2 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/avatars/get-favicon.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "appwrite"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getFavicon('https://example.com'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/avatars/get-flag.md b/docs/examples/1.4.x/client-web/examples/avatars/get-flag.md new file mode 100644 index 0000000000..a43827a1ae --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/avatars/get-flag.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "appwrite"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getFlag('af'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/avatars/get-image.md b/docs/examples/1.4.x/client-web/examples/avatars/get-image.md new file mode 100644 index 0000000000..ea186a1a68 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/avatars/get-image.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "appwrite"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getImage('https://example.com'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/avatars/get-initials.md b/docs/examples/1.4.x/client-web/examples/avatars/get-initials.md new file mode 100644 index 0000000000..7e8c8ec413 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/avatars/get-initials.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "appwrite"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getInitials(); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/avatars/get-q-r.md b/docs/examples/1.4.x/client-web/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..b957084aa1 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/avatars/get-q-r.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "appwrite"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getQR('[TEXT]'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/databases/create-document.md b/docs/examples/1.4.x/client-web/examples/databases/create-document.md new file mode 100644 index 0000000000..92792066ef --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/databases/create-document.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "appwrite"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]', {}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/databases/delete-document.md b/docs/examples/1.4.x/client-web/examples/databases/delete-document.md new file mode 100644 index 0000000000..9e281e7166 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/databases/delete-document.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "appwrite"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.deleteDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/databases/get-document.md b/docs/examples/1.4.x/client-web/examples/databases/get-document.md new file mode 100644 index 0000000000..ea80328794 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/databases/get-document.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "appwrite"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.getDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/databases/list-documents.md b/docs/examples/1.4.x/client-web/examples/databases/list-documents.md new file mode 100644 index 0000000000..4a94c99db3 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/databases/list-documents.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "appwrite"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.listDocuments('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/databases/update-document.md b/docs/examples/1.4.x/client-web/examples/databases/update-document.md new file mode 100644 index 0000000000..cc5ef1cc02 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/databases/update-document.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "appwrite"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/functions/create-execution.md b/docs/examples/1.4.x/client-web/examples/functions/create-execution.md new file mode 100644 index 0000000000..4fc7ac7545 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/functions/create-execution.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "appwrite"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.createExecution('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/functions/get-execution.md b/docs/examples/1.4.x/client-web/examples/functions/get-execution.md new file mode 100644 index 0000000000..2473572c05 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/functions/get-execution.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "appwrite"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.getExecution('[FUNCTION_ID]', '[EXECUTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/functions/list-executions.md b/docs/examples/1.4.x/client-web/examples/functions/list-executions.md new file mode 100644 index 0000000000..481986ef40 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/functions/list-executions.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "appwrite"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.listExecutions('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/graphql/mutation.md b/docs/examples/1.4.x/client-web/examples/graphql/mutation.md new file mode 100644 index 0000000000..1a0b61cd3b --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/graphql/mutation.md @@ -0,0 +1,18 @@ +import { Client, Graphql } from "appwrite"; + +const client = new Client(); + +const graphql = new Graphql(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = graphql.mutation({}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/graphql/query.md b/docs/examples/1.4.x/client-web/examples/graphql/query.md new file mode 100644 index 0000000000..e507fbb5aa --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/graphql/query.md @@ -0,0 +1,18 @@ +import { Client, Graphql } from "appwrite"; + +const client = new Client(); + +const graphql = new Graphql(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = graphql.query({}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/locale/get.md b/docs/examples/1.4.x/client-web/examples/locale/get.md new file mode 100644 index 0000000000..e15bad2ce1 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/locale/get.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "appwrite"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.get(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/locale/list-codes.md b/docs/examples/1.4.x/client-web/examples/locale/list-codes.md new file mode 100644 index 0000000000..a18baa0025 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/locale/list-codes.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "appwrite"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCodes(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/locale/list-continents.md b/docs/examples/1.4.x/client-web/examples/locale/list-continents.md new file mode 100644 index 0000000000..aa3716ef56 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/locale/list-continents.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "appwrite"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listContinents(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/client-web/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..c924b8df4b --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/locale/list-countries-e-u.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "appwrite"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCountriesEU(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/client-web/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..0ab60767da --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/locale/list-countries-phones.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "appwrite"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCountriesPhones(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/locale/list-countries.md b/docs/examples/1.4.x/client-web/examples/locale/list-countries.md new file mode 100644 index 0000000000..ee8c454993 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/locale/list-countries.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "appwrite"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCountries(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/locale/list-currencies.md b/docs/examples/1.4.x/client-web/examples/locale/list-currencies.md new file mode 100644 index 0000000000..dd37b14e25 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/locale/list-currencies.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "appwrite"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCurrencies(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/locale/list-languages.md b/docs/examples/1.4.x/client-web/examples/locale/list-languages.md new file mode 100644 index 0000000000..89ae06d529 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/locale/list-languages.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "appwrite"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listLanguages(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/storage/create-file.md b/docs/examples/1.4.x/client-web/examples/storage/create-file.md new file mode 100644 index 0000000000..0cddb08690 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/storage/create-file.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "appwrite"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.createFile('[BUCKET_ID]', '[FILE_ID]', document.getElementById('uploader').files[0]); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/storage/delete-file.md b/docs/examples/1.4.x/client-web/examples/storage/delete-file.md new file mode 100644 index 0000000000..257d855c32 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/storage/delete-file.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "appwrite"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.deleteFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/storage/get-file-download.md b/docs/examples/1.4.x/client-web/examples/storage/get-file-download.md new file mode 100644 index 0000000000..d8a3542aab --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/storage/get-file-download.md @@ -0,0 +1,14 @@ +import { Client, Storage } from "appwrite"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = storage.getFileDownload('[BUCKET_ID]', '[FILE_ID]'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/storage/get-file-preview.md b/docs/examples/1.4.x/client-web/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..f0588ba7dc --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/storage/get-file-preview.md @@ -0,0 +1,14 @@ +import { Client, Storage } from "appwrite"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = storage.getFilePreview('[BUCKET_ID]', '[FILE_ID]'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/storage/get-file-view.md b/docs/examples/1.4.x/client-web/examples/storage/get-file-view.md new file mode 100644 index 0000000000..5eb2855bef --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/storage/get-file-view.md @@ -0,0 +1,14 @@ +import { Client, Storage } from "appwrite"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = storage.getFileView('[BUCKET_ID]', '[FILE_ID]'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/storage/get-file.md b/docs/examples/1.4.x/client-web/examples/storage/get-file.md new file mode 100644 index 0000000000..6b39ee386e --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/storage/get-file.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "appwrite"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.getFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/storage/list-files.md b/docs/examples/1.4.x/client-web/examples/storage/list-files.md new file mode 100644 index 0000000000..696d4013cd --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/storage/list-files.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "appwrite"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.listFiles('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/storage/update-file.md b/docs/examples/1.4.x/client-web/examples/storage/update-file.md new file mode 100644 index 0000000000..d22a2f6a11 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/storage/update-file.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "appwrite"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.updateFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/create-membership.md b/docs/examples/1.4.x/client-web/examples/teams/create-membership.md new file mode 100644 index 0000000000..fded560d78 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/create-membership.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.createMembership('[TEAM_ID]', [], 'https://example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/create.md b/docs/examples/1.4.x/client-web/examples/teams/create.md new file mode 100644 index 0000000000..c9037e9575 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/create.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.create('[TEAM_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/delete-membership.md b/docs/examples/1.4.x/client-web/examples/teams/delete-membership.md new file mode 100644 index 0000000000..c42d669457 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/delete-membership.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.deleteMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/delete.md b/docs/examples/1.4.x/client-web/examples/teams/delete.md new file mode 100644 index 0000000000..0c99b7aab8 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/delete.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.delete('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/get-membership.md b/docs/examples/1.4.x/client-web/examples/teams/get-membership.md new file mode 100644 index 0000000000..d4d3c5a65d --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/get-membership.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.getMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/get-prefs.md b/docs/examples/1.4.x/client-web/examples/teams/get-prefs.md new file mode 100644 index 0000000000..bcf3f43806 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/get-prefs.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.getPrefs('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/get.md b/docs/examples/1.4.x/client-web/examples/teams/get.md new file mode 100644 index 0000000000..396916ed41 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/get.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.get('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/list-memberships.md b/docs/examples/1.4.x/client-web/examples/teams/list-memberships.md new file mode 100644 index 0000000000..dfa0163037 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/list-memberships.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.listMemberships('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/list.md b/docs/examples/1.4.x/client-web/examples/teams/list.md new file mode 100644 index 0000000000..daf799b95a --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/list.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.list(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/update-membership-status.md b/docs/examples/1.4.x/client-web/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..de1b7f8402 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/update-membership-status.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.updateMembershipStatus('[TEAM_ID]', '[MEMBERSHIP_ID]', '[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/update-membership.md b/docs/examples/1.4.x/client-web/examples/teams/update-membership.md new file mode 100644 index 0000000000..662cb91781 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/update-membership.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.updateMembership('[TEAM_ID]', '[MEMBERSHIP_ID]', []); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/update-name.md b/docs/examples/1.4.x/client-web/examples/teams/update-name.md new file mode 100644 index 0000000000..3159d51c6c --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/update-name.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.updateName('[TEAM_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/client-web/examples/teams/update-prefs.md b/docs/examples/1.4.x/client-web/examples/teams/update-prefs.md new file mode 100644 index 0000000000..36f60b18e7 --- /dev/null +++ b/docs/examples/1.4.x/client-web/examples/teams/update-prefs.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "appwrite"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.updatePrefs('[TEAM_ID]', {}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-cli/examples/account/create-anonymous-session.md b/docs/examples/1.4.x/console-cli/examples/account/create-anonymous-session.md new file mode 100644 index 0000000000..a7eb9c5be3 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create-anonymous-session.md @@ -0,0 +1 @@ +appwrite account createAnonymousSession diff --git a/docs/examples/1.4.x/console-cli/examples/account/create-email-session.md b/docs/examples/1.4.x/console-cli/examples/account/create-email-session.md new file mode 100644 index 0000000000..ec9268c77c --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create-email-session.md @@ -0,0 +1,3 @@ +appwrite account createEmailSession \ + --email email@example.com \ + --password password diff --git a/docs/examples/1.4.x/console-cli/examples/account/create-j-w-t.md b/docs/examples/1.4.x/console-cli/examples/account/create-j-w-t.md new file mode 100644 index 0000000000..7b5337993d --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create-j-w-t.md @@ -0,0 +1 @@ +appwrite account createJWT diff --git a/docs/examples/1.4.x/console-cli/examples/account/create-magic-u-r-l-session.md b/docs/examples/1.4.x/console-cli/examples/account/create-magic-u-r-l-session.md new file mode 100644 index 0000000000..0060f2a892 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create-magic-u-r-l-session.md @@ -0,0 +1,4 @@ +appwrite account createMagicURLSession \ + --userId [USER_ID] \ + --email email@example.com \ + diff --git a/docs/examples/1.4.x/console-cli/examples/account/create-o-auth2session.md b/docs/examples/1.4.x/console-cli/examples/account/create-o-auth2session.md new file mode 100644 index 0000000000..9159b8f25f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create-o-auth2session.md @@ -0,0 +1,5 @@ +appwrite account createOAuth2Session \ + --provider amazon \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/account/create-phone-session.md b/docs/examples/1.4.x/console-cli/examples/account/create-phone-session.md new file mode 100644 index 0000000000..8a9e44f438 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create-phone-session.md @@ -0,0 +1,3 @@ +appwrite account createPhoneSession \ + --userId [USER_ID] \ + --phone +12065550100 diff --git a/docs/examples/1.4.x/console-cli/examples/account/create-phone-verification.md b/docs/examples/1.4.x/console-cli/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..3c4402ba1f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create-phone-verification.md @@ -0,0 +1 @@ +appwrite account createPhoneVerification diff --git a/docs/examples/1.4.x/console-cli/examples/account/create-recovery.md b/docs/examples/1.4.x/console-cli/examples/account/create-recovery.md new file mode 100644 index 0000000000..ea8c145abb --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create-recovery.md @@ -0,0 +1,3 @@ +appwrite account createRecovery \ + --email email@example.com \ + --url https://example.com diff --git a/docs/examples/1.4.x/console-cli/examples/account/create-verification.md b/docs/examples/1.4.x/console-cli/examples/account/create-verification.md new file mode 100644 index 0000000000..402038b4b6 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create-verification.md @@ -0,0 +1,2 @@ +appwrite account createVerification \ + --url https://example.com diff --git a/docs/examples/1.4.x/console-cli/examples/account/create.md b/docs/examples/1.4.x/console-cli/examples/account/create.md new file mode 100644 index 0000000000..8b36dd3771 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/create.md @@ -0,0 +1,5 @@ +appwrite account create \ + --userId [USER_ID] \ + --email email@example.com \ + --password '' \ + diff --git a/docs/examples/1.4.x/console-cli/examples/account/delete-identity.md b/docs/examples/1.4.x/console-cli/examples/account/delete-identity.md new file mode 100644 index 0000000000..2f54abfd10 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/delete-identity.md @@ -0,0 +1,2 @@ +appwrite account deleteIdentity \ + --identityId [IDENTITY_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/account/delete-session.md b/docs/examples/1.4.x/console-cli/examples/account/delete-session.md new file mode 100644 index 0000000000..2c68c1a43b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/delete-session.md @@ -0,0 +1,2 @@ +appwrite account deleteSession \ + --sessionId [SESSION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/account/delete-sessions.md b/docs/examples/1.4.x/console-cli/examples/account/delete-sessions.md new file mode 100644 index 0000000000..dd11877a5d --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/delete-sessions.md @@ -0,0 +1 @@ +appwrite account deleteSessions diff --git a/docs/examples/1.4.x/console-cli/examples/account/get-prefs.md b/docs/examples/1.4.x/console-cli/examples/account/get-prefs.md new file mode 100644 index 0000000000..6569925d99 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/get-prefs.md @@ -0,0 +1 @@ +appwrite account getPrefs diff --git a/docs/examples/1.4.x/console-cli/examples/account/get-session.md b/docs/examples/1.4.x/console-cli/examples/account/get-session.md new file mode 100644 index 0000000000..fac3fca10d --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/get-session.md @@ -0,0 +1,2 @@ +appwrite account getSession \ + --sessionId [SESSION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/account/get.md b/docs/examples/1.4.x/console-cli/examples/account/get.md new file mode 100644 index 0000000000..c8b46e34c7 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/get.md @@ -0,0 +1 @@ +appwrite account get diff --git a/docs/examples/1.4.x/console-cli/examples/account/list-identities.md b/docs/examples/1.4.x/console-cli/examples/account/list-identities.md new file mode 100644 index 0000000000..877b443ea8 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/list-identities.md @@ -0,0 +1,2 @@ +appwrite account listIdentities \ + diff --git a/docs/examples/1.4.x/console-cli/examples/account/list-logs.md b/docs/examples/1.4.x/console-cli/examples/account/list-logs.md new file mode 100644 index 0000000000..e92f49063a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/list-logs.md @@ -0,0 +1,2 @@ +appwrite account listLogs \ + diff --git a/docs/examples/1.4.x/console-cli/examples/account/list-sessions.md b/docs/examples/1.4.x/console-cli/examples/account/list-sessions.md new file mode 100644 index 0000000000..87cbab0f66 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/list-sessions.md @@ -0,0 +1 @@ +appwrite account listSessions diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-email.md b/docs/examples/1.4.x/console-cli/examples/account/update-email.md new file mode 100644 index 0000000000..81938ff3a9 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-email.md @@ -0,0 +1,3 @@ +appwrite account updateEmail \ + --email email@example.com \ + --password password diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-magic-u-r-l-session.md b/docs/examples/1.4.x/console-cli/examples/account/update-magic-u-r-l-session.md new file mode 100644 index 0000000000..1411370123 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-magic-u-r-l-session.md @@ -0,0 +1,3 @@ +appwrite account updateMagicURLSession \ + --userId [USER_ID] \ + --secret [SECRET] diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-name.md b/docs/examples/1.4.x/console-cli/examples/account/update-name.md new file mode 100644 index 0000000000..f4acb58db6 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-name.md @@ -0,0 +1,2 @@ +appwrite account updateName \ + --name [NAME] diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-password.md b/docs/examples/1.4.x/console-cli/examples/account/update-password.md new file mode 100644 index 0000000000..340baec562 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-password.md @@ -0,0 +1,3 @@ +appwrite account updatePassword \ + --password '' \ + diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-phone-session.md b/docs/examples/1.4.x/console-cli/examples/account/update-phone-session.md new file mode 100644 index 0000000000..b2ee53a18c --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-phone-session.md @@ -0,0 +1,3 @@ +appwrite account updatePhoneSession \ + --userId [USER_ID] \ + --secret [SECRET] diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-phone-verification.md b/docs/examples/1.4.x/console-cli/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..5e0dd45617 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-phone-verification.md @@ -0,0 +1,3 @@ +appwrite account updatePhoneVerification \ + --userId [USER_ID] \ + --secret [SECRET] diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-phone.md b/docs/examples/1.4.x/console-cli/examples/account/update-phone.md new file mode 100644 index 0000000000..93a619a801 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-phone.md @@ -0,0 +1,3 @@ +appwrite account updatePhone \ + --phone +12065550100 \ + --password password diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-prefs.md b/docs/examples/1.4.x/console-cli/examples/account/update-prefs.md new file mode 100644 index 0000000000..568ac66e48 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-prefs.md @@ -0,0 +1,2 @@ +appwrite account updatePrefs \ + --prefs '{ "key": "value" }' diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-recovery.md b/docs/examples/1.4.x/console-cli/examples/account/update-recovery.md new file mode 100644 index 0000000000..7825aac8f0 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-recovery.md @@ -0,0 +1,5 @@ +appwrite account updateRecovery \ + --userId [USER_ID] \ + --secret [SECRET] \ + --password password \ + --passwordAgain password diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-session.md b/docs/examples/1.4.x/console-cli/examples/account/update-session.md new file mode 100644 index 0000000000..56f74565de --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-session.md @@ -0,0 +1,2 @@ +appwrite account updateSession \ + --sessionId [SESSION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-status.md b/docs/examples/1.4.x/console-cli/examples/account/update-status.md new file mode 100644 index 0000000000..8886dbbc6a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-status.md @@ -0,0 +1 @@ +appwrite account updateStatus diff --git a/docs/examples/1.4.x/console-cli/examples/account/update-verification.md b/docs/examples/1.4.x/console-cli/examples/account/update-verification.md new file mode 100644 index 0000000000..ff420b5895 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/account/update-verification.md @@ -0,0 +1,3 @@ +appwrite account updateVerification \ + --userId [USER_ID] \ + --secret [SECRET] diff --git a/docs/examples/1.4.x/console-cli/examples/assistant/chat.md b/docs/examples/1.4.x/console-cli/examples/assistant/chat.md new file mode 100644 index 0000000000..3ddd759702 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/assistant/chat.md @@ -0,0 +1,2 @@ +appwrite assistant chat \ + --prompt [PROMPT] diff --git a/docs/examples/1.4.x/console-cli/examples/avatars/get-browser.md b/docs/examples/1.4.x/console-cli/examples/avatars/get-browser.md new file mode 100644 index 0000000000..6b4f0b8007 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/avatars/get-browser.md @@ -0,0 +1,5 @@ +appwrite avatars getBrowser \ + --code aa \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/console-cli/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..365568ba19 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/avatars/get-credit-card.md @@ -0,0 +1,5 @@ +appwrite avatars getCreditCard \ + --code amex \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/avatars/get-favicon.md b/docs/examples/1.4.x/console-cli/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..c658f1a483 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/avatars/get-favicon.md @@ -0,0 +1,2 @@ +appwrite avatars getFavicon \ + --url https://example.com diff --git a/docs/examples/1.4.x/console-cli/examples/avatars/get-flag.md b/docs/examples/1.4.x/console-cli/examples/avatars/get-flag.md new file mode 100644 index 0000000000..9f11fef840 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/avatars/get-flag.md @@ -0,0 +1,5 @@ +appwrite avatars getFlag \ + --code af \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/avatars/get-image.md b/docs/examples/1.4.x/console-cli/examples/avatars/get-image.md new file mode 100644 index 0000000000..7df150610c --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/avatars/get-image.md @@ -0,0 +1,4 @@ +appwrite avatars getImage \ + --url https://example.com \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/avatars/get-initials.md b/docs/examples/1.4.x/console-cli/examples/avatars/get-initials.md new file mode 100644 index 0000000000..b0b3da71c9 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/avatars/get-initials.md @@ -0,0 +1,5 @@ +appwrite avatars getInitials \ + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/avatars/get-q-r.md b/docs/examples/1.4.x/console-cli/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..855f33920a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/avatars/get-q-r.md @@ -0,0 +1,5 @@ +appwrite avatars getQR \ + --text [TEXT] \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/console/variables.md b/docs/examples/1.4.x/console-cli/examples/console/variables.md new file mode 100644 index 0000000000..1c67cf5ad8 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/console/variables.md @@ -0,0 +1 @@ +appwrite console variables diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..4a5b036b21 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-boolean-attribute.md @@ -0,0 +1,7 @@ +appwrite databases createBooleanAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-collection.md b/docs/examples/1.4.x/console-cli/examples/databases/create-collection.md new file mode 100644 index 0000000000..4e349ebb98 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-collection.md @@ -0,0 +1,7 @@ +appwrite databases createCollection \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --name [NAME] \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..95b3f3b27f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-datetime-attribute.md @@ -0,0 +1,7 @@ +appwrite databases createDatetimeAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-document.md b/docs/examples/1.4.x/console-cli/examples/databases/create-document.md new file mode 100644 index 0000000000..6944ac664a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-document.md @@ -0,0 +1,6 @@ +appwrite databases createDocument \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --documentId [DOCUMENT_ID] \ + --data '{ "key": "value" }' \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..d26ca2acbd --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-email-attribute.md @@ -0,0 +1,7 @@ +appwrite databases createEmailAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..5bd2fccbfc --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-enum-attribute.md @@ -0,0 +1,8 @@ +appwrite databases createEnumAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --elements one two three \ + --required false \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..b0bb3776de --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-float-attribute.md @@ -0,0 +1,9 @@ +appwrite databases createFloatAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-index.md b/docs/examples/1.4.x/console-cli/examples/databases/create-index.md new file mode 100644 index 0000000000..27c8dfecf5 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-index.md @@ -0,0 +1,7 @@ +appwrite databases createIndex \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --type key \ + --attributes one two three \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..76b5aad455 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-integer-attribute.md @@ -0,0 +1,9 @@ +appwrite databases createIntegerAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..c9281dd316 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-ip-attribute.md @@ -0,0 +1,7 @@ +appwrite databases createIpAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..2de630e62f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-relationship-attribute.md @@ -0,0 +1,9 @@ +appwrite databases createRelationshipAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --relatedCollectionId [RELATED_COLLECTION_ID] \ + --type oneToOne \ + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..fb90147192 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-string-attribute.md @@ -0,0 +1,9 @@ +appwrite databases createStringAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --size 1 \ + --required false \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..d204de0c1d --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create-url-attribute.md @@ -0,0 +1,7 @@ +appwrite databases createUrlAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/create.md b/docs/examples/1.4.x/console-cli/examples/databases/create.md new file mode 100644 index 0000000000..d32a9f431b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/create.md @@ -0,0 +1,4 @@ +appwrite databases create \ + --databaseId [DATABASE_ID] \ + --name [NAME] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/delete-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..3db88fbfba --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/delete-attribute.md @@ -0,0 +1,4 @@ +appwrite databases deleteAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' diff --git a/docs/examples/1.4.x/console-cli/examples/databases/delete-collection.md b/docs/examples/1.4.x/console-cli/examples/databases/delete-collection.md new file mode 100644 index 0000000000..f1941d4bf0 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/delete-collection.md @@ -0,0 +1,3 @@ +appwrite databases deleteCollection \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/databases/delete-document.md b/docs/examples/1.4.x/console-cli/examples/databases/delete-document.md new file mode 100644 index 0000000000..9dc46f7dc6 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/delete-document.md @@ -0,0 +1,4 @@ +appwrite databases deleteDocument \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --documentId [DOCUMENT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/databases/delete-index.md b/docs/examples/1.4.x/console-cli/examples/databases/delete-index.md new file mode 100644 index 0000000000..8e7194febf --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/delete-index.md @@ -0,0 +1,4 @@ +appwrite databases deleteIndex \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' diff --git a/docs/examples/1.4.x/console-cli/examples/databases/delete.md b/docs/examples/1.4.x/console-cli/examples/databases/delete.md new file mode 100644 index 0000000000..851cc8deb2 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/delete.md @@ -0,0 +1,2 @@ +appwrite databases delete \ + --databaseId [DATABASE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/databases/get-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/get-attribute.md new file mode 100644 index 0000000000..3dbb2c44fe --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/get-attribute.md @@ -0,0 +1,4 @@ +appwrite databases getAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' diff --git a/docs/examples/1.4.x/console-cli/examples/databases/get-collection-usage.md b/docs/examples/1.4.x/console-cli/examples/databases/get-collection-usage.md new file mode 100644 index 0000000000..de8f78665a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/get-collection-usage.md @@ -0,0 +1,4 @@ +appwrite databases getCollectionUsage \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/get-collection.md b/docs/examples/1.4.x/console-cli/examples/databases/get-collection.md new file mode 100644 index 0000000000..a4f08fbd45 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/get-collection.md @@ -0,0 +1,3 @@ +appwrite databases getCollection \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/databases/get-database-usage.md b/docs/examples/1.4.x/console-cli/examples/databases/get-database-usage.md new file mode 100644 index 0000000000..e4d3e4df3a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/get-database-usage.md @@ -0,0 +1,3 @@ +appwrite databases getDatabaseUsage \ + --databaseId [DATABASE_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/get-document.md b/docs/examples/1.4.x/console-cli/examples/databases/get-document.md new file mode 100644 index 0000000000..c84aee31de --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/get-document.md @@ -0,0 +1,5 @@ +appwrite databases getDocument \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --documentId [DOCUMENT_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/get-index.md b/docs/examples/1.4.x/console-cli/examples/databases/get-index.md new file mode 100644 index 0000000000..b7537897ac --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/get-index.md @@ -0,0 +1,4 @@ +appwrite databases getIndex \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' diff --git a/docs/examples/1.4.x/console-cli/examples/databases/get-usage.md b/docs/examples/1.4.x/console-cli/examples/databases/get-usage.md new file mode 100644 index 0000000000..53c85fc849 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/get-usage.md @@ -0,0 +1,2 @@ +appwrite databases getUsage \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/get.md b/docs/examples/1.4.x/console-cli/examples/databases/get.md new file mode 100644 index 0000000000..feb9a3c859 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/get.md @@ -0,0 +1,2 @@ +appwrite databases get \ + --databaseId [DATABASE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/databases/list-attributes.md b/docs/examples/1.4.x/console-cli/examples/databases/list-attributes.md new file mode 100644 index 0000000000..1332e27689 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/list-attributes.md @@ -0,0 +1,4 @@ +appwrite databases listAttributes \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/list-collection-logs.md b/docs/examples/1.4.x/console-cli/examples/databases/list-collection-logs.md new file mode 100644 index 0000000000..fa2f062797 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/list-collection-logs.md @@ -0,0 +1,4 @@ +appwrite databases listCollectionLogs \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/list-collections.md b/docs/examples/1.4.x/console-cli/examples/databases/list-collections.md new file mode 100644 index 0000000000..6517ebbc16 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/list-collections.md @@ -0,0 +1,4 @@ +appwrite databases listCollections \ + --databaseId [DATABASE_ID] \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/list-document-logs.md b/docs/examples/1.4.x/console-cli/examples/databases/list-document-logs.md new file mode 100644 index 0000000000..0ab0125d0d --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/list-document-logs.md @@ -0,0 +1,5 @@ +appwrite databases listDocumentLogs \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --documentId [DOCUMENT_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/list-documents.md b/docs/examples/1.4.x/console-cli/examples/databases/list-documents.md new file mode 100644 index 0000000000..08dcbdf584 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/list-documents.md @@ -0,0 +1,4 @@ +appwrite databases listDocuments \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/list-indexes.md b/docs/examples/1.4.x/console-cli/examples/databases/list-indexes.md new file mode 100644 index 0000000000..349b3cba88 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/list-indexes.md @@ -0,0 +1,4 @@ +appwrite databases listIndexes \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/list-logs.md b/docs/examples/1.4.x/console-cli/examples/databases/list-logs.md new file mode 100644 index 0000000000..f1c44f1f74 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/list-logs.md @@ -0,0 +1,3 @@ +appwrite databases listLogs \ + --databaseId [DATABASE_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/list.md b/docs/examples/1.4.x/console-cli/examples/databases/list.md new file mode 100644 index 0000000000..e723bc32ec --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/list.md @@ -0,0 +1,3 @@ +appwrite databases list \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..ed4fc54045 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-boolean-attribute.md @@ -0,0 +1,6 @@ +appwrite databases updateBooleanAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + --default false diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-collection.md b/docs/examples/1.4.x/console-cli/examples/databases/update-collection.md new file mode 100644 index 0000000000..027d7cc830 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-collection.md @@ -0,0 +1,7 @@ +appwrite databases updateCollection \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --name [NAME] \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..9cb22edb6d --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-datetime-attribute.md @@ -0,0 +1,6 @@ +appwrite databases updateDatetimeAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + --default '' diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-document.md b/docs/examples/1.4.x/console-cli/examples/databases/update-document.md new file mode 100644 index 0000000000..d281fe2efe --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-document.md @@ -0,0 +1,6 @@ +appwrite databases updateDocument \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --documentId [DOCUMENT_ID] \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..8e148e93c8 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-email-attribute.md @@ -0,0 +1,6 @@ +appwrite databases updateEmailAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + --default email@example.com diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..c77c3c0685 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-enum-attribute.md @@ -0,0 +1,7 @@ +appwrite databases updateEnumAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --elements one two three \ + --required false \ + --default [DEFAULT] diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..a28af54a12 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-float-attribute.md @@ -0,0 +1,8 @@ +appwrite databases updateFloatAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + --min null \ + --max null \ + --default null diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..f534a75087 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-integer-attribute.md @@ -0,0 +1,8 @@ +appwrite databases updateIntegerAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + --min null \ + --max null \ + --default null diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..0802bd7914 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-ip-attribute.md @@ -0,0 +1,6 @@ +appwrite databases updateIpAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + --default '' diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..ead7e1e486 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-relationship-attribute.md @@ -0,0 +1,5 @@ +appwrite databases updateRelationshipAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..93a61e1163 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-string-attribute.md @@ -0,0 +1,6 @@ +appwrite databases updateStringAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + --default [DEFAULT] diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/console-cli/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..dba3779ac3 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update-url-attribute.md @@ -0,0 +1,6 @@ +appwrite databases updateUrlAttribute \ + --databaseId [DATABASE_ID] \ + --collectionId [COLLECTION_ID] \ + --key '' \ + --required false \ + --default https://example.com diff --git a/docs/examples/1.4.x/console-cli/examples/databases/update.md b/docs/examples/1.4.x/console-cli/examples/databases/update.md new file mode 100644 index 0000000000..b66d8bc808 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/databases/update.md @@ -0,0 +1,4 @@ +appwrite databases update \ + --databaseId [DATABASE_ID] \ + --name [NAME] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/create-build.md b/docs/examples/1.4.x/console-cli/examples/functions/create-build.md new file mode 100644 index 0000000000..efbf91ceb7 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/create-build.md @@ -0,0 +1,4 @@ +appwrite functions createBuild \ + --functionId [FUNCTION_ID] \ + --deploymentId [DEPLOYMENT_ID] \ + --buildId [BUILD_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/create-deployment.md b/docs/examples/1.4.x/console-cli/examples/functions/create-deployment.md new file mode 100644 index 0000000000..8682bc33ad --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/create-deployment.md @@ -0,0 +1,6 @@ +appwrite functions createDeployment \ + --functionId [FUNCTION_ID] \ + --code 'path/to/file.png' \ + --activate false \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/create-execution.md b/docs/examples/1.4.x/console-cli/examples/functions/create-execution.md new file mode 100644 index 0000000000..ef8bff77ef --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/create-execution.md @@ -0,0 +1,7 @@ +appwrite functions createExecution \ + --functionId [FUNCTION_ID] \ + + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/create-variable.md b/docs/examples/1.4.x/console-cli/examples/functions/create-variable.md new file mode 100644 index 0000000000..79b559fa6e --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/create-variable.md @@ -0,0 +1,4 @@ +appwrite functions createVariable \ + --functionId [FUNCTION_ID] \ + --key [KEY] \ + --value [VALUE] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/create.md b/docs/examples/1.4.x/console-cli/examples/functions/create.md new file mode 100644 index 0000000000..fa5c159018 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/create.md @@ -0,0 +1,21 @@ +appwrite functions create \ + --functionId [FUNCTION_ID] \ + --name [NAME] \ + --runtime node-14.5 \ + + + + + + + + + + + + + + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/delete-deployment.md b/docs/examples/1.4.x/console-cli/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..2033b846ce --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/delete-deployment.md @@ -0,0 +1,3 @@ +appwrite functions deleteDeployment \ + --functionId [FUNCTION_ID] \ + --deploymentId [DEPLOYMENT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/delete-variable.md b/docs/examples/1.4.x/console-cli/examples/functions/delete-variable.md new file mode 100644 index 0000000000..cb556644ca --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/delete-variable.md @@ -0,0 +1,3 @@ +appwrite functions deleteVariable \ + --functionId [FUNCTION_ID] \ + --variableId [VARIABLE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/delete.md b/docs/examples/1.4.x/console-cli/examples/functions/delete.md new file mode 100644 index 0000000000..b3ce304016 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/delete.md @@ -0,0 +1,2 @@ +appwrite functions delete \ + --functionId [FUNCTION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/download-deployment.md b/docs/examples/1.4.x/console-cli/examples/functions/download-deployment.md new file mode 100644 index 0000000000..51621c097f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/download-deployment.md @@ -0,0 +1,3 @@ +appwrite functions downloadDeployment \ + --functionId [FUNCTION_ID] \ + --deploymentId [DEPLOYMENT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/get-deployment.md b/docs/examples/1.4.x/console-cli/examples/functions/get-deployment.md new file mode 100644 index 0000000000..668bcde4fe --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/get-deployment.md @@ -0,0 +1,3 @@ +appwrite functions getDeployment \ + --functionId [FUNCTION_ID] \ + --deploymentId [DEPLOYMENT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/get-execution.md b/docs/examples/1.4.x/console-cli/examples/functions/get-execution.md new file mode 100644 index 0000000000..b6a974766d --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/get-execution.md @@ -0,0 +1,3 @@ +appwrite functions getExecution \ + --functionId [FUNCTION_ID] \ + --executionId [EXECUTION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/get-function-usage.md b/docs/examples/1.4.x/console-cli/examples/functions/get-function-usage.md new file mode 100644 index 0000000000..71129c386f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/get-function-usage.md @@ -0,0 +1,3 @@ +appwrite functions getFunctionUsage \ + --functionId [FUNCTION_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/get-usage.md b/docs/examples/1.4.x/console-cli/examples/functions/get-usage.md new file mode 100644 index 0000000000..a3fe7c38de --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/get-usage.md @@ -0,0 +1,2 @@ +appwrite functions getUsage \ + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/get-variable.md b/docs/examples/1.4.x/console-cli/examples/functions/get-variable.md new file mode 100644 index 0000000000..8a8bd4832e --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/get-variable.md @@ -0,0 +1,3 @@ +appwrite functions getVariable \ + --functionId [FUNCTION_ID] \ + --variableId [VARIABLE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/get.md b/docs/examples/1.4.x/console-cli/examples/functions/get.md new file mode 100644 index 0000000000..0332c4a6aa --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/get.md @@ -0,0 +1,2 @@ +appwrite functions get \ + --functionId [FUNCTION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/list-deployments.md b/docs/examples/1.4.x/console-cli/examples/functions/list-deployments.md new file mode 100644 index 0000000000..5ffd5b909f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/list-deployments.md @@ -0,0 +1,4 @@ +appwrite functions listDeployments \ + --functionId [FUNCTION_ID] \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/list-executions.md b/docs/examples/1.4.x/console-cli/examples/functions/list-executions.md new file mode 100644 index 0000000000..894cb04426 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/list-executions.md @@ -0,0 +1,4 @@ +appwrite functions listExecutions \ + --functionId [FUNCTION_ID] \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/list-runtimes.md b/docs/examples/1.4.x/console-cli/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..15dc019c44 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/list-runtimes.md @@ -0,0 +1 @@ +appwrite functions listRuntimes diff --git a/docs/examples/1.4.x/console-cli/examples/functions/list-variables.md b/docs/examples/1.4.x/console-cli/examples/functions/list-variables.md new file mode 100644 index 0000000000..3e4df28a86 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/list-variables.md @@ -0,0 +1,2 @@ +appwrite functions listVariables \ + --functionId [FUNCTION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/list.md b/docs/examples/1.4.x/console-cli/examples/functions/list.md new file mode 100644 index 0000000000..3b7551266e --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/list.md @@ -0,0 +1,3 @@ +appwrite functions list \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/update-deployment.md b/docs/examples/1.4.x/console-cli/examples/functions/update-deployment.md new file mode 100644 index 0000000000..7276b3e780 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/update-deployment.md @@ -0,0 +1,3 @@ +appwrite functions updateDeployment \ + --functionId [FUNCTION_ID] \ + --deploymentId [DEPLOYMENT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/functions/update-variable.md b/docs/examples/1.4.x/console-cli/examples/functions/update-variable.md new file mode 100644 index 0000000000..56e9ebeb00 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/update-variable.md @@ -0,0 +1,5 @@ +appwrite functions updateVariable \ + --functionId [FUNCTION_ID] \ + --variableId [VARIABLE_ID] \ + --key [KEY] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/functions/update.md b/docs/examples/1.4.x/console-cli/examples/functions/update.md new file mode 100644 index 0000000000..d63f64302a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/functions/update.md @@ -0,0 +1,17 @@ +appwrite functions update \ + --functionId [FUNCTION_ID] \ + --name [NAME] \ + --runtime node-14.5 \ + + + + + + + + + + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/graphql/mutation.md b/docs/examples/1.4.x/console-cli/examples/graphql/mutation.md new file mode 100644 index 0000000000..f6127a175c --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/graphql/mutation.md @@ -0,0 +1,2 @@ +appwrite graphql mutation \ + --query '{ "key": "value" }' diff --git a/docs/examples/1.4.x/console-cli/examples/graphql/query.md b/docs/examples/1.4.x/console-cli/examples/graphql/query.md new file mode 100644 index 0000000000..1d84bcaa6a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/graphql/query.md @@ -0,0 +1,2 @@ +appwrite graphql query \ + --query '{ "key": "value" }' diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-antivirus.md b/docs/examples/1.4.x/console-cli/examples/health/get-antivirus.md new file mode 100644 index 0000000000..96dd7e78b2 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-antivirus.md @@ -0,0 +1 @@ +appwrite health getAntivirus diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-cache.md b/docs/examples/1.4.x/console-cli/examples/health/get-cache.md new file mode 100644 index 0000000000..ad1111ccf0 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-cache.md @@ -0,0 +1 @@ +appwrite health getCache diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-d-b.md b/docs/examples/1.4.x/console-cli/examples/health/get-d-b.md new file mode 100644 index 0000000000..b0ea2d3eac --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-d-b.md @@ -0,0 +1 @@ +appwrite health getDB diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-pub-sub.md b/docs/examples/1.4.x/console-cli/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..aa1773b35b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-pub-sub.md @@ -0,0 +1 @@ +appwrite health getPubSub diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/console-cli/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..7cae239389 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-queue-certificates.md @@ -0,0 +1 @@ +appwrite health getQueueCertificates diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-queue-functions.md b/docs/examples/1.4.x/console-cli/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..9edfddac62 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-queue-functions.md @@ -0,0 +1 @@ +appwrite health getQueueFunctions diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-queue-logs.md b/docs/examples/1.4.x/console-cli/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..9a0974934b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-queue-logs.md @@ -0,0 +1 @@ +appwrite health getQueueLogs diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/console-cli/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..f38eaa4e77 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-queue-webhooks.md @@ -0,0 +1 @@ +appwrite health getQueueWebhooks diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-queue.md b/docs/examples/1.4.x/console-cli/examples/health/get-queue.md new file mode 100644 index 0000000000..24ad16cbaa --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-queue.md @@ -0,0 +1 @@ +appwrite health getQueue diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-storage-local.md b/docs/examples/1.4.x/console-cli/examples/health/get-storage-local.md new file mode 100644 index 0000000000..b5df39fae0 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-storage-local.md @@ -0,0 +1 @@ +appwrite health getStorageLocal diff --git a/docs/examples/1.4.x/console-cli/examples/health/get-time.md b/docs/examples/1.4.x/console-cli/examples/health/get-time.md new file mode 100644 index 0000000000..067e5daf9e --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get-time.md @@ -0,0 +1 @@ +appwrite health getTime diff --git a/docs/examples/1.4.x/console-cli/examples/health/get.md b/docs/examples/1.4.x/console-cli/examples/health/get.md new file mode 100644 index 0000000000..94c08e5aa3 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/health/get.md @@ -0,0 +1 @@ +appwrite health get diff --git a/docs/examples/1.4.x/console-cli/examples/locale/get.md b/docs/examples/1.4.x/console-cli/examples/locale/get.md new file mode 100644 index 0000000000..2002a06c20 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/locale/get.md @@ -0,0 +1 @@ +appwrite locale get diff --git a/docs/examples/1.4.x/console-cli/examples/locale/list-codes.md b/docs/examples/1.4.x/console-cli/examples/locale/list-codes.md new file mode 100644 index 0000000000..5586d1566c --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/locale/list-codes.md @@ -0,0 +1 @@ +appwrite locale listCodes diff --git a/docs/examples/1.4.x/console-cli/examples/locale/list-continents.md b/docs/examples/1.4.x/console-cli/examples/locale/list-continents.md new file mode 100644 index 0000000000..775af5d9df --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/locale/list-continents.md @@ -0,0 +1 @@ +appwrite locale listContinents diff --git a/docs/examples/1.4.x/console-cli/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/console-cli/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..43b7eff7ad --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/locale/list-countries-e-u.md @@ -0,0 +1 @@ +appwrite locale listCountriesEU diff --git a/docs/examples/1.4.x/console-cli/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/console-cli/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..072516bf71 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/locale/list-countries-phones.md @@ -0,0 +1 @@ +appwrite locale listCountriesPhones diff --git a/docs/examples/1.4.x/console-cli/examples/locale/list-countries.md b/docs/examples/1.4.x/console-cli/examples/locale/list-countries.md new file mode 100644 index 0000000000..ee7101df68 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/locale/list-countries.md @@ -0,0 +1 @@ +appwrite locale listCountries diff --git a/docs/examples/1.4.x/console-cli/examples/locale/list-currencies.md b/docs/examples/1.4.x/console-cli/examples/locale/list-currencies.md new file mode 100644 index 0000000000..01b1b3c4b2 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/locale/list-currencies.md @@ -0,0 +1 @@ +appwrite locale listCurrencies diff --git a/docs/examples/1.4.x/console-cli/examples/locale/list-languages.md b/docs/examples/1.4.x/console-cli/examples/locale/list-languages.md new file mode 100644 index 0000000000..d47622c570 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/locale/list-languages.md @@ -0,0 +1 @@ +appwrite locale listLanguages diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/create-appwrite-migration.md b/docs/examples/1.4.x/console-cli/examples/migrations/create-appwrite-migration.md new file mode 100644 index 0000000000..874abb5eed --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/create-appwrite-migration.md @@ -0,0 +1,5 @@ +appwrite migrations createAppwriteMigration \ + --resources one two three \ + --endpoint https://example.com \ + --projectId [PROJECT_ID] \ + --apiKey [API_KEY] diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/create-firebase-migration.md b/docs/examples/1.4.x/console-cli/examples/migrations/create-firebase-migration.md new file mode 100644 index 0000000000..a87097c054 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/create-firebase-migration.md @@ -0,0 +1,3 @@ +appwrite migrations createFirebaseMigration \ + --resources one two three \ + --serviceAccount [SERVICE_ACCOUNT] diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/create-firebase-o-auth-migration.md b/docs/examples/1.4.x/console-cli/examples/migrations/create-firebase-o-auth-migration.md new file mode 100644 index 0000000000..d85e1e0199 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/create-firebase-o-auth-migration.md @@ -0,0 +1,3 @@ +appwrite migrations createFirebaseOAuthMigration \ + --resources one two three \ + --projectId [PROJECT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/create-n-host-migration.md b/docs/examples/1.4.x/console-cli/examples/migrations/create-n-host-migration.md new file mode 100644 index 0000000000..896f5a2801 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/create-n-host-migration.md @@ -0,0 +1,9 @@ +appwrite migrations createNHostMigration \ + --resources one two three \ + --subdomain [SUBDOMAIN] \ + --region [REGION] \ + --adminSecret [ADMIN_SECRET] \ + --database [DATABASE] \ + --username [USERNAME] \ + --password [PASSWORD] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/create-supabase-migration.md b/docs/examples/1.4.x/console-cli/examples/migrations/create-supabase-migration.md new file mode 100644 index 0000000000..49eede05c4 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/create-supabase-migration.md @@ -0,0 +1,8 @@ +appwrite migrations createSupabaseMigration \ + --resources one two three \ + --endpoint https://example.com \ + --apiKey [API_KEY] \ + --databaseHost [DATABASE_HOST] \ + --username [USERNAME] \ + --password [PASSWORD] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/delete-firebase-auth.md b/docs/examples/1.4.x/console-cli/examples/migrations/delete-firebase-auth.md new file mode 100644 index 0000000000..d58abd9878 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/delete-firebase-auth.md @@ -0,0 +1 @@ +appwrite migrations deleteFirebaseAuth diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/delete.md b/docs/examples/1.4.x/console-cli/examples/migrations/delete.md new file mode 100644 index 0000000000..9447d97fed --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/delete.md @@ -0,0 +1,2 @@ +appwrite migrations delete \ + --migrationId [MIGRATION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/get-appwrite-report.md b/docs/examples/1.4.x/console-cli/examples/migrations/get-appwrite-report.md new file mode 100644 index 0000000000..bdc88573a2 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/get-appwrite-report.md @@ -0,0 +1,5 @@ +appwrite migrations getAppwriteReport \ + --resources one two three \ + --endpoint https://example.com \ + --projectID [PROJECT_ID] \ + --key [KEY] diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/get-firebase-report-o-auth.md b/docs/examples/1.4.x/console-cli/examples/migrations/get-firebase-report-o-auth.md new file mode 100644 index 0000000000..2faa1d2e87 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/get-firebase-report-o-auth.md @@ -0,0 +1,3 @@ +appwrite migrations getFirebaseReportOAuth \ + --resources one two three \ + --projectId [PROJECT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/get-firebase-report.md b/docs/examples/1.4.x/console-cli/examples/migrations/get-firebase-report.md new file mode 100644 index 0000000000..c8bfc0b382 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/get-firebase-report.md @@ -0,0 +1,3 @@ +appwrite migrations getFirebaseReport \ + --resources one two three \ + --serviceAccount [SERVICE_ACCOUNT] diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/get-n-host-report.md b/docs/examples/1.4.x/console-cli/examples/migrations/get-n-host-report.md new file mode 100644 index 0000000000..36613b13b2 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/get-n-host-report.md @@ -0,0 +1,9 @@ +appwrite migrations getNHostReport \ + --resources one two three \ + --subdomain [SUBDOMAIN] \ + --region [REGION] \ + --adminSecret [ADMIN_SECRET] \ + --database [DATABASE] \ + --username [USERNAME] \ + --password [PASSWORD] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/get-supabase-report.md b/docs/examples/1.4.x/console-cli/examples/migrations/get-supabase-report.md new file mode 100644 index 0000000000..3ef3874a67 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/get-supabase-report.md @@ -0,0 +1,8 @@ +appwrite migrations getSupabaseReport \ + --resources one two three \ + --endpoint https://example.com \ + --apiKey [API_KEY] \ + --databaseHost [DATABASE_HOST] \ + --username [USERNAME] \ + --password [PASSWORD] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/get.md b/docs/examples/1.4.x/console-cli/examples/migrations/get.md new file mode 100644 index 0000000000..5f823b675d --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/get.md @@ -0,0 +1,2 @@ +appwrite migrations get \ + --migrationId [MIGRATION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/list-firebase-projects.md b/docs/examples/1.4.x/console-cli/examples/migrations/list-firebase-projects.md new file mode 100644 index 0000000000..a0e59713eb --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/list-firebase-projects.md @@ -0,0 +1 @@ +appwrite migrations listFirebaseProjects diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/list.md b/docs/examples/1.4.x/console-cli/examples/migrations/list.md new file mode 100644 index 0000000000..c120a61e80 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/list.md @@ -0,0 +1,3 @@ +appwrite migrations list \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/migrations/retry.md b/docs/examples/1.4.x/console-cli/examples/migrations/retry.md new file mode 100644 index 0000000000..848bf4d0ec --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/migrations/retry.md @@ -0,0 +1,2 @@ +appwrite migrations retry \ + --migrationId [MIGRATION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/project/create-variable.md b/docs/examples/1.4.x/console-cli/examples/project/create-variable.md new file mode 100644 index 0000000000..800c8bdca6 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/project/create-variable.md @@ -0,0 +1,3 @@ +appwrite project createVariable \ + --key [KEY] \ + --value [VALUE] diff --git a/docs/examples/1.4.x/console-cli/examples/project/delete-variable.md b/docs/examples/1.4.x/console-cli/examples/project/delete-variable.md new file mode 100644 index 0000000000..e71af4851a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/project/delete-variable.md @@ -0,0 +1,2 @@ +appwrite project deleteVariable \ + --variableId [VARIABLE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/project/get-usage.md b/docs/examples/1.4.x/console-cli/examples/project/get-usage.md new file mode 100644 index 0000000000..e2024f3f6e --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/project/get-usage.md @@ -0,0 +1,2 @@ +appwrite project getUsage \ + diff --git a/docs/examples/1.4.x/console-cli/examples/project/get-variable.md b/docs/examples/1.4.x/console-cli/examples/project/get-variable.md new file mode 100644 index 0000000000..bf4d97f46e --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/project/get-variable.md @@ -0,0 +1,2 @@ +appwrite project getVariable \ + --variableId [VARIABLE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/project/list-variables.md b/docs/examples/1.4.x/console-cli/examples/project/list-variables.md new file mode 100644 index 0000000000..bd26c7db6b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/project/list-variables.md @@ -0,0 +1 @@ +appwrite project listVariables diff --git a/docs/examples/1.4.x/console-cli/examples/project/update-variable.md b/docs/examples/1.4.x/console-cli/examples/project/update-variable.md new file mode 100644 index 0000000000..3196419a32 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/project/update-variable.md @@ -0,0 +1,4 @@ +appwrite project updateVariable \ + --variableId [VARIABLE_ID] \ + --key [KEY] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/create-key.md b/docs/examples/1.4.x/console-cli/examples/projects/create-key.md new file mode 100644 index 0000000000..14112865c5 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/create-key.md @@ -0,0 +1,5 @@ +appwrite projects createKey \ + --projectId [PROJECT_ID] \ + --name [NAME] \ + --scopes one two three \ + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/create-platform.md b/docs/examples/1.4.x/console-cli/examples/projects/create-platform.md new file mode 100644 index 0000000000..1374f510e2 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/create-platform.md @@ -0,0 +1,7 @@ +appwrite projects createPlatform \ + --projectId [PROJECT_ID] \ + --type web \ + --name [NAME] \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/create-webhook.md b/docs/examples/1.4.x/console-cli/examples/projects/create-webhook.md new file mode 100644 index 0000000000..2eaacd167f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/create-webhook.md @@ -0,0 +1,8 @@ +appwrite projects createWebhook \ + --projectId [PROJECT_ID] \ + --name [NAME] \ + --events one two three \ + --url https://example.com \ + --security false \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/create.md b/docs/examples/1.4.x/console-cli/examples/projects/create.md new file mode 100644 index 0000000000..e851cefb5f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/create.md @@ -0,0 +1,14 @@ +appwrite projects create \ + --projectId '' \ + --name [NAME] \ + --teamId [TEAM_ID] \ + + + + + + + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/delete-email-template.md b/docs/examples/1.4.x/console-cli/examples/projects/delete-email-template.md new file mode 100644 index 0000000000..38939595f0 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/delete-email-template.md @@ -0,0 +1,4 @@ +appwrite projects deleteEmailTemplate \ + --projectId [PROJECT_ID] \ + --type verification \ + --locale af diff --git a/docs/examples/1.4.x/console-cli/examples/projects/delete-key.md b/docs/examples/1.4.x/console-cli/examples/projects/delete-key.md new file mode 100644 index 0000000000..48f97cf529 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/delete-key.md @@ -0,0 +1,3 @@ +appwrite projects deleteKey \ + --projectId [PROJECT_ID] \ + --keyId [KEY_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/delete-platform.md b/docs/examples/1.4.x/console-cli/examples/projects/delete-platform.md new file mode 100644 index 0000000000..9e14cb5b69 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/delete-platform.md @@ -0,0 +1,3 @@ +appwrite projects deletePlatform \ + --projectId [PROJECT_ID] \ + --platformId [PLATFORM_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/delete-sms-template.md b/docs/examples/1.4.x/console-cli/examples/projects/delete-sms-template.md new file mode 100644 index 0000000000..fdb080b6e5 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/delete-sms-template.md @@ -0,0 +1,4 @@ +appwrite projects deleteSmsTemplate \ + --projectId [PROJECT_ID] \ + --type verification \ + --locale af diff --git a/docs/examples/1.4.x/console-cli/examples/projects/delete-webhook.md b/docs/examples/1.4.x/console-cli/examples/projects/delete-webhook.md new file mode 100644 index 0000000000..1235e737c4 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/delete-webhook.md @@ -0,0 +1,3 @@ +appwrite projects deleteWebhook \ + --projectId [PROJECT_ID] \ + --webhookId [WEBHOOK_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/delete.md b/docs/examples/1.4.x/console-cli/examples/projects/delete.md new file mode 100644 index 0000000000..9b0903d301 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/delete.md @@ -0,0 +1,2 @@ +appwrite projects delete \ + --projectId [PROJECT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/get-email-template.md b/docs/examples/1.4.x/console-cli/examples/projects/get-email-template.md new file mode 100644 index 0000000000..dcb55ce0a9 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/get-email-template.md @@ -0,0 +1,4 @@ +appwrite projects getEmailTemplate \ + --projectId [PROJECT_ID] \ + --type verification \ + --locale af diff --git a/docs/examples/1.4.x/console-cli/examples/projects/get-key.md b/docs/examples/1.4.x/console-cli/examples/projects/get-key.md new file mode 100644 index 0000000000..75548d21b3 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/get-key.md @@ -0,0 +1,3 @@ +appwrite projects getKey \ + --projectId [PROJECT_ID] \ + --keyId [KEY_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/get-platform.md b/docs/examples/1.4.x/console-cli/examples/projects/get-platform.md new file mode 100644 index 0000000000..97432f00a2 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/get-platform.md @@ -0,0 +1,3 @@ +appwrite projects getPlatform \ + --projectId [PROJECT_ID] \ + --platformId [PLATFORM_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/get-sms-template.md b/docs/examples/1.4.x/console-cli/examples/projects/get-sms-template.md new file mode 100644 index 0000000000..0144b31e2f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/get-sms-template.md @@ -0,0 +1,4 @@ +appwrite projects getSmsTemplate \ + --projectId [PROJECT_ID] \ + --type verification \ + --locale af diff --git a/docs/examples/1.4.x/console-cli/examples/projects/get-usage.md b/docs/examples/1.4.x/console-cli/examples/projects/get-usage.md new file mode 100644 index 0000000000..a10e474c14 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/get-usage.md @@ -0,0 +1,3 @@ +appwrite projects getUsage \ + --projectId [PROJECT_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/get-webhook.md b/docs/examples/1.4.x/console-cli/examples/projects/get-webhook.md new file mode 100644 index 0000000000..b51a78c247 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/get-webhook.md @@ -0,0 +1,3 @@ +appwrite projects getWebhook \ + --projectId [PROJECT_ID] \ + --webhookId [WEBHOOK_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/get.md b/docs/examples/1.4.x/console-cli/examples/projects/get.md new file mode 100644 index 0000000000..b0589ea3e7 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/get.md @@ -0,0 +1,2 @@ +appwrite projects get \ + --projectId [PROJECT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/list-keys.md b/docs/examples/1.4.x/console-cli/examples/projects/list-keys.md new file mode 100644 index 0000000000..aba2fab9e1 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/list-keys.md @@ -0,0 +1,2 @@ +appwrite projects listKeys \ + --projectId [PROJECT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/list-platforms.md b/docs/examples/1.4.x/console-cli/examples/projects/list-platforms.md new file mode 100644 index 0000000000..cd7ae3760f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/list-platforms.md @@ -0,0 +1,2 @@ +appwrite projects listPlatforms \ + --projectId [PROJECT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/list-webhooks.md b/docs/examples/1.4.x/console-cli/examples/projects/list-webhooks.md new file mode 100644 index 0000000000..cda3f1e5c8 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/list-webhooks.md @@ -0,0 +1,2 @@ +appwrite projects listWebhooks \ + --projectId [PROJECT_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/list.md b/docs/examples/1.4.x/console-cli/examples/projects/list.md new file mode 100644 index 0000000000..0d3dd7a539 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/list.md @@ -0,0 +1,3 @@ +appwrite projects list \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-auth-duration.md b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-duration.md new file mode 100644 index 0000000000..f2e49efc73 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-duration.md @@ -0,0 +1,3 @@ +appwrite projects updateAuthDuration \ + --projectId [PROJECT_ID] \ + --duration 0 diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-auth-limit.md b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-limit.md new file mode 100644 index 0000000000..0f59c9600c --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-limit.md @@ -0,0 +1,3 @@ +appwrite projects updateAuthLimit \ + --projectId [PROJECT_ID] \ + --limit 0 diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-auth-password-dictionary.md b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-password-dictionary.md new file mode 100644 index 0000000000..e05b7d1722 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-password-dictionary.md @@ -0,0 +1,3 @@ +appwrite projects updateAuthPasswordDictionary \ + --projectId [PROJECT_ID] \ + --enabled false diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-auth-password-history.md b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-password-history.md new file mode 100644 index 0000000000..9f507127ae --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-password-history.md @@ -0,0 +1,3 @@ +appwrite projects updateAuthPasswordHistory \ + --projectId [PROJECT_ID] \ + --limit 0 diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-auth-sessions-limit.md b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-sessions-limit.md new file mode 100644 index 0000000000..f22ecf3596 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-sessions-limit.md @@ -0,0 +1,3 @@ +appwrite projects updateAuthSessionsLimit \ + --projectId [PROJECT_ID] \ + --limit 1 diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-auth-status.md b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-status.md new file mode 100644 index 0000000000..c4348c1b09 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-auth-status.md @@ -0,0 +1,4 @@ +appwrite projects updateAuthStatus \ + --projectId [PROJECT_ID] \ + --method email-password \ + --status false diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-email-template.md b/docs/examples/1.4.x/console-cli/examples/projects/update-email-template.md new file mode 100644 index 0000000000..e89ca80c63 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-email-template.md @@ -0,0 +1,9 @@ +appwrite projects updateEmailTemplate \ + --projectId [PROJECT_ID] \ + --type verification \ + --locale af \ + --subject [SUBJECT] \ + --message [MESSAGE] \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-key.md b/docs/examples/1.4.x/console-cli/examples/projects/update-key.md new file mode 100644 index 0000000000..97a004b5a2 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-key.md @@ -0,0 +1,6 @@ +appwrite projects updateKey \ + --projectId [PROJECT_ID] \ + --keyId [KEY_ID] \ + --name [NAME] \ + --scopes one two three \ + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-o-auth2.md b/docs/examples/1.4.x/console-cli/examples/projects/update-o-auth2.md new file mode 100644 index 0000000000..95c4165192 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-o-auth2.md @@ -0,0 +1,6 @@ +appwrite projects updateOAuth2 \ + --projectId [PROJECT_ID] \ + --provider amazon \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-personal-data-check.md b/docs/examples/1.4.x/console-cli/examples/projects/update-personal-data-check.md new file mode 100644 index 0000000000..d6cf4ce3ea --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-personal-data-check.md @@ -0,0 +1,3 @@ +appwrite projects updatePersonalDataCheck \ + --projectId [PROJECT_ID] \ + --enabled false diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-platform.md b/docs/examples/1.4.x/console-cli/examples/projects/update-platform.md new file mode 100644 index 0000000000..77268a4ee7 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-platform.md @@ -0,0 +1,7 @@ +appwrite projects updatePlatform \ + --projectId [PROJECT_ID] \ + --platformId [PLATFORM_ID] \ + --name [NAME] \ + + + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-service-status-all.md b/docs/examples/1.4.x/console-cli/examples/projects/update-service-status-all.md new file mode 100644 index 0000000000..bcf29dbdab --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-service-status-all.md @@ -0,0 +1,3 @@ +appwrite projects updateServiceStatusAll \ + --projectId [PROJECT_ID] \ + --status false diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-service-status.md b/docs/examples/1.4.x/console-cli/examples/projects/update-service-status.md new file mode 100644 index 0000000000..4cfd9f9f3c --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-service-status.md @@ -0,0 +1,4 @@ +appwrite projects updateServiceStatus \ + --projectId [PROJECT_ID] \ + --service account \ + --status false diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-sms-template.md b/docs/examples/1.4.x/console-cli/examples/projects/update-sms-template.md new file mode 100644 index 0000000000..9220501690 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-sms-template.md @@ -0,0 +1,5 @@ +appwrite projects updateSmsTemplate \ + --projectId [PROJECT_ID] \ + --type verification \ + --locale af \ + --message [MESSAGE] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-smtp-configuration.md b/docs/examples/1.4.x/console-cli/examples/projects/update-smtp-configuration.md new file mode 100644 index 0000000000..def346b6f3 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-smtp-configuration.md @@ -0,0 +1,11 @@ +appwrite projects updateSmtpConfiguration \ + --projectId [PROJECT_ID] \ + --enabled false \ + + + + + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-team.md b/docs/examples/1.4.x/console-cli/examples/projects/update-team.md new file mode 100644 index 0000000000..906e2879e6 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-team.md @@ -0,0 +1,3 @@ +appwrite projects updateTeam \ + --projectId [PROJECT_ID] \ + --teamId [TEAM_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-webhook-signature.md b/docs/examples/1.4.x/console-cli/examples/projects/update-webhook-signature.md new file mode 100644 index 0000000000..1040b491e8 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-webhook-signature.md @@ -0,0 +1,3 @@ +appwrite projects updateWebhookSignature \ + --projectId [PROJECT_ID] \ + --webhookId [WEBHOOK_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update-webhook.md b/docs/examples/1.4.x/console-cli/examples/projects/update-webhook.md new file mode 100644 index 0000000000..98517cbfa8 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update-webhook.md @@ -0,0 +1,9 @@ +appwrite projects updateWebhook \ + --projectId [PROJECT_ID] \ + --webhookId [WEBHOOK_ID] \ + --name [NAME] \ + --events one two three \ + --url https://example.com \ + --security false \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/projects/update.md b/docs/examples/1.4.x/console-cli/examples/projects/update.md new file mode 100644 index 0000000000..83e99a1a8a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/projects/update.md @@ -0,0 +1,12 @@ +appwrite projects update \ + --projectId [PROJECT_ID] \ + --name [NAME] \ + + + + + + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/proxy/create-rule.md b/docs/examples/1.4.x/console-cli/examples/proxy/create-rule.md new file mode 100644 index 0000000000..3d821040a7 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/proxy/create-rule.md @@ -0,0 +1,4 @@ +appwrite proxy createRule \ + --domain '' \ + --resourceType api \ + diff --git a/docs/examples/1.4.x/console-cli/examples/proxy/delete-rule.md b/docs/examples/1.4.x/console-cli/examples/proxy/delete-rule.md new file mode 100644 index 0000000000..7b1c77d5dd --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/proxy/delete-rule.md @@ -0,0 +1,2 @@ +appwrite proxy deleteRule \ + --ruleId [RULE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/proxy/get-rule.md b/docs/examples/1.4.x/console-cli/examples/proxy/get-rule.md new file mode 100644 index 0000000000..2f16d37ed6 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/proxy/get-rule.md @@ -0,0 +1,2 @@ +appwrite proxy getRule \ + --ruleId [RULE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/proxy/list-rules.md b/docs/examples/1.4.x/console-cli/examples/proxy/list-rules.md new file mode 100644 index 0000000000..bc654bac5c --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/proxy/list-rules.md @@ -0,0 +1,3 @@ +appwrite proxy listRules \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/proxy/update-rule-verification.md b/docs/examples/1.4.x/console-cli/examples/proxy/update-rule-verification.md new file mode 100644 index 0000000000..6f4e4df826 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/proxy/update-rule-verification.md @@ -0,0 +1,2 @@ +appwrite proxy updateRuleVerification \ + --ruleId [RULE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/storage/create-bucket.md b/docs/examples/1.4.x/console-cli/examples/storage/create-bucket.md new file mode 100644 index 0000000000..25666885f7 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/create-bucket.md @@ -0,0 +1,11 @@ +appwrite storage createBucket \ + --bucketId [BUCKET_ID] \ + --name [NAME] \ + + + + + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/storage/create-file.md b/docs/examples/1.4.x/console-cli/examples/storage/create-file.md new file mode 100644 index 0000000000..e13b8d0e98 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/create-file.md @@ -0,0 +1,5 @@ +appwrite storage createFile \ + --bucketId [BUCKET_ID] \ + --fileId [FILE_ID] \ + --file 'path/to/file.png' \ + diff --git a/docs/examples/1.4.x/console-cli/examples/storage/delete-bucket.md b/docs/examples/1.4.x/console-cli/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..178a6a4b3a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/delete-bucket.md @@ -0,0 +1,2 @@ +appwrite storage deleteBucket \ + --bucketId [BUCKET_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/storage/delete-file.md b/docs/examples/1.4.x/console-cli/examples/storage/delete-file.md new file mode 100644 index 0000000000..0275f87172 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/delete-file.md @@ -0,0 +1,3 @@ +appwrite storage deleteFile \ + --bucketId [BUCKET_ID] \ + --fileId [FILE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/storage/get-bucket-usage.md b/docs/examples/1.4.x/console-cli/examples/storage/get-bucket-usage.md new file mode 100644 index 0000000000..930575e2e9 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/get-bucket-usage.md @@ -0,0 +1,3 @@ +appwrite storage getBucketUsage \ + --bucketId [BUCKET_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/storage/get-bucket.md b/docs/examples/1.4.x/console-cli/examples/storage/get-bucket.md new file mode 100644 index 0000000000..76479be7d6 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/get-bucket.md @@ -0,0 +1,2 @@ +appwrite storage getBucket \ + --bucketId [BUCKET_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/storage/get-file-download.md b/docs/examples/1.4.x/console-cli/examples/storage/get-file-download.md new file mode 100644 index 0000000000..637c7db1da --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/get-file-download.md @@ -0,0 +1,3 @@ +appwrite storage getFileDownload \ + --bucketId [BUCKET_ID] \ + --fileId [FILE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/storage/get-file-preview.md b/docs/examples/1.4.x/console-cli/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..309088506b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/get-file-preview.md @@ -0,0 +1,14 @@ +appwrite storage getFilePreview \ + --bucketId [BUCKET_ID] \ + --fileId [FILE_ID] \ + + + + + + + + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/storage/get-file-view.md b/docs/examples/1.4.x/console-cli/examples/storage/get-file-view.md new file mode 100644 index 0000000000..a8500f3597 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/get-file-view.md @@ -0,0 +1,3 @@ +appwrite storage getFileView \ + --bucketId [BUCKET_ID] \ + --fileId [FILE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/storage/get-file.md b/docs/examples/1.4.x/console-cli/examples/storage/get-file.md new file mode 100644 index 0000000000..f556ef1d5c --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/get-file.md @@ -0,0 +1,3 @@ +appwrite storage getFile \ + --bucketId [BUCKET_ID] \ + --fileId [FILE_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/storage/get-usage.md b/docs/examples/1.4.x/console-cli/examples/storage/get-usage.md new file mode 100644 index 0000000000..29466e02f0 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/get-usage.md @@ -0,0 +1,2 @@ +appwrite storage getUsage \ + diff --git a/docs/examples/1.4.x/console-cli/examples/storage/list-buckets.md b/docs/examples/1.4.x/console-cli/examples/storage/list-buckets.md new file mode 100644 index 0000000000..a5cad1988f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/list-buckets.md @@ -0,0 +1,3 @@ +appwrite storage listBuckets \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/storage/list-files.md b/docs/examples/1.4.x/console-cli/examples/storage/list-files.md new file mode 100644 index 0000000000..062781feaf --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/list-files.md @@ -0,0 +1,4 @@ +appwrite storage listFiles \ + --bucketId [BUCKET_ID] \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/storage/update-bucket.md b/docs/examples/1.4.x/console-cli/examples/storage/update-bucket.md new file mode 100644 index 0000000000..96132f4551 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/update-bucket.md @@ -0,0 +1,11 @@ +appwrite storage updateBucket \ + --bucketId [BUCKET_ID] \ + --name [NAME] \ + + + + + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/storage/update-file.md b/docs/examples/1.4.x/console-cli/examples/storage/update-file.md new file mode 100644 index 0000000000..6f6a9ca2f6 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/storage/update-file.md @@ -0,0 +1,5 @@ +appwrite storage updateFile \ + --bucketId [BUCKET_ID] \ + --fileId [FILE_ID] \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/teams/create-membership.md b/docs/examples/1.4.x/console-cli/examples/teams/create-membership.md new file mode 100644 index 0000000000..6faa89d1d9 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/create-membership.md @@ -0,0 +1,8 @@ +appwrite teams createMembership \ + --teamId [TEAM_ID] \ + --roles one two three \ + --url https://example.com \ + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/teams/create.md b/docs/examples/1.4.x/console-cli/examples/teams/create.md new file mode 100644 index 0000000000..3704d02d0b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/create.md @@ -0,0 +1,4 @@ +appwrite teams create \ + --teamId [TEAM_ID] \ + --name [NAME] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/teams/delete-membership.md b/docs/examples/1.4.x/console-cli/examples/teams/delete-membership.md new file mode 100644 index 0000000000..6aaaf8902b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/delete-membership.md @@ -0,0 +1,3 @@ +appwrite teams deleteMembership \ + --teamId [TEAM_ID] \ + --membershipId [MEMBERSHIP_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/teams/delete.md b/docs/examples/1.4.x/console-cli/examples/teams/delete.md new file mode 100644 index 0000000000..0a4d554b1b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/delete.md @@ -0,0 +1,2 @@ +appwrite teams delete \ + --teamId [TEAM_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/teams/get-membership.md b/docs/examples/1.4.x/console-cli/examples/teams/get-membership.md new file mode 100644 index 0000000000..25d11863b9 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/get-membership.md @@ -0,0 +1,3 @@ +appwrite teams getMembership \ + --teamId [TEAM_ID] \ + --membershipId [MEMBERSHIP_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/teams/get-prefs.md b/docs/examples/1.4.x/console-cli/examples/teams/get-prefs.md new file mode 100644 index 0000000000..46d9edc3b7 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/get-prefs.md @@ -0,0 +1,2 @@ +appwrite teams getPrefs \ + --teamId [TEAM_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/teams/get.md b/docs/examples/1.4.x/console-cli/examples/teams/get.md new file mode 100644 index 0000000000..111aff623b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/get.md @@ -0,0 +1,2 @@ +appwrite teams get \ + --teamId [TEAM_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/teams/list-logs.md b/docs/examples/1.4.x/console-cli/examples/teams/list-logs.md new file mode 100644 index 0000000000..81e09b93c3 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/list-logs.md @@ -0,0 +1,3 @@ +appwrite teams listLogs \ + --teamId [TEAM_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/teams/list-memberships.md b/docs/examples/1.4.x/console-cli/examples/teams/list-memberships.md new file mode 100644 index 0000000000..367227fd08 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/list-memberships.md @@ -0,0 +1,4 @@ +appwrite teams listMemberships \ + --teamId [TEAM_ID] \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/teams/list.md b/docs/examples/1.4.x/console-cli/examples/teams/list.md new file mode 100644 index 0000000000..dfffc4d4dd --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/list.md @@ -0,0 +1,3 @@ +appwrite teams list \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/teams/update-membership-status.md b/docs/examples/1.4.x/console-cli/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..0f3efc413a --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/update-membership-status.md @@ -0,0 +1,5 @@ +appwrite teams updateMembershipStatus \ + --teamId [TEAM_ID] \ + --membershipId [MEMBERSHIP_ID] \ + --userId [USER_ID] \ + --secret [SECRET] diff --git a/docs/examples/1.4.x/console-cli/examples/teams/update-membership.md b/docs/examples/1.4.x/console-cli/examples/teams/update-membership.md new file mode 100644 index 0000000000..96d2c2e684 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/update-membership.md @@ -0,0 +1,4 @@ +appwrite teams updateMembership \ + --teamId [TEAM_ID] \ + --membershipId [MEMBERSHIP_ID] \ + --roles one two three diff --git a/docs/examples/1.4.x/console-cli/examples/teams/update-name.md b/docs/examples/1.4.x/console-cli/examples/teams/update-name.md new file mode 100644 index 0000000000..78b23e422f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/update-name.md @@ -0,0 +1,3 @@ +appwrite teams updateName \ + --teamId [TEAM_ID] \ + --name [NAME] diff --git a/docs/examples/1.4.x/console-cli/examples/teams/update-prefs.md b/docs/examples/1.4.x/console-cli/examples/teams/update-prefs.md new file mode 100644 index 0000000000..dbad52d3d2 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/teams/update-prefs.md @@ -0,0 +1,3 @@ +appwrite teams updatePrefs \ + --teamId [TEAM_ID] \ + --prefs '{ "key": "value" }' diff --git a/docs/examples/1.4.x/console-cli/examples/users/create-argon2user.md b/docs/examples/1.4.x/console-cli/examples/users/create-argon2user.md new file mode 100644 index 0000000000..e215603b23 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/create-argon2user.md @@ -0,0 +1,5 @@ +appwrite users createArgon2User \ + --userId [USER_ID] \ + --email email@example.com \ + --password password \ + diff --git a/docs/examples/1.4.x/console-cli/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/console-cli/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..b4f121266b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/create-bcrypt-user.md @@ -0,0 +1,5 @@ +appwrite users createBcryptUser \ + --userId [USER_ID] \ + --email email@example.com \ + --password password \ + diff --git a/docs/examples/1.4.x/console-cli/examples/users/create-m-d5user.md b/docs/examples/1.4.x/console-cli/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..4bb8cb4531 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/create-m-d5user.md @@ -0,0 +1,5 @@ +appwrite users createMD5User \ + --userId [USER_ID] \ + --email email@example.com \ + --password password \ + diff --git a/docs/examples/1.4.x/console-cli/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/console-cli/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..c0ebd7b0ec --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/create-p-h-pass-user.md @@ -0,0 +1,5 @@ +appwrite users createPHPassUser \ + --userId [USER_ID] \ + --email email@example.com \ + --password password \ + diff --git a/docs/examples/1.4.x/console-cli/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/console-cli/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..3aae965b68 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/create-s-h-a-user.md @@ -0,0 +1,6 @@ +appwrite users createSHAUser \ + --userId [USER_ID] \ + --email email@example.com \ + --password password \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/console-cli/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..73b62b8424 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,8 @@ +appwrite users createScryptModifiedUser \ + --userId [USER_ID] \ + --email email@example.com \ + --password password \ + --passwordSalt [PASSWORD_SALT] \ + --passwordSaltSeparator [PASSWORD_SALT_SEPARATOR] \ + --passwordSignerKey [PASSWORD_SIGNER_KEY] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/console-cli/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..595231ed11 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/create-scrypt-user.md @@ -0,0 +1,10 @@ +appwrite users createScryptUser \ + --userId [USER_ID] \ + --email email@example.com \ + --password password \ + --passwordSalt [PASSWORD_SALT] \ + --passwordCpu null \ + --passwordMemory null \ + --passwordParallel null \ + --passwordLength null \ + diff --git a/docs/examples/1.4.x/console-cli/examples/users/create.md b/docs/examples/1.4.x/console-cli/examples/users/create.md new file mode 100644 index 0000000000..c8a0d67003 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/create.md @@ -0,0 +1,6 @@ +appwrite users create \ + --userId [USER_ID] \ + + + + diff --git a/docs/examples/1.4.x/console-cli/examples/users/delete-identity.md b/docs/examples/1.4.x/console-cli/examples/users/delete-identity.md new file mode 100644 index 0000000000..f680f98390 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/delete-identity.md @@ -0,0 +1,2 @@ +appwrite users deleteIdentity \ + --identityId [IDENTITY_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/users/delete-session.md b/docs/examples/1.4.x/console-cli/examples/users/delete-session.md new file mode 100644 index 0000000000..e4b7632cf7 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/delete-session.md @@ -0,0 +1,3 @@ +appwrite users deleteSession \ + --userId [USER_ID] \ + --sessionId [SESSION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/users/delete-sessions.md b/docs/examples/1.4.x/console-cli/examples/users/delete-sessions.md new file mode 100644 index 0000000000..16c2c3a070 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/delete-sessions.md @@ -0,0 +1,2 @@ +appwrite users deleteSessions \ + --userId [USER_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/users/delete.md b/docs/examples/1.4.x/console-cli/examples/users/delete.md new file mode 100644 index 0000000000..9c24060965 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/delete.md @@ -0,0 +1,2 @@ +appwrite users delete \ + --userId [USER_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/users/get-prefs.md b/docs/examples/1.4.x/console-cli/examples/users/get-prefs.md new file mode 100644 index 0000000000..1aa1b1e332 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/get-prefs.md @@ -0,0 +1,2 @@ +appwrite users getPrefs \ + --userId [USER_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/users/get-usage.md b/docs/examples/1.4.x/console-cli/examples/users/get-usage.md new file mode 100644 index 0000000000..860cdc0c42 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/get-usage.md @@ -0,0 +1,3 @@ +appwrite users getUsage \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/users/get.md b/docs/examples/1.4.x/console-cli/examples/users/get.md new file mode 100644 index 0000000000..95f44afecf --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/get.md @@ -0,0 +1,2 @@ +appwrite users get \ + --userId [USER_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/users/list-identities.md b/docs/examples/1.4.x/console-cli/examples/users/list-identities.md new file mode 100644 index 0000000000..c6cd6d5e28 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/list-identities.md @@ -0,0 +1,3 @@ +appwrite users listIdentities \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/users/list-logs.md b/docs/examples/1.4.x/console-cli/examples/users/list-logs.md new file mode 100644 index 0000000000..257576fdb7 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/list-logs.md @@ -0,0 +1,3 @@ +appwrite users listLogs \ + --userId [USER_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/users/list-memberships.md b/docs/examples/1.4.x/console-cli/examples/users/list-memberships.md new file mode 100644 index 0000000000..44516c7a90 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/list-memberships.md @@ -0,0 +1,2 @@ +appwrite users listMemberships \ + --userId [USER_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/users/list-sessions.md b/docs/examples/1.4.x/console-cli/examples/users/list-sessions.md new file mode 100644 index 0000000000..2717411d22 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/list-sessions.md @@ -0,0 +1,2 @@ +appwrite users listSessions \ + --userId [USER_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/users/list.md b/docs/examples/1.4.x/console-cli/examples/users/list.md new file mode 100644 index 0000000000..e5fdb9e5c5 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/list.md @@ -0,0 +1,3 @@ +appwrite users list \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/users/update-email-verification.md b/docs/examples/1.4.x/console-cli/examples/users/update-email-verification.md new file mode 100644 index 0000000000..ab87d52212 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/update-email-verification.md @@ -0,0 +1,3 @@ +appwrite users updateEmailVerification \ + --userId [USER_ID] \ + --emailVerification false diff --git a/docs/examples/1.4.x/console-cli/examples/users/update-email.md b/docs/examples/1.4.x/console-cli/examples/users/update-email.md new file mode 100644 index 0000000000..be8bb11607 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/update-email.md @@ -0,0 +1,3 @@ +appwrite users updateEmail \ + --userId [USER_ID] \ + --email email@example.com diff --git a/docs/examples/1.4.x/console-cli/examples/users/update-labels.md b/docs/examples/1.4.x/console-cli/examples/users/update-labels.md new file mode 100644 index 0000000000..b02e533936 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/update-labels.md @@ -0,0 +1,3 @@ +appwrite users updateLabels \ + --userId [USER_ID] \ + --labels one two three diff --git a/docs/examples/1.4.x/console-cli/examples/users/update-name.md b/docs/examples/1.4.x/console-cli/examples/users/update-name.md new file mode 100644 index 0000000000..ce9cad511b --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/update-name.md @@ -0,0 +1,3 @@ +appwrite users updateName \ + --userId [USER_ID] \ + --name [NAME] diff --git a/docs/examples/1.4.x/console-cli/examples/users/update-password.md b/docs/examples/1.4.x/console-cli/examples/users/update-password.md new file mode 100644 index 0000000000..b4b7498249 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/update-password.md @@ -0,0 +1,3 @@ +appwrite users updatePassword \ + --userId [USER_ID] \ + --password '' diff --git a/docs/examples/1.4.x/console-cli/examples/users/update-phone-verification.md b/docs/examples/1.4.x/console-cli/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..4cea770bd0 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/update-phone-verification.md @@ -0,0 +1,3 @@ +appwrite users updatePhoneVerification \ + --userId [USER_ID] \ + --phoneVerification false diff --git a/docs/examples/1.4.x/console-cli/examples/users/update-phone.md b/docs/examples/1.4.x/console-cli/examples/users/update-phone.md new file mode 100644 index 0000000000..5909e68e64 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/update-phone.md @@ -0,0 +1,3 @@ +appwrite users updatePhone \ + --userId [USER_ID] \ + --number +12065550100 diff --git a/docs/examples/1.4.x/console-cli/examples/users/update-prefs.md b/docs/examples/1.4.x/console-cli/examples/users/update-prefs.md new file mode 100644 index 0000000000..cc4a7422ac --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/update-prefs.md @@ -0,0 +1,3 @@ +appwrite users updatePrefs \ + --userId [USER_ID] \ + --prefs '{ "key": "value" }' diff --git a/docs/examples/1.4.x/console-cli/examples/users/update-status.md b/docs/examples/1.4.x/console-cli/examples/users/update-status.md new file mode 100644 index 0000000000..6bc10ee5de --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/users/update-status.md @@ -0,0 +1,3 @@ +appwrite users updateStatus \ + --userId [USER_ID] \ + --status false diff --git a/docs/examples/1.4.x/console-cli/examples/vcs/create-repository-detection.md b/docs/examples/1.4.x/console-cli/examples/vcs/create-repository-detection.md new file mode 100644 index 0000000000..7fa1c56041 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/vcs/create-repository-detection.md @@ -0,0 +1,4 @@ +appwrite vcs createRepositoryDetection \ + --installationId [INSTALLATION_ID] \ + --providerRepositoryId [PROVIDER_REPOSITORY_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/vcs/create-repository.md b/docs/examples/1.4.x/console-cli/examples/vcs/create-repository.md new file mode 100644 index 0000000000..8d728e0c11 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/vcs/create-repository.md @@ -0,0 +1,4 @@ +appwrite vcs createRepository \ + --installationId [INSTALLATION_ID] \ + --name [NAME] \ + --private false diff --git a/docs/examples/1.4.x/console-cli/examples/vcs/delete-installation.md b/docs/examples/1.4.x/console-cli/examples/vcs/delete-installation.md new file mode 100644 index 0000000000..027e9f5d6f --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/vcs/delete-installation.md @@ -0,0 +1,2 @@ +appwrite vcs deleteInstallation \ + --installationId [INSTALLATION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/vcs/get-installation.md b/docs/examples/1.4.x/console-cli/examples/vcs/get-installation.md new file mode 100644 index 0000000000..bf62ddb1c9 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/vcs/get-installation.md @@ -0,0 +1,2 @@ +appwrite vcs getInstallation \ + --installationId [INSTALLATION_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/vcs/get-repository.md b/docs/examples/1.4.x/console-cli/examples/vcs/get-repository.md new file mode 100644 index 0000000000..b458a3be89 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/vcs/get-repository.md @@ -0,0 +1,3 @@ +appwrite vcs getRepository \ + --installationId [INSTALLATION_ID] \ + --providerRepositoryId [PROVIDER_REPOSITORY_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/vcs/list-installations.md b/docs/examples/1.4.x/console-cli/examples/vcs/list-installations.md new file mode 100644 index 0000000000..a0af28dfbb --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/vcs/list-installations.md @@ -0,0 +1,3 @@ +appwrite vcs listInstallations \ + + diff --git a/docs/examples/1.4.x/console-cli/examples/vcs/list-repositories.md b/docs/examples/1.4.x/console-cli/examples/vcs/list-repositories.md new file mode 100644 index 0000000000..5b03b77265 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/vcs/list-repositories.md @@ -0,0 +1,3 @@ +appwrite vcs listRepositories \ + --installationId [INSTALLATION_ID] \ + diff --git a/docs/examples/1.4.x/console-cli/examples/vcs/list-repository-branches.md b/docs/examples/1.4.x/console-cli/examples/vcs/list-repository-branches.md new file mode 100644 index 0000000000..8e69009ece --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/vcs/list-repository-branches.md @@ -0,0 +1,3 @@ +appwrite vcs listRepositoryBranches \ + --installationId [INSTALLATION_ID] \ + --providerRepositoryId [PROVIDER_REPOSITORY_ID] diff --git a/docs/examples/1.4.x/console-cli/examples/vcs/update-external-deployments.md b/docs/examples/1.4.x/console-cli/examples/vcs/update-external-deployments.md new file mode 100644 index 0000000000..7eed90efe3 --- /dev/null +++ b/docs/examples/1.4.x/console-cli/examples/vcs/update-external-deployments.md @@ -0,0 +1,4 @@ +appwrite vcs updateExternalDeployments \ + --installationId [INSTALLATION_ID] \ + --repositoryId [REPOSITORY_ID] \ + --providerPullRequestId [PROVIDER_PULL_REQUEST_ID] diff --git a/docs/examples/1.4.x/console-web/examples/account/create-anonymous-session.md b/docs/examples/1.4.x/console-web/examples/account/create-anonymous-session.md new file mode 100644 index 0000000000..9521cf68a5 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create-anonymous-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createAnonymousSession(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/create-email-session.md b/docs/examples/1.4.x/console-web/examples/account/create-email-session.md new file mode 100644 index 0000000000..19812773df --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create-email-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createEmailSession('email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/create-j-w-t.md b/docs/examples/1.4.x/console-web/examples/account/create-j-w-t.md new file mode 100644 index 0000000000..8a851df369 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create-j-w-t.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createJWT(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/create-magic-u-r-l-session.md b/docs/examples/1.4.x/console-web/examples/account/create-magic-u-r-l-session.md new file mode 100644 index 0000000000..6917aa288c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create-magic-u-r-l-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createMagicURLSession('[USER_ID]', 'email@example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/create-o-auth2session.md b/docs/examples/1.4.x/console-web/examples/account/create-o-auth2session.md new file mode 100644 index 0000000000..bf33c52f30 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create-o-auth2session.md @@ -0,0 +1,14 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +// Go to OAuth provider login page +account.createOAuth2Session('amazon'); + diff --git a/docs/examples/1.4.x/console-web/examples/account/create-phone-session.md b/docs/examples/1.4.x/console-web/examples/account/create-phone-session.md new file mode 100644 index 0000000000..85e7d68eed --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create-phone-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createPhoneSession('[USER_ID]', '+12065550100'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/create-phone-verification.md b/docs/examples/1.4.x/console-web/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..0b10961e53 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create-phone-verification.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createPhoneVerification(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/create-recovery.md b/docs/examples/1.4.x/console-web/examples/account/create-recovery.md new file mode 100644 index 0000000000..dd33c01f04 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create-recovery.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createRecovery('email@example.com', 'https://example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/create-verification.md b/docs/examples/1.4.x/console-web/examples/account/create-verification.md new file mode 100644 index 0000000000..7b1ec32f2f --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create-verification.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.createVerification('https://example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/create.md b/docs/examples/1.4.x/console-web/examples/account/create.md new file mode 100644 index 0000000000..4c61ef8eb2 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/create.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.create('[USER_ID]', 'email@example.com', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/delete-identity.md b/docs/examples/1.4.x/console-web/examples/account/delete-identity.md new file mode 100644 index 0000000000..8e7a87270a --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/delete-identity.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.deleteIdentity('[IDENTITY_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/delete-session.md b/docs/examples/1.4.x/console-web/examples/account/delete-session.md new file mode 100644 index 0000000000..b360b3bb89 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/delete-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.deleteSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/delete-sessions.md b/docs/examples/1.4.x/console-web/examples/account/delete-sessions.md new file mode 100644 index 0000000000..0d0fea88f4 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/delete-sessions.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.deleteSessions(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/get-prefs.md b/docs/examples/1.4.x/console-web/examples/account/get-prefs.md new file mode 100644 index 0000000000..284f8fabda --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/get-prefs.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.getPrefs(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/get-session.md b/docs/examples/1.4.x/console-web/examples/account/get-session.md new file mode 100644 index 0000000000..651d35c734 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/get-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.getSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/get.md b/docs/examples/1.4.x/console-web/examples/account/get.md new file mode 100644 index 0000000000..f6fc4b9401 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/get.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.get(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/list-identities.md b/docs/examples/1.4.x/console-web/examples/account/list-identities.md new file mode 100644 index 0000000000..ea18a00081 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/list-identities.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.listIdentities(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/list-logs.md b/docs/examples/1.4.x/console-web/examples/account/list-logs.md new file mode 100644 index 0000000000..4f1d6813a7 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/list-logs.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.listLogs(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/list-sessions.md b/docs/examples/1.4.x/console-web/examples/account/list-sessions.md new file mode 100644 index 0000000000..bd3b102b21 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/list-sessions.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.listSessions(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-email.md b/docs/examples/1.4.x/console-web/examples/account/update-email.md new file mode 100644 index 0000000000..21b7fcc3f2 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-email.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateEmail('email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-magic-u-r-l-session.md b/docs/examples/1.4.x/console-web/examples/account/update-magic-u-r-l-session.md new file mode 100644 index 0000000000..1bc748ed30 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-magic-u-r-l-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateMagicURLSession('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-name.md b/docs/examples/1.4.x/console-web/examples/account/update-name.md new file mode 100644 index 0000000000..5a9ab011b4 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-name.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateName('[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-password.md b/docs/examples/1.4.x/console-web/examples/account/update-password.md new file mode 100644 index 0000000000..ca059e5304 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-password.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePassword(''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-phone-session.md b/docs/examples/1.4.x/console-web/examples/account/update-phone-session.md new file mode 100644 index 0000000000..4b47389a3c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-phone-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePhoneSession('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-phone-verification.md b/docs/examples/1.4.x/console-web/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..99c13cb90e --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-phone-verification.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePhoneVerification('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-phone.md b/docs/examples/1.4.x/console-web/examples/account/update-phone.md new file mode 100644 index 0000000000..80f715e0bc --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-phone.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePhone('+12065550100', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-prefs.md b/docs/examples/1.4.x/console-web/examples/account/update-prefs.md new file mode 100644 index 0000000000..0a85380d34 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-prefs.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updatePrefs({}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-recovery.md b/docs/examples/1.4.x/console-web/examples/account/update-recovery.md new file mode 100644 index 0000000000..64c1545e89 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-recovery.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-session.md b/docs/examples/1.4.x/console-web/examples/account/update-session.md new file mode 100644 index 0000000000..29dc0c0907 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-session.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-status.md b/docs/examples/1.4.x/console-web/examples/account/update-status.md new file mode 100644 index 0000000000..87b5146525 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-status.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateStatus(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/account/update-verification.md b/docs/examples/1.4.x/console-web/examples/account/update-verification.md new file mode 100644 index 0000000000..93dd5db120 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/account/update-verification.md @@ -0,0 +1,18 @@ +import { Client, Account } from "@appwrite.io/console"; + +const client = new Client(); + +const account = new Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = account.updateVerification('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/assistant/chat.md b/docs/examples/1.4.x/console-web/examples/assistant/chat.md new file mode 100644 index 0000000000..2806672a99 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/assistant/chat.md @@ -0,0 +1,17 @@ +import { Client, Assistant } from "@appwrite.io/console"; + +const client = new Client(); + +const assistant = new Assistant(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = assistant.chat('[PROMPT]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/avatars/get-browser.md b/docs/examples/1.4.x/console-web/examples/avatars/get-browser.md new file mode 100644 index 0000000000..f830effff2 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/avatars/get-browser.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "@appwrite.io/console"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getBrowser('aa'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/console-web/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..a4e67b25e7 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/avatars/get-credit-card.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "@appwrite.io/console"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getCreditCard('amex'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/avatars/get-favicon.md b/docs/examples/1.4.x/console-web/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..14bc1b9b00 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/avatars/get-favicon.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "@appwrite.io/console"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getFavicon('https://example.com'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/avatars/get-flag.md b/docs/examples/1.4.x/console-web/examples/avatars/get-flag.md new file mode 100644 index 0000000000..52ebe68c65 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/avatars/get-flag.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "@appwrite.io/console"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getFlag('af'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/avatars/get-image.md b/docs/examples/1.4.x/console-web/examples/avatars/get-image.md new file mode 100644 index 0000000000..517421e7f0 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/avatars/get-image.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "@appwrite.io/console"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getImage('https://example.com'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/avatars/get-initials.md b/docs/examples/1.4.x/console-web/examples/avatars/get-initials.md new file mode 100644 index 0000000000..8b03b5d386 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/avatars/get-initials.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "@appwrite.io/console"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getInitials(); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/avatars/get-q-r.md b/docs/examples/1.4.x/console-web/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..89cea47ad9 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/avatars/get-q-r.md @@ -0,0 +1,14 @@ +import { Client, Avatars } from "@appwrite.io/console"; + +const client = new Client(); + +const avatars = new Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = avatars.getQR('[TEXT]'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/console/variables.md b/docs/examples/1.4.x/console-web/examples/console/variables.md new file mode 100644 index 0000000000..3c552dee38 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/console/variables.md @@ -0,0 +1,18 @@ +import { Client, Console } from "@appwrite.io/console"; + +const client = new Client(); + +const console = new Console(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = console.variables(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..3924ff5cc5 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-boolean-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createBooleanAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-collection.md b/docs/examples/1.4.x/console-web/examples/databases/create-collection.md new file mode 100644 index 0000000000..ff3dbd974d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-collection.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createCollection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..4e1f3190b3 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-datetime-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createDatetimeAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-document.md b/docs/examples/1.4.x/console-web/examples/databases/create-document.md new file mode 100644 index 0000000000..4b9adc4e7c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-document.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]', {}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..8d2a5523b6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-email-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createEmailAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..503290b951 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-enum-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createEnumAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..7ce41b6b0b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-float-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createFloatAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-index.md b/docs/examples/1.4.x/console-web/examples/databases/create-index.md new file mode 100644 index 0000000000..4da79809f4 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-index.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createIndex('[DATABASE_ID]', '[COLLECTION_ID]', '', 'key', []); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..28218a16d7 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-integer-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createIntegerAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..88fcd66825 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-ip-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createIpAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..6fe22ad22e --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-relationship-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createRelationshipAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '[RELATED_COLLECTION_ID]', 'oneToOne'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..8beade8f9d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-string-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createStringAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', 1, false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..1cbd402c2e --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create-url-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.createUrlAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/create.md b/docs/examples/1.4.x/console-web/examples/databases/create.md new file mode 100644 index 0000000000..bca894d724 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/create.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.create('[DATABASE_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/delete-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..858010b313 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/delete-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.deleteAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/delete-collection.md b/docs/examples/1.4.x/console-web/examples/databases/delete-collection.md new file mode 100644 index 0000000000..9ce95a5e54 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/delete-collection.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.deleteCollection('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/delete-document.md b/docs/examples/1.4.x/console-web/examples/databases/delete-document.md new file mode 100644 index 0000000000..d31d06b521 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/delete-document.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.deleteDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/delete-index.md b/docs/examples/1.4.x/console-web/examples/databases/delete-index.md new file mode 100644 index 0000000000..2ef22b82ad --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/delete-index.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.deleteIndex('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/delete.md b/docs/examples/1.4.x/console-web/examples/databases/delete.md new file mode 100644 index 0000000000..bfd5b0cea3 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/delete.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.delete('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/get-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/get-attribute.md new file mode 100644 index 0000000000..1542f64763 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/get-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.getAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/get-collection-usage.md b/docs/examples/1.4.x/console-web/examples/databases/get-collection-usage.md new file mode 100644 index 0000000000..983a613373 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/get-collection-usage.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.getCollectionUsage('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/get-collection.md b/docs/examples/1.4.x/console-web/examples/databases/get-collection.md new file mode 100644 index 0000000000..6dae02f5c2 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/get-collection.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.getCollection('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/get-database-usage.md b/docs/examples/1.4.x/console-web/examples/databases/get-database-usage.md new file mode 100644 index 0000000000..f75040811e --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/get-database-usage.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.getDatabaseUsage('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/get-document.md b/docs/examples/1.4.x/console-web/examples/databases/get-document.md new file mode 100644 index 0000000000..87569bd863 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/get-document.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.getDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/get-index.md b/docs/examples/1.4.x/console-web/examples/databases/get-index.md new file mode 100644 index 0000000000..d3df35d7a7 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/get-index.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.getIndex('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/get-usage.md b/docs/examples/1.4.x/console-web/examples/databases/get-usage.md new file mode 100644 index 0000000000..aabe123e89 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/get-usage.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.getUsage(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/get.md b/docs/examples/1.4.x/console-web/examples/databases/get.md new file mode 100644 index 0000000000..64c8a859ed --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/get.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.get('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/list-attributes.md b/docs/examples/1.4.x/console-web/examples/databases/list-attributes.md new file mode 100644 index 0000000000..df9123680e --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/list-attributes.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.listAttributes('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/list-collection-logs.md b/docs/examples/1.4.x/console-web/examples/databases/list-collection-logs.md new file mode 100644 index 0000000000..89662fe4b3 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/list-collection-logs.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.listCollectionLogs('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/list-collections.md b/docs/examples/1.4.x/console-web/examples/databases/list-collections.md new file mode 100644 index 0000000000..498e0d9c13 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/list-collections.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.listCollections('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/list-document-logs.md b/docs/examples/1.4.x/console-web/examples/databases/list-document-logs.md new file mode 100644 index 0000000000..0161998358 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/list-document-logs.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.listDocumentLogs('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/list-documents.md b/docs/examples/1.4.x/console-web/examples/databases/list-documents.md new file mode 100644 index 0000000000..9e29eb52c7 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/list-documents.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.listDocuments('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/list-indexes.md b/docs/examples/1.4.x/console-web/examples/databases/list-indexes.md new file mode 100644 index 0000000000..3449b7d82b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/list-indexes.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.listIndexes('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/list-logs.md b/docs/examples/1.4.x/console-web/examples/databases/list-logs.md new file mode 100644 index 0000000000..3b3f0dcead --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/list-logs.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.listLogs('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/list.md b/docs/examples/1.4.x/console-web/examples/databases/list.md new file mode 100644 index 0000000000..20ae55793d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/list.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.list(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..629f8644b0 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-boolean-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateBooleanAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-collection.md b/docs/examples/1.4.x/console-web/examples/databases/update-collection.md new file mode 100644 index 0000000000..c0043b2500 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-collection.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateCollection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..f5be61d0e6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-datetime-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateDatetimeAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-document.md b/docs/examples/1.4.x/console-web/examples/databases/update-document.md new file mode 100644 index 0000000000..249af34648 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-document.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..e9a89a9436 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-email-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateEmailAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, 'email@example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..8f0d5b6842 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-enum-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateEnumAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], false, '[DEFAULT]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..72fcd77e7b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-float-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateFloatAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, null, null, null); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..d035b842b1 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-integer-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateIntegerAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, null, null, null); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..3373ae49ae --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-ip-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateIpAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..a329d5b6ad --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-relationship-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateRelationshipAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..69482531ed --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-string-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateStringAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, '[DEFAULT]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/console-web/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..481394021d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update-url-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.updateUrlAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, 'https://example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/databases/update.md b/docs/examples/1.4.x/console-web/examples/databases/update.md new file mode 100644 index 0000000000..a8160956e5 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/databases/update.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client(); + +const databases = new Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = databases.update('[DATABASE_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/create-build.md b/docs/examples/1.4.x/console-web/examples/functions/create-build.md new file mode 100644 index 0000000000..141bb3247c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/create-build.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.createBuild('[FUNCTION_ID]', '[DEPLOYMENT_ID]', '[BUILD_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/create-deployment.md b/docs/examples/1.4.x/console-web/examples/functions/create-deployment.md new file mode 100644 index 0000000000..6a97468f85 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/create-deployment.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.createDeployment('[FUNCTION_ID]', document.getElementById('uploader').files[0], false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/create-execution.md b/docs/examples/1.4.x/console-web/examples/functions/create-execution.md new file mode 100644 index 0000000000..cd623bb056 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/create-execution.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.createExecution('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/create-variable.md b/docs/examples/1.4.x/console-web/examples/functions/create-variable.md new file mode 100644 index 0000000000..df147ac2c8 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/create-variable.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.createVariable('[FUNCTION_ID]', '[KEY]', '[VALUE]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/create.md b/docs/examples/1.4.x/console-web/examples/functions/create.md new file mode 100644 index 0000000000..cbe62775f7 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/create.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.create('[FUNCTION_ID]', '[NAME]', 'node-14.5'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/delete-deployment.md b/docs/examples/1.4.x/console-web/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..9597da3dcf --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/delete-deployment.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.deleteDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/delete-variable.md b/docs/examples/1.4.x/console-web/examples/functions/delete-variable.md new file mode 100644 index 0000000000..30f2c031aa --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/delete-variable.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.deleteVariable('[FUNCTION_ID]', '[VARIABLE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/delete.md b/docs/examples/1.4.x/console-web/examples/functions/delete.md new file mode 100644 index 0000000000..3cfa756613 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/delete.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.delete('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/download-deployment.md b/docs/examples/1.4.x/console-web/examples/functions/download-deployment.md new file mode 100644 index 0000000000..fc514e7cb4 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/download-deployment.md @@ -0,0 +1,14 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = functions.downloadDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/get-deployment.md b/docs/examples/1.4.x/console-web/examples/functions/get-deployment.md new file mode 100644 index 0000000000..3a16587aca --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/get-deployment.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.getDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/get-execution.md b/docs/examples/1.4.x/console-web/examples/functions/get-execution.md new file mode 100644 index 0000000000..ac92b98af8 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/get-execution.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.getExecution('[FUNCTION_ID]', '[EXECUTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/get-function-usage.md b/docs/examples/1.4.x/console-web/examples/functions/get-function-usage.md new file mode 100644 index 0000000000..9ac20346ea --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/get-function-usage.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.getFunctionUsage('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/get-usage.md b/docs/examples/1.4.x/console-web/examples/functions/get-usage.md new file mode 100644 index 0000000000..6e3fe87860 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/get-usage.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.getUsage(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/get-variable.md b/docs/examples/1.4.x/console-web/examples/functions/get-variable.md new file mode 100644 index 0000000000..3d4b07f44e --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/get-variable.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.getVariable('[FUNCTION_ID]', '[VARIABLE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/get.md b/docs/examples/1.4.x/console-web/examples/functions/get.md new file mode 100644 index 0000000000..5cb2e28910 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/get.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.get('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/list-deployments.md b/docs/examples/1.4.x/console-web/examples/functions/list-deployments.md new file mode 100644 index 0000000000..bd63271f27 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/list-deployments.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.listDeployments('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/list-executions.md b/docs/examples/1.4.x/console-web/examples/functions/list-executions.md new file mode 100644 index 0000000000..5df980d48b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/list-executions.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.listExecutions('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/list-runtimes.md b/docs/examples/1.4.x/console-web/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..18f13b2c83 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/list-runtimes.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.listRuntimes(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/list-variables.md b/docs/examples/1.4.x/console-web/examples/functions/list-variables.md new file mode 100644 index 0000000000..5fd03bfc19 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/list-variables.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.listVariables('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/list.md b/docs/examples/1.4.x/console-web/examples/functions/list.md new file mode 100644 index 0000000000..721ad6bbb0 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/list.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.list(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/update-deployment.md b/docs/examples/1.4.x/console-web/examples/functions/update-deployment.md new file mode 100644 index 0000000000..98752326ef --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/update-deployment.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.updateDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/update-variable.md b/docs/examples/1.4.x/console-web/examples/functions/update-variable.md new file mode 100644 index 0000000000..33380ee102 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/update-variable.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.updateVariable('[FUNCTION_ID]', '[VARIABLE_ID]', '[KEY]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/functions/update.md b/docs/examples/1.4.x/console-web/examples/functions/update.md new file mode 100644 index 0000000000..ec062bc2c6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/functions/update.md @@ -0,0 +1,18 @@ +import { Client, Functions } from "@appwrite.io/console"; + +const client = new Client(); + +const functions = new Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = functions.update('[FUNCTION_ID]', '[NAME]', 'node-14.5'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/graphql/mutation.md b/docs/examples/1.4.x/console-web/examples/graphql/mutation.md new file mode 100644 index 0000000000..ee70c3630c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/graphql/mutation.md @@ -0,0 +1,18 @@ +import { Client, Graphql } from "@appwrite.io/console"; + +const client = new Client(); + +const graphql = new Graphql(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = graphql.mutation({}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/graphql/query.md b/docs/examples/1.4.x/console-web/examples/graphql/query.md new file mode 100644 index 0000000000..055c6ad002 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/graphql/query.md @@ -0,0 +1,18 @@ +import { Client, Graphql } from "@appwrite.io/console"; + +const client = new Client(); + +const graphql = new Graphql(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = graphql.query({}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-antivirus.md b/docs/examples/1.4.x/console-web/examples/health/get-antivirus.md new file mode 100644 index 0000000000..6d57550dd9 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-antivirus.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getAntivirus(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-cache.md b/docs/examples/1.4.x/console-web/examples/health/get-cache.md new file mode 100644 index 0000000000..5748c8e9dc --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-cache.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getCache(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-d-b.md b/docs/examples/1.4.x/console-web/examples/health/get-d-b.md new file mode 100644 index 0000000000..181dca7076 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-d-b.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getDB(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-pub-sub.md b/docs/examples/1.4.x/console-web/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..a56abb704d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-pub-sub.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getPubSub(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/console-web/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..29fcb6707a --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-queue-certificates.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getQueueCertificates(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-queue-functions.md b/docs/examples/1.4.x/console-web/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..0b011cb32d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-queue-functions.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getQueueFunctions(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-queue-logs.md b/docs/examples/1.4.x/console-web/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..2dc33b377b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-queue-logs.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getQueueLogs(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/console-web/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..534d68c7f4 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-queue-webhooks.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getQueueWebhooks(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-queue.md b/docs/examples/1.4.x/console-web/examples/health/get-queue.md new file mode 100644 index 0000000000..bdc3caf749 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-queue.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getQueue(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-storage-local.md b/docs/examples/1.4.x/console-web/examples/health/get-storage-local.md new file mode 100644 index 0000000000..ff842f4ba6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-storage-local.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getStorageLocal(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get-time.md b/docs/examples/1.4.x/console-web/examples/health/get-time.md new file mode 100644 index 0000000000..6d8e1c225a --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get-time.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.getTime(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/health/get.md b/docs/examples/1.4.x/console-web/examples/health/get.md new file mode 100644 index 0000000000..76e74be74c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/health/get.md @@ -0,0 +1,18 @@ +import { Client, Health } from "@appwrite.io/console"; + +const client = new Client(); + +const health = new Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = health.get(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/locale/get.md b/docs/examples/1.4.x/console-web/examples/locale/get.md new file mode 100644 index 0000000000..ac47468df8 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/locale/get.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "@appwrite.io/console"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.get(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/locale/list-codes.md b/docs/examples/1.4.x/console-web/examples/locale/list-codes.md new file mode 100644 index 0000000000..9cb13350b3 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/locale/list-codes.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "@appwrite.io/console"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCodes(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/locale/list-continents.md b/docs/examples/1.4.x/console-web/examples/locale/list-continents.md new file mode 100644 index 0000000000..b2358396fc --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/locale/list-continents.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "@appwrite.io/console"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listContinents(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/console-web/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..59d6e24dbf --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/locale/list-countries-e-u.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "@appwrite.io/console"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCountriesEU(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/console-web/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..898cb3cf31 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/locale/list-countries-phones.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "@appwrite.io/console"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCountriesPhones(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/locale/list-countries.md b/docs/examples/1.4.x/console-web/examples/locale/list-countries.md new file mode 100644 index 0000000000..a36b8c25ed --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/locale/list-countries.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "@appwrite.io/console"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCountries(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/locale/list-currencies.md b/docs/examples/1.4.x/console-web/examples/locale/list-currencies.md new file mode 100644 index 0000000000..1f34891425 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/locale/list-currencies.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "@appwrite.io/console"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listCurrencies(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/locale/list-languages.md b/docs/examples/1.4.x/console-web/examples/locale/list-languages.md new file mode 100644 index 0000000000..4fb4dbf0be --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/locale/list-languages.md @@ -0,0 +1,18 @@ +import { Client, Locale } from "@appwrite.io/console"; + +const client = new Client(); + +const locale = new Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = locale.listLanguages(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/create-appwrite-migration.md b/docs/examples/1.4.x/console-web/examples/migrations/create-appwrite-migration.md new file mode 100644 index 0000000000..7001e18204 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/create-appwrite-migration.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.createAppwriteMigration([], 'https://example.com', '[PROJECT_ID]', '[API_KEY]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/create-firebase-migration.md b/docs/examples/1.4.x/console-web/examples/migrations/create-firebase-migration.md new file mode 100644 index 0000000000..de5becb5ca --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/create-firebase-migration.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.createFirebaseMigration([], '[SERVICE_ACCOUNT]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/create-firebase-o-auth-migration.md b/docs/examples/1.4.x/console-web/examples/migrations/create-firebase-o-auth-migration.md new file mode 100644 index 0000000000..07e3efb080 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/create-firebase-o-auth-migration.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.createFirebaseOAuthMigration([], '[PROJECT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/create-n-host-migration.md b/docs/examples/1.4.x/console-web/examples/migrations/create-n-host-migration.md new file mode 100644 index 0000000000..b9a614d44a --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/create-n-host-migration.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.createNHostMigration([], '[SUBDOMAIN]', '[REGION]', '[ADMIN_SECRET]', '[DATABASE]', '[USERNAME]', '[PASSWORD]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/create-supabase-migration.md b/docs/examples/1.4.x/console-web/examples/migrations/create-supabase-migration.md new file mode 100644 index 0000000000..38b533f66b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/create-supabase-migration.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.createSupabaseMigration([], 'https://example.com', '[API_KEY]', '[DATABASE_HOST]', '[USERNAME]', '[PASSWORD]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/delete-firebase-auth.md b/docs/examples/1.4.x/console-web/examples/migrations/delete-firebase-auth.md new file mode 100644 index 0000000000..b7d890a28a --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/delete-firebase-auth.md @@ -0,0 +1,17 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = migrations.deleteFirebaseAuth(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/delete.md b/docs/examples/1.4.x/console-web/examples/migrations/delete.md new file mode 100644 index 0000000000..88d8262718 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/delete.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.delete('[MIGRATION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/get-appwrite-report.md b/docs/examples/1.4.x/console-web/examples/migrations/get-appwrite-report.md new file mode 100644 index 0000000000..0b922b2bc5 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/get-appwrite-report.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.getAppwriteReport([], 'https://example.com', '[PROJECT_ID]', '[KEY]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/get-firebase-report-o-auth.md b/docs/examples/1.4.x/console-web/examples/migrations/get-firebase-report-o-auth.md new file mode 100644 index 0000000000..7b52ac95b7 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/get-firebase-report-o-auth.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.getFirebaseReportOAuth([], '[PROJECT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/get-firebase-report.md b/docs/examples/1.4.x/console-web/examples/migrations/get-firebase-report.md new file mode 100644 index 0000000000..3764d786a6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/get-firebase-report.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.getFirebaseReport([], '[SERVICE_ACCOUNT]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/get-n-host-report.md b/docs/examples/1.4.x/console-web/examples/migrations/get-n-host-report.md new file mode 100644 index 0000000000..34d3404408 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/get-n-host-report.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.getNHostReport([], '[SUBDOMAIN]', '[REGION]', '[ADMIN_SECRET]', '[DATABASE]', '[USERNAME]', '[PASSWORD]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/get-supabase-report.md b/docs/examples/1.4.x/console-web/examples/migrations/get-supabase-report.md new file mode 100644 index 0000000000..00fbb9e56f --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/get-supabase-report.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.getSupabaseReport([], 'https://example.com', '[API_KEY]', '[DATABASE_HOST]', '[USERNAME]', '[PASSWORD]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/get.md b/docs/examples/1.4.x/console-web/examples/migrations/get.md new file mode 100644 index 0000000000..1331be2543 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/get.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.get('[MIGRATION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/list-firebase-projects.md b/docs/examples/1.4.x/console-web/examples/migrations/list-firebase-projects.md new file mode 100644 index 0000000000..e653144357 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/list-firebase-projects.md @@ -0,0 +1,17 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = migrations.listFirebaseProjects(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/list.md b/docs/examples/1.4.x/console-web/examples/migrations/list.md new file mode 100644 index 0000000000..61f7754aff --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/list.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.list(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/migrations/retry.md b/docs/examples/1.4.x/console-web/examples/migrations/retry.md new file mode 100644 index 0000000000..4c39d98c5d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/migrations/retry.md @@ -0,0 +1,18 @@ +import { Client, Migrations } from "@appwrite.io/console"; + +const client = new Client(); + +const migrations = new Migrations(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = migrations.retry('[MIGRATION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/project/create-variable.md b/docs/examples/1.4.x/console-web/examples/project/create-variable.md new file mode 100644 index 0000000000..94c0f04fe0 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/project/create-variable.md @@ -0,0 +1,18 @@ +import { Client, Project } from "@appwrite.io/console"; + +const client = new Client(); + +const project = new Project(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = project.createVariable('[KEY]', '[VALUE]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/project/delete-variable.md b/docs/examples/1.4.x/console-web/examples/project/delete-variable.md new file mode 100644 index 0000000000..23c4144e39 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/project/delete-variable.md @@ -0,0 +1,18 @@ +import { Client, Project } from "@appwrite.io/console"; + +const client = new Client(); + +const project = new Project(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = project.deleteVariable('[VARIABLE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/project/get-usage.md b/docs/examples/1.4.x/console-web/examples/project/get-usage.md new file mode 100644 index 0000000000..c831a06ff1 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/project/get-usage.md @@ -0,0 +1,18 @@ +import { Client, Project } from "@appwrite.io/console"; + +const client = new Client(); + +const project = new Project(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = project.getUsage(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/project/get-variable.md b/docs/examples/1.4.x/console-web/examples/project/get-variable.md new file mode 100644 index 0000000000..c147f638e5 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/project/get-variable.md @@ -0,0 +1,18 @@ +import { Client, Project } from "@appwrite.io/console"; + +const client = new Client(); + +const project = new Project(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = project.getVariable('[VARIABLE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/project/list-variables.md b/docs/examples/1.4.x/console-web/examples/project/list-variables.md new file mode 100644 index 0000000000..facfc32163 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/project/list-variables.md @@ -0,0 +1,18 @@ +import { Client, Project } from "@appwrite.io/console"; + +const client = new Client(); + +const project = new Project(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = project.listVariables(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/project/update-variable.md b/docs/examples/1.4.x/console-web/examples/project/update-variable.md new file mode 100644 index 0000000000..57590189dc --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/project/update-variable.md @@ -0,0 +1,18 @@ +import { Client, Project } from "@appwrite.io/console"; + +const client = new Client(); + +const project = new Project(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = project.updateVariable('[VARIABLE_ID]', '[KEY]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/create-key.md b/docs/examples/1.4.x/console-web/examples/projects/create-key.md new file mode 100644 index 0000000000..02032e81c5 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/create-key.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.createKey('[PROJECT_ID]', '[NAME]', []); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/create-platform.md b/docs/examples/1.4.x/console-web/examples/projects/create-platform.md new file mode 100644 index 0000000000..4a31968171 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/create-platform.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.createPlatform('[PROJECT_ID]', 'web', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/create-webhook.md b/docs/examples/1.4.x/console-web/examples/projects/create-webhook.md new file mode 100644 index 0000000000..356a5ffe86 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/create-webhook.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.createWebhook('[PROJECT_ID]', '[NAME]', [], 'https://example.com', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/create.md b/docs/examples/1.4.x/console-web/examples/projects/create.md new file mode 100644 index 0000000000..87eab0aea0 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/create.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.create('', '[NAME]', '[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/delete-email-template.md b/docs/examples/1.4.x/console-web/examples/projects/delete-email-template.md new file mode 100644 index 0000000000..0df4a1db5c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/delete-email-template.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.deleteEmailTemplate('[PROJECT_ID]', 'verification', 'af'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/delete-key.md b/docs/examples/1.4.x/console-web/examples/projects/delete-key.md new file mode 100644 index 0000000000..74c6bd1562 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/delete-key.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.deleteKey('[PROJECT_ID]', '[KEY_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/delete-platform.md b/docs/examples/1.4.x/console-web/examples/projects/delete-platform.md new file mode 100644 index 0000000000..da8ce56e54 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/delete-platform.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.deletePlatform('[PROJECT_ID]', '[PLATFORM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/delete-sms-template.md b/docs/examples/1.4.x/console-web/examples/projects/delete-sms-template.md new file mode 100644 index 0000000000..ba0bc8ead3 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/delete-sms-template.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.deleteSmsTemplate('[PROJECT_ID]', 'verification', 'af'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/delete-webhook.md b/docs/examples/1.4.x/console-web/examples/projects/delete-webhook.md new file mode 100644 index 0000000000..08e3af636f --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/delete-webhook.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.deleteWebhook('[PROJECT_ID]', '[WEBHOOK_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/delete.md b/docs/examples/1.4.x/console-web/examples/projects/delete.md new file mode 100644 index 0000000000..4f227a49a6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/delete.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.delete('[PROJECT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/get-email-template.md b/docs/examples/1.4.x/console-web/examples/projects/get-email-template.md new file mode 100644 index 0000000000..f7c193b95d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/get-email-template.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.getEmailTemplate('[PROJECT_ID]', 'verification', 'af'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/get-key.md b/docs/examples/1.4.x/console-web/examples/projects/get-key.md new file mode 100644 index 0000000000..c0d3282c14 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/get-key.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.getKey('[PROJECT_ID]', '[KEY_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/get-platform.md b/docs/examples/1.4.x/console-web/examples/projects/get-platform.md new file mode 100644 index 0000000000..fd65231aff --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/get-platform.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.getPlatform('[PROJECT_ID]', '[PLATFORM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/get-sms-template.md b/docs/examples/1.4.x/console-web/examples/projects/get-sms-template.md new file mode 100644 index 0000000000..5fce9ffcfb --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/get-sms-template.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.getSmsTemplate('[PROJECT_ID]', 'verification', 'af'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/get-usage.md b/docs/examples/1.4.x/console-web/examples/projects/get-usage.md new file mode 100644 index 0000000000..8d8c91355d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/get-usage.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.getUsage('[PROJECT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/get-webhook.md b/docs/examples/1.4.x/console-web/examples/projects/get-webhook.md new file mode 100644 index 0000000000..7f580b5f57 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/get-webhook.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.getWebhook('[PROJECT_ID]', '[WEBHOOK_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/get.md b/docs/examples/1.4.x/console-web/examples/projects/get.md new file mode 100644 index 0000000000..23c235a741 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/get.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.get('[PROJECT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/list-keys.md b/docs/examples/1.4.x/console-web/examples/projects/list-keys.md new file mode 100644 index 0000000000..c2dce0a419 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/list-keys.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.listKeys('[PROJECT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/list-platforms.md b/docs/examples/1.4.x/console-web/examples/projects/list-platforms.md new file mode 100644 index 0000000000..968438f6bb --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/list-platforms.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.listPlatforms('[PROJECT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/list-webhooks.md b/docs/examples/1.4.x/console-web/examples/projects/list-webhooks.md new file mode 100644 index 0000000000..e0e0af367f --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/list-webhooks.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.listWebhooks('[PROJECT_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/list.md b/docs/examples/1.4.x/console-web/examples/projects/list.md new file mode 100644 index 0000000000..0cf5002afe --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/list.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.list(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-auth-duration.md b/docs/examples/1.4.x/console-web/examples/projects/update-auth-duration.md new file mode 100644 index 0000000000..37c69222df --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-auth-duration.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateAuthDuration('[PROJECT_ID]', 0); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-auth-limit.md b/docs/examples/1.4.x/console-web/examples/projects/update-auth-limit.md new file mode 100644 index 0000000000..a63f5b4518 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-auth-limit.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateAuthLimit('[PROJECT_ID]', 0); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-auth-password-dictionary.md b/docs/examples/1.4.x/console-web/examples/projects/update-auth-password-dictionary.md new file mode 100644 index 0000000000..e3cb529d1b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-auth-password-dictionary.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateAuthPasswordDictionary('[PROJECT_ID]', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-auth-password-history.md b/docs/examples/1.4.x/console-web/examples/projects/update-auth-password-history.md new file mode 100644 index 0000000000..67b885d49d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-auth-password-history.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateAuthPasswordHistory('[PROJECT_ID]', 0); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-auth-sessions-limit.md b/docs/examples/1.4.x/console-web/examples/projects/update-auth-sessions-limit.md new file mode 100644 index 0000000000..ef2dffa67a --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-auth-sessions-limit.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateAuthSessionsLimit('[PROJECT_ID]', 1); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-auth-status.md b/docs/examples/1.4.x/console-web/examples/projects/update-auth-status.md new file mode 100644 index 0000000000..4751442d8f --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-auth-status.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateAuthStatus('[PROJECT_ID]', 'email-password', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-email-template.md b/docs/examples/1.4.x/console-web/examples/projects/update-email-template.md new file mode 100644 index 0000000000..b49594768a --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-email-template.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateEmailTemplate('[PROJECT_ID]', 'verification', 'af', '[SUBJECT]', '[MESSAGE]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-key.md b/docs/examples/1.4.x/console-web/examples/projects/update-key.md new file mode 100644 index 0000000000..fd2bde82bf --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-key.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateKey('[PROJECT_ID]', '[KEY_ID]', '[NAME]', []); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-o-auth2.md b/docs/examples/1.4.x/console-web/examples/projects/update-o-auth2.md new file mode 100644 index 0000000000..34ce814208 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-o-auth2.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateOAuth2('[PROJECT_ID]', 'amazon'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-personal-data-check.md b/docs/examples/1.4.x/console-web/examples/projects/update-personal-data-check.md new file mode 100644 index 0000000000..6165e91b80 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-personal-data-check.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updatePersonalDataCheck('[PROJECT_ID]', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-platform.md b/docs/examples/1.4.x/console-web/examples/projects/update-platform.md new file mode 100644 index 0000000000..ce49dfffd8 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-platform.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updatePlatform('[PROJECT_ID]', '[PLATFORM_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-service-status-all.md b/docs/examples/1.4.x/console-web/examples/projects/update-service-status-all.md new file mode 100644 index 0000000000..d348067194 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-service-status-all.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateServiceStatusAll('[PROJECT_ID]', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-service-status.md b/docs/examples/1.4.x/console-web/examples/projects/update-service-status.md new file mode 100644 index 0000000000..5b727003b0 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-service-status.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateServiceStatus('[PROJECT_ID]', 'account', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-sms-template.md b/docs/examples/1.4.x/console-web/examples/projects/update-sms-template.md new file mode 100644 index 0000000000..54edccd2aa --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-sms-template.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateSmsTemplate('[PROJECT_ID]', 'verification', 'af', '[MESSAGE]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-smtp-configuration.md b/docs/examples/1.4.x/console-web/examples/projects/update-smtp-configuration.md new file mode 100644 index 0000000000..54f344e3a6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-smtp-configuration.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateSmtpConfiguration('[PROJECT_ID]', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-team.md b/docs/examples/1.4.x/console-web/examples/projects/update-team.md new file mode 100644 index 0000000000..8b1c2f5665 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-team.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateTeam('[PROJECT_ID]', '[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-webhook-signature.md b/docs/examples/1.4.x/console-web/examples/projects/update-webhook-signature.md new file mode 100644 index 0000000000..472271f8e6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-webhook-signature.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateWebhookSignature('[PROJECT_ID]', '[WEBHOOK_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update-webhook.md b/docs/examples/1.4.x/console-web/examples/projects/update-webhook.md new file mode 100644 index 0000000000..1339a45822 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update-webhook.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.updateWebhook('[PROJECT_ID]', '[WEBHOOK_ID]', '[NAME]', [], 'https://example.com', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/projects/update.md b/docs/examples/1.4.x/console-web/examples/projects/update.md new file mode 100644 index 0000000000..31281808c4 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/projects/update.md @@ -0,0 +1,18 @@ +import { Client, Projects } from "@appwrite.io/console"; + +const client = new Client(); + +const projects = new Projects(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = projects.update('[PROJECT_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/proxy/create-rule.md b/docs/examples/1.4.x/console-web/examples/proxy/create-rule.md new file mode 100644 index 0000000000..fc11d86b97 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/proxy/create-rule.md @@ -0,0 +1,18 @@ +import { Client, Proxy } from "@appwrite.io/console"; + +const client = new Client(); + +const proxy = new Proxy(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = proxy.createRule('', 'api'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/proxy/delete-rule.md b/docs/examples/1.4.x/console-web/examples/proxy/delete-rule.md new file mode 100644 index 0000000000..f21e4f2528 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/proxy/delete-rule.md @@ -0,0 +1,18 @@ +import { Client, Proxy } from "@appwrite.io/console"; + +const client = new Client(); + +const proxy = new Proxy(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = proxy.deleteRule('[RULE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/proxy/get-rule.md b/docs/examples/1.4.x/console-web/examples/proxy/get-rule.md new file mode 100644 index 0000000000..99ddbca273 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/proxy/get-rule.md @@ -0,0 +1,18 @@ +import { Client, Proxy } from "@appwrite.io/console"; + +const client = new Client(); + +const proxy = new Proxy(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = proxy.getRule('[RULE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/proxy/list-rules.md b/docs/examples/1.4.x/console-web/examples/proxy/list-rules.md new file mode 100644 index 0000000000..baa277339c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/proxy/list-rules.md @@ -0,0 +1,18 @@ +import { Client, Proxy } from "@appwrite.io/console"; + +const client = new Client(); + +const proxy = new Proxy(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = proxy.listRules(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/proxy/update-rule-verification.md b/docs/examples/1.4.x/console-web/examples/proxy/update-rule-verification.md new file mode 100644 index 0000000000..33b442220c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/proxy/update-rule-verification.md @@ -0,0 +1,18 @@ +import { Client, Proxy } from "@appwrite.io/console"; + +const client = new Client(); + +const proxy = new Proxy(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = proxy.updateRuleVerification('[RULE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/create-bucket.md b/docs/examples/1.4.x/console-web/examples/storage/create-bucket.md new file mode 100644 index 0000000000..7696b14294 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/create-bucket.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.createBucket('[BUCKET_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/create-file.md b/docs/examples/1.4.x/console-web/examples/storage/create-file.md new file mode 100644 index 0000000000..d1bf55b42b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/create-file.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.createFile('[BUCKET_ID]', '[FILE_ID]', document.getElementById('uploader').files[0]); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/delete-bucket.md b/docs/examples/1.4.x/console-web/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..4634b11f5b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/delete-bucket.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.deleteBucket('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/delete-file.md b/docs/examples/1.4.x/console-web/examples/storage/delete-file.md new file mode 100644 index 0000000000..b4c0ff0f9d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/delete-file.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.deleteFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/get-bucket-usage.md b/docs/examples/1.4.x/console-web/examples/storage/get-bucket-usage.md new file mode 100644 index 0000000000..65c66d7aa0 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/get-bucket-usage.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.getBucketUsage('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/get-bucket.md b/docs/examples/1.4.x/console-web/examples/storage/get-bucket.md new file mode 100644 index 0000000000..2b65e8b0ce --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/get-bucket.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.getBucket('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/get-file-download.md b/docs/examples/1.4.x/console-web/examples/storage/get-file-download.md new file mode 100644 index 0000000000..1ce57cb38a --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/get-file-download.md @@ -0,0 +1,14 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = storage.getFileDownload('[BUCKET_ID]', '[FILE_ID]'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/get-file-preview.md b/docs/examples/1.4.x/console-web/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..ab6bc18fc4 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/get-file-preview.md @@ -0,0 +1,14 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = storage.getFilePreview('[BUCKET_ID]', '[FILE_ID]'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/get-file-view.md b/docs/examples/1.4.x/console-web/examples/storage/get-file-view.md new file mode 100644 index 0000000000..7ce851f025 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/get-file-view.md @@ -0,0 +1,14 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const result = storage.getFileView('[BUCKET_ID]', '[FILE_ID]'); + +console.log(result); // Resource URL \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/get-file.md b/docs/examples/1.4.x/console-web/examples/storage/get-file.md new file mode 100644 index 0000000000..b6e800303d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/get-file.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.getFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/get-usage.md b/docs/examples/1.4.x/console-web/examples/storage/get-usage.md new file mode 100644 index 0000000000..f618ba4e16 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/get-usage.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.getUsage(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/list-buckets.md b/docs/examples/1.4.x/console-web/examples/storage/list-buckets.md new file mode 100644 index 0000000000..5a356900fa --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/list-buckets.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.listBuckets(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/list-files.md b/docs/examples/1.4.x/console-web/examples/storage/list-files.md new file mode 100644 index 0000000000..0c6170f11d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/list-files.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.listFiles('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/update-bucket.md b/docs/examples/1.4.x/console-web/examples/storage/update-bucket.md new file mode 100644 index 0000000000..09ed4ce441 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/update-bucket.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.updateBucket('[BUCKET_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/storage/update-file.md b/docs/examples/1.4.x/console-web/examples/storage/update-file.md new file mode 100644 index 0000000000..abaaf9afd4 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/storage/update-file.md @@ -0,0 +1,18 @@ +import { Client, Storage } from "@appwrite.io/console"; + +const client = new Client(); + +const storage = new Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = storage.updateFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/create-membership.md b/docs/examples/1.4.x/console-web/examples/teams/create-membership.md new file mode 100644 index 0000000000..ddd4861137 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/create-membership.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.createMembership('[TEAM_ID]', [], 'https://example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/create.md b/docs/examples/1.4.x/console-web/examples/teams/create.md new file mode 100644 index 0000000000..a2cb34296b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/create.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.create('[TEAM_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/delete-membership.md b/docs/examples/1.4.x/console-web/examples/teams/delete-membership.md new file mode 100644 index 0000000000..4e7d7e7a74 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/delete-membership.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.deleteMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/delete.md b/docs/examples/1.4.x/console-web/examples/teams/delete.md new file mode 100644 index 0000000000..0bc778ba63 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/delete.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.delete('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/get-membership.md b/docs/examples/1.4.x/console-web/examples/teams/get-membership.md new file mode 100644 index 0000000000..c0bdae5fc6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/get-membership.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.getMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/get-prefs.md b/docs/examples/1.4.x/console-web/examples/teams/get-prefs.md new file mode 100644 index 0000000000..2104c5f898 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/get-prefs.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.getPrefs('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/get.md b/docs/examples/1.4.x/console-web/examples/teams/get.md new file mode 100644 index 0000000000..2dbfdb4b0b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/get.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.get('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/list-logs.md b/docs/examples/1.4.x/console-web/examples/teams/list-logs.md new file mode 100644 index 0000000000..2c3c7311e2 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/list-logs.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.listLogs('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/list-memberships.md b/docs/examples/1.4.x/console-web/examples/teams/list-memberships.md new file mode 100644 index 0000000000..f7a7d1a54e --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/list-memberships.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.listMemberships('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/list.md b/docs/examples/1.4.x/console-web/examples/teams/list.md new file mode 100644 index 0000000000..99e482d8f3 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/list.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.list(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/update-membership-status.md b/docs/examples/1.4.x/console-web/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..1c8ec3a27e --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/update-membership-status.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.updateMembershipStatus('[TEAM_ID]', '[MEMBERSHIP_ID]', '[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/update-membership.md b/docs/examples/1.4.x/console-web/examples/teams/update-membership.md new file mode 100644 index 0000000000..1f9051fa77 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/update-membership.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.updateMembership('[TEAM_ID]', '[MEMBERSHIP_ID]', []); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/update-name.md b/docs/examples/1.4.x/console-web/examples/teams/update-name.md new file mode 100644 index 0000000000..4bee8deb52 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/update-name.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.updateName('[TEAM_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/teams/update-prefs.md b/docs/examples/1.4.x/console-web/examples/teams/update-prefs.md new file mode 100644 index 0000000000..7d7ed63328 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/teams/update-prefs.md @@ -0,0 +1,18 @@ +import { Client, Teams } from "@appwrite.io/console"; + +const client = new Client(); + +const teams = new Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = teams.updatePrefs('[TEAM_ID]', {}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/create-argon2user.md b/docs/examples/1.4.x/console-web/examples/users/create-argon2user.md new file mode 100644 index 0000000000..f4dabafe18 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/create-argon2user.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.createArgon2User('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/console-web/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..247f579c9c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/create-bcrypt-user.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.createBcryptUser('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/create-m-d5user.md b/docs/examples/1.4.x/console-web/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..8a81f0801b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/create-m-d5user.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.createMD5User('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/console-web/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..f7297c1023 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/create-p-h-pass-user.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.createPHPassUser('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/console-web/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..3cefaf17df --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/create-s-h-a-user.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.createSHAUser('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/console-web/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..d8889fa229 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.createScryptModifiedUser('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', '[PASSWORD_SALT_SEPARATOR]', '[PASSWORD_SIGNER_KEY]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/console-web/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..3c4b357e4c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/create-scrypt-user.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.createScryptUser('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', null, null, null, null); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/create.md b/docs/examples/1.4.x/console-web/examples/users/create.md new file mode 100644 index 0000000000..845895d6a5 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/create.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.create('[USER_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/delete-identity.md b/docs/examples/1.4.x/console-web/examples/users/delete-identity.md new file mode 100644 index 0000000000..d2aa30d34b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/delete-identity.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.deleteIdentity('[IDENTITY_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/delete-session.md b/docs/examples/1.4.x/console-web/examples/users/delete-session.md new file mode 100644 index 0000000000..70404ca574 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/delete-session.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.deleteSession('[USER_ID]', '[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/delete-sessions.md b/docs/examples/1.4.x/console-web/examples/users/delete-sessions.md new file mode 100644 index 0000000000..b02771c709 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/delete-sessions.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.deleteSessions('[USER_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/delete.md b/docs/examples/1.4.x/console-web/examples/users/delete.md new file mode 100644 index 0000000000..0bb95c395b --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/delete.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.delete('[USER_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/get-prefs.md b/docs/examples/1.4.x/console-web/examples/users/get-prefs.md new file mode 100644 index 0000000000..593552bd03 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/get-prefs.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.getPrefs('[USER_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/get-usage.md b/docs/examples/1.4.x/console-web/examples/users/get-usage.md new file mode 100644 index 0000000000..59d95e6dcb --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/get-usage.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.getUsage(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/get.md b/docs/examples/1.4.x/console-web/examples/users/get.md new file mode 100644 index 0000000000..46cee750f7 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/get.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.get('[USER_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/list-identities.md b/docs/examples/1.4.x/console-web/examples/users/list-identities.md new file mode 100644 index 0000000000..214fa9728d --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/list-identities.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.listIdentities(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/list-logs.md b/docs/examples/1.4.x/console-web/examples/users/list-logs.md new file mode 100644 index 0000000000..ded1e98b40 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/list-logs.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.listLogs('[USER_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/list-memberships.md b/docs/examples/1.4.x/console-web/examples/users/list-memberships.md new file mode 100644 index 0000000000..b47f7acf57 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/list-memberships.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.listMemberships('[USER_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/list-sessions.md b/docs/examples/1.4.x/console-web/examples/users/list-sessions.md new file mode 100644 index 0000000000..087834e569 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/list-sessions.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.listSessions('[USER_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/list.md b/docs/examples/1.4.x/console-web/examples/users/list.md new file mode 100644 index 0000000000..28a8258b12 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/list.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.list(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/update-email-verification.md b/docs/examples/1.4.x/console-web/examples/users/update-email-verification.md new file mode 100644 index 0000000000..019b072371 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/update-email-verification.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.updateEmailVerification('[USER_ID]', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/update-email.md b/docs/examples/1.4.x/console-web/examples/users/update-email.md new file mode 100644 index 0000000000..e37d03a01c --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/update-email.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.updateEmail('[USER_ID]', 'email@example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/update-labels.md b/docs/examples/1.4.x/console-web/examples/users/update-labels.md new file mode 100644 index 0000000000..9d61425d70 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/update-labels.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.updateLabels('[USER_ID]', []); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/update-name.md b/docs/examples/1.4.x/console-web/examples/users/update-name.md new file mode 100644 index 0000000000..2834c747da --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/update-name.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.updateName('[USER_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/update-password.md b/docs/examples/1.4.x/console-web/examples/users/update-password.md new file mode 100644 index 0000000000..5192abda89 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/update-password.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.updatePassword('[USER_ID]', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/update-phone-verification.md b/docs/examples/1.4.x/console-web/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..17ddf467d9 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/update-phone-verification.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.updatePhoneVerification('[USER_ID]', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/update-phone.md b/docs/examples/1.4.x/console-web/examples/users/update-phone.md new file mode 100644 index 0000000000..a1d85aaaca --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/update-phone.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.updatePhone('[USER_ID]', '+12065550100'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/update-prefs.md b/docs/examples/1.4.x/console-web/examples/users/update-prefs.md new file mode 100644 index 0000000000..e3c5b76c2a --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/update-prefs.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.updatePrefs('[USER_ID]', {}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/users/update-status.md b/docs/examples/1.4.x/console-web/examples/users/update-status.md new file mode 100644 index 0000000000..eafbec728f --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/users/update-status.md @@ -0,0 +1,18 @@ +import { Client, Users } from "@appwrite.io/console"; + +const client = new Client(); + +const users = new Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID +; + +const promise = users.updateStatus('[USER_ID]', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/vcs/create-repository-detection.md b/docs/examples/1.4.x/console-web/examples/vcs/create-repository-detection.md new file mode 100644 index 0000000000..cc445939e0 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/vcs/create-repository-detection.md @@ -0,0 +1,17 @@ +import { Client, Vcs } from "@appwrite.io/console"; + +const client = new Client(); + +const vcs = new Vcs(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = vcs.createRepositoryDetection('[INSTALLATION_ID]', '[PROVIDER_REPOSITORY_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/vcs/create-repository.md b/docs/examples/1.4.x/console-web/examples/vcs/create-repository.md new file mode 100644 index 0000000000..7dbc238034 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/vcs/create-repository.md @@ -0,0 +1,17 @@ +import { Client, Vcs } from "@appwrite.io/console"; + +const client = new Client(); + +const vcs = new Vcs(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = vcs.createRepository('[INSTALLATION_ID]', '[NAME]', false); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/vcs/delete-installation.md b/docs/examples/1.4.x/console-web/examples/vcs/delete-installation.md new file mode 100644 index 0000000000..390b5afc24 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/vcs/delete-installation.md @@ -0,0 +1,17 @@ +import { Client, Vcs } from "@appwrite.io/console"; + +const client = new Client(); + +const vcs = new Vcs(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = vcs.deleteInstallation('[INSTALLATION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/vcs/get-installation.md b/docs/examples/1.4.x/console-web/examples/vcs/get-installation.md new file mode 100644 index 0000000000..c3fb9861d8 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/vcs/get-installation.md @@ -0,0 +1,17 @@ +import { Client, Vcs } from "@appwrite.io/console"; + +const client = new Client(); + +const vcs = new Vcs(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = vcs.getInstallation('[INSTALLATION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/vcs/get-repository.md b/docs/examples/1.4.x/console-web/examples/vcs/get-repository.md new file mode 100644 index 0000000000..63253a6aed --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/vcs/get-repository.md @@ -0,0 +1,17 @@ +import { Client, Vcs } from "@appwrite.io/console"; + +const client = new Client(); + +const vcs = new Vcs(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = vcs.getRepository('[INSTALLATION_ID]', '[PROVIDER_REPOSITORY_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/vcs/list-installations.md b/docs/examples/1.4.x/console-web/examples/vcs/list-installations.md new file mode 100644 index 0000000000..474fb07ea6 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/vcs/list-installations.md @@ -0,0 +1,17 @@ +import { Client, Vcs } from "@appwrite.io/console"; + +const client = new Client(); + +const vcs = new Vcs(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = vcs.listInstallations(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/vcs/list-repositories.md b/docs/examples/1.4.x/console-web/examples/vcs/list-repositories.md new file mode 100644 index 0000000000..db4920f960 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/vcs/list-repositories.md @@ -0,0 +1,17 @@ +import { Client, Vcs } from "@appwrite.io/console"; + +const client = new Client(); + +const vcs = new Vcs(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = vcs.listRepositories('[INSTALLATION_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/vcs/list-repository-branches.md b/docs/examples/1.4.x/console-web/examples/vcs/list-repository-branches.md new file mode 100644 index 0000000000..f29ff96fda --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/vcs/list-repository-branches.md @@ -0,0 +1,17 @@ +import { Client, Vcs } from "@appwrite.io/console"; + +const client = new Client(); + +const vcs = new Vcs(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = vcs.listRepositoryBranches('[INSTALLATION_ID]', '[PROVIDER_REPOSITORY_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/console-web/examples/vcs/update-external-deployments.md b/docs/examples/1.4.x/console-web/examples/vcs/update-external-deployments.md new file mode 100644 index 0000000000..648ce30785 --- /dev/null +++ b/docs/examples/1.4.x/console-web/examples/vcs/update-external-deployments.md @@ -0,0 +1,17 @@ +import { Client, Vcs } from "@appwrite.io/console"; + +const client = new Client(); + +const vcs = new Vcs(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint +; + +const promise = vcs.updateExternalDeployments('[INSTALLATION_ID]', '[REPOSITORY_ID]', '[PROVIDER_PULL_REQUEST_ID]'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-dart/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..912f8c3b1e --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/create-phone-verification.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.createPhoneVerification(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/create-recovery.md b/docs/examples/1.4.x/server-dart/examples/account/create-recovery.md new file mode 100644 index 0000000000..d9f13957c7 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/create-recovery.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.createRecovery( + email: 'email@example.com', + url: 'https://example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/create-verification.md b/docs/examples/1.4.x/server-dart/examples/account/create-verification.md new file mode 100644 index 0000000000..cca3c7b774 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/create-verification.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.createVerification( + url: 'https://example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/delete-identity.md b/docs/examples/1.4.x/server-dart/examples/account/delete-identity.md new file mode 100644 index 0000000000..7b8f09a353 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/delete-identity.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.deleteIdentity( + identityId: '[IDENTITY_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/delete-session.md b/docs/examples/1.4.x/server-dart/examples/account/delete-session.md new file mode 100644 index 0000000000..9486ec9b80 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/delete-session.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.deleteSession( + sessionId: '[SESSION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-dart/examples/account/delete-sessions.md new file mode 100644 index 0000000000..a5732cb68e --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/delete-sessions.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.deleteSessions(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/get-prefs.md b/docs/examples/1.4.x/server-dart/examples/account/get-prefs.md new file mode 100644 index 0000000000..527a71f3b1 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/get-prefs.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.getPrefs(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/get-session.md b/docs/examples/1.4.x/server-dart/examples/account/get-session.md new file mode 100644 index 0000000000..6eb711ab4d --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/get-session.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.getSession( + sessionId: '[SESSION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/get.md b/docs/examples/1.4.x/server-dart/examples/account/get.md new file mode 100644 index 0000000000..c72fdddb10 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/get.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.get(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/list-identities.md b/docs/examples/1.4.x/server-dart/examples/account/list-identities.md new file mode 100644 index 0000000000..63789e529f --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/list-identities.md @@ -0,0 +1,22 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.listIdentities( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/list-logs.md b/docs/examples/1.4.x/server-dart/examples/account/list-logs.md new file mode 100644 index 0000000000..68d2c49f74 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/list-logs.md @@ -0,0 +1,22 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.listLogs( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/list-sessions.md b/docs/examples/1.4.x/server-dart/examples/account/list-sessions.md new file mode 100644 index 0000000000..0d6567b5f3 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/list-sessions.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.listSessions(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-email.md b/docs/examples/1.4.x/server-dart/examples/account/update-email.md new file mode 100644 index 0000000000..b83f7d86da --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-email.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updateEmail( + email: 'email@example.com', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-name.md b/docs/examples/1.4.x/server-dart/examples/account/update-name.md new file mode 100644 index 0000000000..0bd27cf204 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-name.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updateName( + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-password.md b/docs/examples/1.4.x/server-dart/examples/account/update-password.md new file mode 100644 index 0000000000..d5e27a7574 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-password.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updatePassword( + password: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-dart/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..f2995b9b93 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-phone-verification.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updatePhoneVerification( + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-phone.md b/docs/examples/1.4.x/server-dart/examples/account/update-phone.md new file mode 100644 index 0000000000..5848da5d10 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-phone.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updatePhone( + phone: '+12065550100', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-prefs.md b/docs/examples/1.4.x/server-dart/examples/account/update-prefs.md new file mode 100644 index 0000000000..ffbe700288 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-prefs.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updatePrefs( + prefs: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-recovery.md b/docs/examples/1.4.x/server-dart/examples/account/update-recovery.md new file mode 100644 index 0000000000..c2cf9d2396 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-recovery.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updateRecovery( + userId: '[USER_ID]', + secret: '[SECRET]', + password: 'password', + passwordAgain: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-session.md b/docs/examples/1.4.x/server-dart/examples/account/update-session.md new file mode 100644 index 0000000000..61e11e27af --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-session.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updateSession( + sessionId: '[SESSION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-status.md b/docs/examples/1.4.x/server-dart/examples/account/update-status.md new file mode 100644 index 0000000000..12f733334a --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-status.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updateStatus(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/account/update-verification.md b/docs/examples/1.4.x/server-dart/examples/account/update-verification.md new file mode 100644 index 0000000000..40e36426a1 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/account/update-verification.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = account.updateVerification( + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-dart/examples/avatars/get-browser.md new file mode 100644 index 0000000000..0bac9df4ef --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/avatars/get-browser.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = avatars.getBrowser( + code: 'aa', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-dart/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..b9a8166e48 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/avatars/get-credit-card.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = avatars.getCreditCard( + code: 'amex', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-dart/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..6a728e7792 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/avatars/get-favicon.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = avatars.getFavicon( + url: 'https://example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-dart/examples/avatars/get-flag.md new file mode 100644 index 0000000000..02e4880926 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/avatars/get-flag.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = avatars.getFlag( + code: 'af', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/avatars/get-image.md b/docs/examples/1.4.x/server-dart/examples/avatars/get-image.md new file mode 100644 index 0000000000..b1d5e33884 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/avatars/get-image.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = avatars.getImage( + url: 'https://example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-dart/examples/avatars/get-initials.md new file mode 100644 index 0000000000..5a68caf1d9 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/avatars/get-initials.md @@ -0,0 +1,22 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = avatars.getInitials( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-dart/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..8283b9bdf4 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/avatars/get-q-r.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Avatars avatars = Avatars(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = avatars.getQR( + text: '[TEXT]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..224719685b --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-boolean-attribute.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createBooleanAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-collection.md b/docs/examples/1.4.x/server-dart/examples/databases/create-collection.md new file mode 100644 index 0000000000..c90183deed --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-collection.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createCollection( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..24c44088f3 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-datetime-attribute.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createDatetimeAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-document.md b/docs/examples/1.4.x/server-dart/examples/databases/create-document.md new file mode 100644 index 0000000000..00d844da0f --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-document.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: '[DOCUMENT_ID]', + data: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..92fd32037b --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-email-attribute.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createEmailAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..fa8ad92015 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-enum-attribute.md @@ -0,0 +1,27 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createEnumAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + elements: [], + xrequired: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..96047bf2b2 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-float-attribute.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createFloatAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-index.md b/docs/examples/1.4.x/server-dart/examples/databases/create-index.md new file mode 100644 index 0000000000..c16a02719e --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-index.md @@ -0,0 +1,27 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createIndex( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + type: 'key', + attributes: [], + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..bc4f12f0c4 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-integer-attribute.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createIntegerAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..ef3e985a38 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-ip-attribute.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createIpAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..01f2b42f75 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-relationship-attribute.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createRelationshipAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + relatedCollectionId: '[RELATED_COLLECTION_ID]', + type: 'oneToOne', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..14f2769dbb --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-string-attribute.md @@ -0,0 +1,27 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createStringAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + size: 1, + xrequired: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..4cf3e99a72 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create-url-attribute.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.createUrlAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/create.md b/docs/examples/1.4.x/server-dart/examples/databases/create.md new file mode 100644 index 0000000000..cbaf3b742d --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/create.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.create( + databaseId: '[DATABASE_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..e9865bfe22 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/delete-attribute.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.deleteAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-dart/examples/databases/delete-collection.md new file mode 100644 index 0000000000..5886920115 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/delete-collection.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.deleteCollection( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/delete-document.md b/docs/examples/1.4.x/server-dart/examples/databases/delete-document.md new file mode 100644 index 0000000000..0d298f3b42 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/delete-document.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.deleteDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: '[DOCUMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/delete-index.md b/docs/examples/1.4.x/server-dart/examples/databases/delete-index.md new file mode 100644 index 0000000000..be5b2a5c9f --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/delete-index.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.deleteIndex( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/delete.md b/docs/examples/1.4.x/server-dart/examples/databases/delete.md new file mode 100644 index 0000000000..ff19beea69 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/delete.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.delete( + databaseId: '[DATABASE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/get-attribute.md new file mode 100644 index 0000000000..c27ddb648c --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/get-attribute.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.getAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/get-collection.md b/docs/examples/1.4.x/server-dart/examples/databases/get-collection.md new file mode 100644 index 0000000000..359f0df829 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/get-collection.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.getCollection( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/get-document.md b/docs/examples/1.4.x/server-dart/examples/databases/get-document.md new file mode 100644 index 0000000000..2141abf4be --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/get-document.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.getDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: '[DOCUMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/get-index.md b/docs/examples/1.4.x/server-dart/examples/databases/get-index.md new file mode 100644 index 0000000000..2b8a90318d --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/get-index.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.getIndex( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/get.md b/docs/examples/1.4.x/server-dart/examples/databases/get.md new file mode 100644 index 0000000000..f0cc118b96 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/get.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.get( + databaseId: '[DATABASE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-dart/examples/databases/list-attributes.md new file mode 100644 index 0000000000..60ca58f3c3 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/list-attributes.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.listAttributes( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/list-collections.md b/docs/examples/1.4.x/server-dart/examples/databases/list-collections.md new file mode 100644 index 0000000000..a10038db11 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/list-collections.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.listCollections( + databaseId: '[DATABASE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/list-documents.md b/docs/examples/1.4.x/server-dart/examples/databases/list-documents.md new file mode 100644 index 0000000000..70299774fb --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/list-documents.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.listDocuments( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-dart/examples/databases/list-indexes.md new file mode 100644 index 0000000000..6703ebf35a --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/list-indexes.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.listIndexes( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/list.md b/docs/examples/1.4.x/server-dart/examples/databases/list.md new file mode 100644 index 0000000000..d9bd06ad34 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/list.md @@ -0,0 +1,22 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.list( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..94853d2819 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-boolean-attribute.md @@ -0,0 +1,27 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateBooleanAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + xdefault: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-collection.md b/docs/examples/1.4.x/server-dart/examples/databases/update-collection.md new file mode 100644 index 0000000000..a5f32dead1 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-collection.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateCollection( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..f93aa81500 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-datetime-attribute.md @@ -0,0 +1,27 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateDatetimeAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + xdefault: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-document.md b/docs/examples/1.4.x/server-dart/examples/databases/update-document.md new file mode 100644 index 0000000000..fb08413f2f --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-document.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateDocument( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + documentId: '[DOCUMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..8fd104db32 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-email-attribute.md @@ -0,0 +1,27 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateEmailAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + xdefault: 'email@example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..20c44817ef --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-enum-attribute.md @@ -0,0 +1,28 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateEnumAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + elements: [], + xrequired: false, + xdefault: '[DEFAULT]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..50432542c6 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-float-attribute.md @@ -0,0 +1,29 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateFloatAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + min: 0, + max: 0, + xdefault: 0, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..2d3da6ced6 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-integer-attribute.md @@ -0,0 +1,29 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateIntegerAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + min: 0, + max: 0, + xdefault: 0, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..8c4cf4f3f2 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-ip-attribute.md @@ -0,0 +1,27 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateIpAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + xdefault: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..239e23daab --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-relationship-attribute.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateRelationshipAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..7f24507aba --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-string-attribute.md @@ -0,0 +1,27 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateStringAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + xdefault: '[DEFAULT]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-dart/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..d7dd6758bb --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update-url-attribute.md @@ -0,0 +1,27 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.updateUrlAttribute( + databaseId: '[DATABASE_ID]', + collectionId: '[COLLECTION_ID]', + key: '', + xrequired: false, + xdefault: 'https://example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/databases/update.md b/docs/examples/1.4.x/server-dart/examples/databases/update.md new file mode 100644 index 0000000000..59070cefa9 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/databases/update.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Databases databases = Databases(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = databases.update( + databaseId: '[DATABASE_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/create-build.md b/docs/examples/1.4.x/server-dart/examples/functions/create-build.md new file mode 100644 index 0000000000..530ba6deab --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/create-build.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.createBuild( + functionId: '[FUNCTION_ID]', + deploymentId: '[DEPLOYMENT_ID]', + buildId: '[BUILD_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-dart/examples/functions/create-deployment.md new file mode 100644 index 0000000000..8be0f1a725 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/create-deployment.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.createDeployment( + functionId: '[FUNCTION_ID]', + code: InputFile(path: './path-to-files/image.jpg', filename: 'image.jpg'), + activate: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/create-execution.md b/docs/examples/1.4.x/server-dart/examples/functions/create-execution.md new file mode 100644 index 0000000000..f5de49f7cf --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/create-execution.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.createExecution( + functionId: '[FUNCTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/create-variable.md b/docs/examples/1.4.x/server-dart/examples/functions/create-variable.md new file mode 100644 index 0000000000..50cd063ca1 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/create-variable.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.createVariable( + functionId: '[FUNCTION_ID]', + key: '[KEY]', + value: '[VALUE]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/create.md b/docs/examples/1.4.x/server-dart/examples/functions/create.md new file mode 100644 index 0000000000..839c6f6edd --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/create.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.create( + functionId: '[FUNCTION_ID]', + name: '[NAME]', + runtime: 'node-14.5', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-dart/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..e65380c501 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/delete-deployment.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.deleteDeployment( + functionId: '[FUNCTION_ID]', + deploymentId: '[DEPLOYMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-dart/examples/functions/delete-variable.md new file mode 100644 index 0000000000..87c7f407b5 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/delete-variable.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.deleteVariable( + functionId: '[FUNCTION_ID]', + variableId: '[VARIABLE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/delete.md b/docs/examples/1.4.x/server-dart/examples/functions/delete.md new file mode 100644 index 0000000000..5163366912 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/delete.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.delete( + functionId: '[FUNCTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-dart/examples/functions/download-deployment.md new file mode 100644 index 0000000000..d77d3aaff8 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/download-deployment.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.downloadDeployment( + functionId: '[FUNCTION_ID]', + deploymentId: '[DEPLOYMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-dart/examples/functions/get-deployment.md new file mode 100644 index 0000000000..9cab571e94 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/get-deployment.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.getDeployment( + functionId: '[FUNCTION_ID]', + deploymentId: '[DEPLOYMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/get-execution.md b/docs/examples/1.4.x/server-dart/examples/functions/get-execution.md new file mode 100644 index 0000000000..6cadde6426 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/get-execution.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.getExecution( + functionId: '[FUNCTION_ID]', + executionId: '[EXECUTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/get-variable.md b/docs/examples/1.4.x/server-dart/examples/functions/get-variable.md new file mode 100644 index 0000000000..924bee2bff --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/get-variable.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.getVariable( + functionId: '[FUNCTION_ID]', + variableId: '[VARIABLE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/get.md b/docs/examples/1.4.x/server-dart/examples/functions/get.md new file mode 100644 index 0000000000..503ab20709 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/get.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.get( + functionId: '[FUNCTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-dart/examples/functions/list-deployments.md new file mode 100644 index 0000000000..b12f9eba87 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/list-deployments.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.listDeployments( + functionId: '[FUNCTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/list-executions.md b/docs/examples/1.4.x/server-dart/examples/functions/list-executions.md new file mode 100644 index 0000000000..3d66a4496a --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/list-executions.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.listExecutions( + functionId: '[FUNCTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-dart/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..091a1116f7 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/list-runtimes.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.listRuntimes(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/list-variables.md b/docs/examples/1.4.x/server-dart/examples/functions/list-variables.md new file mode 100644 index 0000000000..f3c6655b14 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/list-variables.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.listVariables( + functionId: '[FUNCTION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/list.md b/docs/examples/1.4.x/server-dart/examples/functions/list.md new file mode 100644 index 0000000000..4f2b11404d --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/list.md @@ -0,0 +1,22 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.list( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-dart/examples/functions/update-deployment.md new file mode 100644 index 0000000000..d503aecb3b --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/update-deployment.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.updateDeployment( + functionId: '[FUNCTION_ID]', + deploymentId: '[DEPLOYMENT_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/update-variable.md b/docs/examples/1.4.x/server-dart/examples/functions/update-variable.md new file mode 100644 index 0000000000..126d264470 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/update-variable.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.updateVariable( + functionId: '[FUNCTION_ID]', + variableId: '[VARIABLE_ID]', + key: '[KEY]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/functions/update.md b/docs/examples/1.4.x/server-dart/examples/functions/update.md new file mode 100644 index 0000000000..86295b4ea3 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/functions/update.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Functions functions = Functions(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = functions.update( + functionId: '[FUNCTION_ID]', + name: '[NAME]', + runtime: 'node-14.5', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/graphql/mutation.md b/docs/examples/1.4.x/server-dart/examples/graphql/mutation.md new file mode 100644 index 0000000000..780ee09f4a --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/graphql/mutation.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Graphql graphql = Graphql(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = graphql.mutation( + query: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/graphql/query.md b/docs/examples/1.4.x/server-dart/examples/graphql/query.md new file mode 100644 index 0000000000..7f22f5360d --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/graphql/query.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Graphql graphql = Graphql(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = graphql.query( + query: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-dart/examples/health/get-antivirus.md new file mode 100644 index 0000000000..922dcfa136 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-antivirus.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getAntivirus(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-cache.md b/docs/examples/1.4.x/server-dart/examples/health/get-cache.md new file mode 100644 index 0000000000..4b63edeee3 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-cache.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getCache(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-d-b.md b/docs/examples/1.4.x/server-dart/examples/health/get-d-b.md new file mode 100644 index 0000000000..65188c096e --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-d-b.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getDB(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-dart/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..ef20bed89f --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-pub-sub.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getPubSub(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-dart/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..4063ab3514 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-queue-certificates.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getQueueCertificates(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-dart/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..5ebaad6484 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-queue-functions.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getQueueFunctions(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-dart/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..11a5285439 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-queue-logs.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getQueueLogs(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-dart/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..a43f5f8423 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-queue-webhooks.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getQueueWebhooks(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-queue.md b/docs/examples/1.4.x/server-dart/examples/health/get-queue.md new file mode 100644 index 0000000000..8b7c823dc7 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-queue.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getQueue(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-dart/examples/health/get-storage-local.md new file mode 100644 index 0000000000..4a586690fe --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-storage-local.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getStorageLocal(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get-time.md b/docs/examples/1.4.x/server-dart/examples/health/get-time.md new file mode 100644 index 0000000000..d8166dd3d1 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get-time.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.getTime(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/health/get.md b/docs/examples/1.4.x/server-dart/examples/health/get.md new file mode 100644 index 0000000000..1be37e5a93 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/health/get.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Health health = Health(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = health.get(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/locale/get.md b/docs/examples/1.4.x/server-dart/examples/locale/get.md new file mode 100644 index 0000000000..9ecb18c52d --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/locale/get.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = locale.get(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/locale/list-codes.md b/docs/examples/1.4.x/server-dart/examples/locale/list-codes.md new file mode 100644 index 0000000000..abc4528cfc --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/locale/list-codes.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = locale.listCodes(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/locale/list-continents.md b/docs/examples/1.4.x/server-dart/examples/locale/list-continents.md new file mode 100644 index 0000000000..e6849303b1 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/locale/list-continents.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = locale.listContinents(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-dart/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..2d1ddcf8f0 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/locale/list-countries-e-u.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = locale.listCountriesEU(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-dart/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..2305701339 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/locale/list-countries-phones.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = locale.listCountriesPhones(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/locale/list-countries.md b/docs/examples/1.4.x/server-dart/examples/locale/list-countries.md new file mode 100644 index 0000000000..ef1158339f --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/locale/list-countries.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = locale.listCountries(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-dart/examples/locale/list-currencies.md new file mode 100644 index 0000000000..0810f3dafb --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/locale/list-currencies.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = locale.listCurrencies(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/locale/list-languages.md b/docs/examples/1.4.x/server-dart/examples/locale/list-languages.md new file mode 100644 index 0000000000..f3d642cc48 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/locale/list-languages.md @@ -0,0 +1,21 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Locale locale = Locale(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = locale.listLanguages(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-dart/examples/storage/create-bucket.md new file mode 100644 index 0000000000..745a6b508d --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/create-bucket.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.createBucket( + bucketId: '[BUCKET_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/create-file.md b/docs/examples/1.4.x/server-dart/examples/storage/create-file.md new file mode 100644 index 0000000000..ab4c661a54 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/create-file.md @@ -0,0 +1,26 @@ +import 'dart:io'; +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.createFile( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + file: InputFile(path: './path-to-files/image.jpg', filename: 'image.jpg'), + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-dart/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..de516561bd --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/delete-bucket.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.deleteBucket( + bucketId: '[BUCKET_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/delete-file.md b/docs/examples/1.4.x/server-dart/examples/storage/delete-file.md new file mode 100644 index 0000000000..8e4460bb00 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/delete-file.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.deleteFile( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-dart/examples/storage/get-bucket.md new file mode 100644 index 0000000000..9e39076e35 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/get-bucket.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.getBucket( + bucketId: '[BUCKET_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-dart/examples/storage/get-file-download.md new file mode 100644 index 0000000000..6534fe33ff --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/get-file-download.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.getFileDownload( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-dart/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..ca16d635b2 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/get-file-preview.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.getFilePreview( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-dart/examples/storage/get-file-view.md new file mode 100644 index 0000000000..5c3d69dcbc --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/get-file-view.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.getFileView( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/get-file.md b/docs/examples/1.4.x/server-dart/examples/storage/get-file.md new file mode 100644 index 0000000000..bc45c3f1e8 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/get-file.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.getFile( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-dart/examples/storage/list-buckets.md new file mode 100644 index 0000000000..6a35febb39 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/list-buckets.md @@ -0,0 +1,22 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.listBuckets( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/list-files.md b/docs/examples/1.4.x/server-dart/examples/storage/list-files.md new file mode 100644 index 0000000000..40b8d3bce5 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/list-files.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.listFiles( + bucketId: '[BUCKET_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-dart/examples/storage/update-bucket.md new file mode 100644 index 0000000000..064d2f2e37 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/update-bucket.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.updateBucket( + bucketId: '[BUCKET_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/storage/update-file.md b/docs/examples/1.4.x/server-dart/examples/storage/update-file.md new file mode 100644 index 0000000000..2fa999a558 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/storage/update-file.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Storage storage = Storage(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = storage.updateFile( + bucketId: '[BUCKET_ID]', + fileId: '[FILE_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/create-membership.md b/docs/examples/1.4.x/server-dart/examples/teams/create-membership.md new file mode 100644 index 0000000000..6a98fea0bd --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/create-membership.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.createMembership( + teamId: '[TEAM_ID]', + roles: [], + url: 'https://example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/create.md b/docs/examples/1.4.x/server-dart/examples/teams/create.md new file mode 100644 index 0000000000..74895b23a0 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/create.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.create( + teamId: '[TEAM_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-dart/examples/teams/delete-membership.md new file mode 100644 index 0000000000..8c135994d6 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/delete-membership.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.deleteMembership( + teamId: '[TEAM_ID]', + membershipId: '[MEMBERSHIP_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/delete.md b/docs/examples/1.4.x/server-dart/examples/teams/delete.md new file mode 100644 index 0000000000..a5fee4d084 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/delete.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.delete( + teamId: '[TEAM_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/get-membership.md b/docs/examples/1.4.x/server-dart/examples/teams/get-membership.md new file mode 100644 index 0000000000..4193b245f4 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/get-membership.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.getMembership( + teamId: '[TEAM_ID]', + membershipId: '[MEMBERSHIP_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-dart/examples/teams/get-prefs.md new file mode 100644 index 0000000000..27f2ef15ad --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/get-prefs.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = teams.getPrefs( + teamId: '[TEAM_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/get.md b/docs/examples/1.4.x/server-dart/examples/teams/get.md new file mode 100644 index 0000000000..daa67c4eb8 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/get.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.get( + teamId: '[TEAM_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-dart/examples/teams/list-memberships.md new file mode 100644 index 0000000000..74c66c0319 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/list-memberships.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.listMemberships( + teamId: '[TEAM_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/list.md b/docs/examples/1.4.x/server-dart/examples/teams/list.md new file mode 100644 index 0000000000..11033f33da --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/list.md @@ -0,0 +1,22 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.list( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-dart/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..ca704e0fdb --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/update-membership-status.md @@ -0,0 +1,26 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = teams.updateMembershipStatus( + teamId: '[TEAM_ID]', + membershipId: '[MEMBERSHIP_ID]', + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/update-membership.md b/docs/examples/1.4.x/server-dart/examples/teams/update-membership.md new file mode 100644 index 0000000000..85b126c13a --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/update-membership.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.updateMembership( + teamId: '[TEAM_ID]', + membershipId: '[MEMBERSHIP_ID]', + roles: [], + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/update-name.md b/docs/examples/1.4.x/server-dart/examples/teams/update-name.md new file mode 100644 index 0000000000..088a5cfbe6 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/update-name.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = teams.updateName( + teamId: '[TEAM_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-dart/examples/teams/update-prefs.md new file mode 100644 index 0000000000..d99e821759 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/teams/update-prefs.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Teams teams = Teams(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token + ; + + Future result = teams.updatePrefs( + teamId: '[TEAM_ID]', + prefs: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-dart/examples/users/create-argon2user.md new file mode 100644 index 0000000000..a40b3afd55 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/create-argon2user.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.createArgon2User( + userId: '[USER_ID]', + email: 'email@example.com', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-dart/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..8b55d656b0 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/create-bcrypt-user.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.createBcryptUser( + userId: '[USER_ID]', + email: 'email@example.com', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-dart/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..3ab8901f3c --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/create-m-d5user.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.createMD5User( + userId: '[USER_ID]', + email: 'email@example.com', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-dart/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..bedb44f4c2 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/create-p-h-pass-user.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.createPHPassUser( + userId: '[USER_ID]', + email: 'email@example.com', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-dart/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..361f309a37 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/create-s-h-a-user.md @@ -0,0 +1,25 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.createSHAUser( + userId: '[USER_ID]', + email: 'email@example.com', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-dart/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..fa5b80519e --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,28 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.createScryptModifiedUser( + userId: '[USER_ID]', + email: 'email@example.com', + password: 'password', + passwordSalt: '[PASSWORD_SALT]', + passwordSaltSeparator: '[PASSWORD_SALT_SEPARATOR]', + passwordSignerKey: '[PASSWORD_SIGNER_KEY]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-dart/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..91e1f7dc6d --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/create-scrypt-user.md @@ -0,0 +1,30 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.createScryptUser( + userId: '[USER_ID]', + email: 'email@example.com', + password: 'password', + passwordSalt: '[PASSWORD_SALT]', + passwordCpu: 0, + passwordMemory: 0, + passwordParallel: 0, + passwordLength: 0, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/create.md b/docs/examples/1.4.x/server-dart/examples/users/create.md new file mode 100644 index 0000000000..517cd22fcb --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/create.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.create( + userId: '[USER_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/delete-identity.md b/docs/examples/1.4.x/server-dart/examples/users/delete-identity.md new file mode 100644 index 0000000000..4bcfd6d421 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/delete-identity.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.deleteIdentity( + identityId: '[IDENTITY_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/delete-session.md b/docs/examples/1.4.x/server-dart/examples/users/delete-session.md new file mode 100644 index 0000000000..3f7611873e --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/delete-session.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.deleteSession( + userId: '[USER_ID]', + sessionId: '[SESSION_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-dart/examples/users/delete-sessions.md new file mode 100644 index 0000000000..69cbc5e8d5 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/delete-sessions.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.deleteSessions( + userId: '[USER_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/delete.md b/docs/examples/1.4.x/server-dart/examples/users/delete.md new file mode 100644 index 0000000000..1e1311d5d9 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/delete.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.delete( + userId: '[USER_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/get-prefs.md b/docs/examples/1.4.x/server-dart/examples/users/get-prefs.md new file mode 100644 index 0000000000..eb33ae656c --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/get-prefs.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.getPrefs( + userId: '[USER_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/get.md b/docs/examples/1.4.x/server-dart/examples/users/get.md new file mode 100644 index 0000000000..c56852934c --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/get.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.get( + userId: '[USER_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/list-identities.md b/docs/examples/1.4.x/server-dart/examples/users/list-identities.md new file mode 100644 index 0000000000..b19fed01fe --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/list-identities.md @@ -0,0 +1,22 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.listIdentities( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/list-logs.md b/docs/examples/1.4.x/server-dart/examples/users/list-logs.md new file mode 100644 index 0000000000..0d2143ad48 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/list-logs.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.listLogs( + userId: '[USER_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/list-memberships.md b/docs/examples/1.4.x/server-dart/examples/users/list-memberships.md new file mode 100644 index 0000000000..36a83edec0 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/list-memberships.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.listMemberships( + userId: '[USER_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/list-sessions.md b/docs/examples/1.4.x/server-dart/examples/users/list-sessions.md new file mode 100644 index 0000000000..5f77fdbfa7 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/list-sessions.md @@ -0,0 +1,23 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.listSessions( + userId: '[USER_ID]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/list.md b/docs/examples/1.4.x/server-dart/examples/users/list.md new file mode 100644 index 0000000000..34498c00ac --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/list.md @@ -0,0 +1,22 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.list( + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-dart/examples/users/update-email-verification.md new file mode 100644 index 0000000000..8853f86529 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/update-email-verification.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.updateEmailVerification( + userId: '[USER_ID]', + emailVerification: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/update-email.md b/docs/examples/1.4.x/server-dart/examples/users/update-email.md new file mode 100644 index 0000000000..8813e1101f --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/update-email.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.updateEmail( + userId: '[USER_ID]', + email: 'email@example.com', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/update-labels.md b/docs/examples/1.4.x/server-dart/examples/users/update-labels.md new file mode 100644 index 0000000000..ecd06e7699 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/update-labels.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.updateLabels( + userId: '[USER_ID]', + labels: [], + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/update-name.md b/docs/examples/1.4.x/server-dart/examples/users/update-name.md new file mode 100644 index 0000000000..56797d585c --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/update-name.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.updateName( + userId: '[USER_ID]', + name: '[NAME]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/update-password.md b/docs/examples/1.4.x/server-dart/examples/users/update-password.md new file mode 100644 index 0000000000..3dfedb4d4b --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/update-password.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.updatePassword( + userId: '[USER_ID]', + password: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-dart/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..37c3ced608 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/update-phone-verification.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.updatePhoneVerification( + userId: '[USER_ID]', + phoneVerification: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/update-phone.md b/docs/examples/1.4.x/server-dart/examples/users/update-phone.md new file mode 100644 index 0000000000..4d5e311078 --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/update-phone.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.updatePhone( + userId: '[USER_ID]', + number: '+12065550100', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/update-prefs.md b/docs/examples/1.4.x/server-dart/examples/users/update-prefs.md new file mode 100644 index 0000000000..c6c1bbedff --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/update-prefs.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.updatePrefs( + userId: '[USER_ID]', + prefs: {}, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dart/examples/users/update-status.md b/docs/examples/1.4.x/server-dart/examples/users/update-status.md new file mode 100644 index 0000000000..6f80745a7a --- /dev/null +++ b/docs/examples/1.4.x/server-dart/examples/users/update-status.md @@ -0,0 +1,24 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Users users = Users(client); + + client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key + ; + + Future result = users.updateStatus( + userId: '[USER_ID]', + status: false, + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-deno/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..fe765887cc --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/create-phone-verification.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.createPhoneVerification(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/create-recovery.md b/docs/examples/1.4.x/server-deno/examples/account/create-recovery.md new file mode 100644 index 0000000000..e5adb2a78b --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/create-recovery.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.createRecovery('email@example.com', 'https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/create-verification.md b/docs/examples/1.4.x/server-deno/examples/account/create-verification.md new file mode 100644 index 0000000000..5861278e70 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/create-verification.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.createVerification('https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/delete-identity.md b/docs/examples/1.4.x/server-deno/examples/account/delete-identity.md new file mode 100644 index 0000000000..f24954e2b6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/delete-identity.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.deleteIdentity('[IDENTITY_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/delete-session.md b/docs/examples/1.4.x/server-deno/examples/account/delete-session.md new file mode 100644 index 0000000000..22417acb98 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/delete-session.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.deleteSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-deno/examples/account/delete-sessions.md new file mode 100644 index 0000000000..2a82bd9566 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/delete-sessions.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.deleteSessions(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/get-prefs.md b/docs/examples/1.4.x/server-deno/examples/account/get-prefs.md new file mode 100644 index 0000000000..c9645d0fe1 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/get-prefs.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.getPrefs(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/get-session.md b/docs/examples/1.4.x/server-deno/examples/account/get-session.md new file mode 100644 index 0000000000..f2c1c94469 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/get-session.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.getSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/get.md b/docs/examples/1.4.x/server-deno/examples/account/get.md new file mode 100644 index 0000000000..03b22307ac --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/get.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.get(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/list-identities.md b/docs/examples/1.4.x/server-deno/examples/account/list-identities.md new file mode 100644 index 0000000000..c3faa7b5b3 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/list-identities.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.listIdentities(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/list-logs.md b/docs/examples/1.4.x/server-deno/examples/account/list-logs.md new file mode 100644 index 0000000000..fb79304101 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/list-logs.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.listLogs(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/list-sessions.md b/docs/examples/1.4.x/server-deno/examples/account/list-sessions.md new file mode 100644 index 0000000000..32a7cfa09a --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/list-sessions.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.listSessions(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-email.md b/docs/examples/1.4.x/server-deno/examples/account/update-email.md new file mode 100644 index 0000000000..26906d7eed --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-email.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updateEmail('email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-name.md b/docs/examples/1.4.x/server-deno/examples/account/update-name.md new file mode 100644 index 0000000000..b1a351216f --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-name.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updateName('[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-password.md b/docs/examples/1.4.x/server-deno/examples/account/update-password.md new file mode 100644 index 0000000000..a271dfe7e6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-password.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updatePassword(''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-deno/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..064252a328 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-phone-verification.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updatePhoneVerification('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-phone.md b/docs/examples/1.4.x/server-deno/examples/account/update-phone.md new file mode 100644 index 0000000000..e023424f9e --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-phone.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updatePhone('+12065550100', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-prefs.md b/docs/examples/1.4.x/server-deno/examples/account/update-prefs.md new file mode 100644 index 0000000000..4a6ca88ae8 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-prefs.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updatePrefs({}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-recovery.md b/docs/examples/1.4.x/server-deno/examples/account/update-recovery.md new file mode 100644 index 0000000000..06916bb278 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-recovery.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-session.md b/docs/examples/1.4.x/server-deno/examples/account/update-session.md new file mode 100644 index 0000000000..23a7ad2cf6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-session.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updateSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-status.md b/docs/examples/1.4.x/server-deno/examples/account/update-status.md new file mode 100644 index 0000000000..6b9b18981b --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-status.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updateStatus(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/account/update-verification.md b/docs/examples/1.4.x/server-deno/examples/account/update-verification.md new file mode 100644 index 0000000000..c11f2b71c1 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/account/update-verification.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = account.updateVerification('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-deno/examples/avatars/get-browser.md new file mode 100644 index 0000000000..44c946e4d7 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/avatars/get-browser.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = avatars.getBrowser('aa'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-deno/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..0f44982738 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/avatars/get-credit-card.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = avatars.getCreditCard('amex'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-deno/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..f0a539b5fc --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/avatars/get-favicon.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = avatars.getFavicon('https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-deno/examples/avatars/get-flag.md new file mode 100644 index 0000000000..c7593aee1e --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/avatars/get-flag.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = avatars.getFlag('af'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/avatars/get-image.md b/docs/examples/1.4.x/server-deno/examples/avatars/get-image.md new file mode 100644 index 0000000000..6e86307a5f --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/avatars/get-image.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = avatars.getImage('https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-deno/examples/avatars/get-initials.md new file mode 100644 index 0000000000..2adba9e971 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/avatars/get-initials.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = avatars.getInitials(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-deno/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..2c5faf0112 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/avatars/get-q-r.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = avatars.getQR('[TEXT]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..81b66771ff --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-boolean-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createBooleanAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-collection.md b/docs/examples/1.4.x/server-deno/examples/databases/create-collection.md new file mode 100644 index 0000000000..5d59286e3c --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-collection.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createCollection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..c2c4eb8185 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-datetime-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createDatetimeAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-document.md b/docs/examples/1.4.x/server-deno/examples/databases/create-document.md new file mode 100644 index 0000000000..d38818c164 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-document.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]', {}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..4952625bfc --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-email-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createEmailAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..d00274d616 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-enum-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createEnumAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..c2b056fd1b --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-float-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createFloatAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-index.md b/docs/examples/1.4.x/server-deno/examples/databases/create-index.md new file mode 100644 index 0000000000..bfde8e3fb5 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-index.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createIndex('[DATABASE_ID]', '[COLLECTION_ID]', '', 'key', []); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..2a36f413e5 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-integer-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createIntegerAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..19180d6ac0 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-ip-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createIpAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..e613a6f596 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-relationship-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createRelationshipAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '[RELATED_COLLECTION_ID]', 'oneToOne'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..f3b0a36923 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-string-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createStringAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', 1, false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..488751adff --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create-url-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.createUrlAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/create.md b/docs/examples/1.4.x/server-deno/examples/databases/create.md new file mode 100644 index 0000000000..ea1ebb6460 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/create.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.create('[DATABASE_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..e6fe0823f2 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/delete-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.deleteAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-deno/examples/databases/delete-collection.md new file mode 100644 index 0000000000..970602ac28 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/delete-collection.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.deleteCollection('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/delete-document.md b/docs/examples/1.4.x/server-deno/examples/databases/delete-document.md new file mode 100644 index 0000000000..1a23e03e27 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/delete-document.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.deleteDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/delete-index.md b/docs/examples/1.4.x/server-deno/examples/databases/delete-index.md new file mode 100644 index 0000000000..8a6050522a --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/delete-index.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.deleteIndex('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/delete.md b/docs/examples/1.4.x/server-deno/examples/databases/delete.md new file mode 100644 index 0000000000..b735eccdbe --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/delete.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.delete('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/get-attribute.md new file mode 100644 index 0000000000..1ec9957b5e --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/get-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.getAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/get-collection.md b/docs/examples/1.4.x/server-deno/examples/databases/get-collection.md new file mode 100644 index 0000000000..bf471e3b36 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/get-collection.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.getCollection('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/get-document.md b/docs/examples/1.4.x/server-deno/examples/databases/get-document.md new file mode 100644 index 0000000000..a7248d0641 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/get-document.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.getDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/get-index.md b/docs/examples/1.4.x/server-deno/examples/databases/get-index.md new file mode 100644 index 0000000000..c1fe00cb65 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/get-index.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.getIndex('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/get.md b/docs/examples/1.4.x/server-deno/examples/databases/get.md new file mode 100644 index 0000000000..46df3aad22 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/get.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.get('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-deno/examples/databases/list-attributes.md new file mode 100644 index 0000000000..f2b21141b3 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/list-attributes.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.listAttributes('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/list-collections.md b/docs/examples/1.4.x/server-deno/examples/databases/list-collections.md new file mode 100644 index 0000000000..83e4ee951f --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/list-collections.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.listCollections('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/list-documents.md b/docs/examples/1.4.x/server-deno/examples/databases/list-documents.md new file mode 100644 index 0000000000..c7db17efb5 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/list-documents.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.listDocuments('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-deno/examples/databases/list-indexes.md new file mode 100644 index 0000000000..69c412b99d --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/list-indexes.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.listIndexes('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/list.md b/docs/examples/1.4.x/server-deno/examples/databases/list.md new file mode 100644 index 0000000000..8bb75110ec --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/list.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.list(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..c8b55b77e5 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-boolean-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateBooleanAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-collection.md b/docs/examples/1.4.x/server-deno/examples/databases/update-collection.md new file mode 100644 index 0000000000..f81f46e7f4 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-collection.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateCollection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..25549b4ed2 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-datetime-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateDatetimeAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-document.md b/docs/examples/1.4.x/server-deno/examples/databases/update-document.md new file mode 100644 index 0000000000..9964fdb6eb --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-document.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..78d2403cd8 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-email-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateEmailAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, 'email@example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..f47b96fc53 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-enum-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateEnumAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], false, '[DEFAULT]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..62df38cddc --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-float-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateFloatAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, null, null, null); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..001671eda1 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-integer-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateIntegerAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, null, null, null); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..8ee0d5c80a --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-ip-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateIpAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..c12a64a9dc --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-relationship-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateRelationshipAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..ab77495e23 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-string-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateStringAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, '[DEFAULT]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-deno/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..c9ab818c80 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update-url-attribute.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.updateUrlAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, 'https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/databases/update.md b/docs/examples/1.4.x/server-deno/examples/databases/update.md new file mode 100644 index 0000000000..64886a697b --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/databases/update.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = databases.update('[DATABASE_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/create-build.md b/docs/examples/1.4.x/server-deno/examples/functions/create-build.md new file mode 100644 index 0000000000..28d10105e3 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/create-build.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.createBuild('[FUNCTION_ID]', '[DEPLOYMENT_ID]', '[BUILD_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-deno/examples/functions/create-deployment.md new file mode 100644 index 0000000000..167d177bb7 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/create-deployment.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.createDeployment('[FUNCTION_ID]', InputFile.fromPath('/path/to/file.png', 'file.png'), false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/create-execution.md b/docs/examples/1.4.x/server-deno/examples/functions/create-execution.md new file mode 100644 index 0000000000..6ec920ef9d --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/create-execution.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.createExecution('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/create-variable.md b/docs/examples/1.4.x/server-deno/examples/functions/create-variable.md new file mode 100644 index 0000000000..375ef8b7a6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/create-variable.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.createVariable('[FUNCTION_ID]', '[KEY]', '[VALUE]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/create.md b/docs/examples/1.4.x/server-deno/examples/functions/create.md new file mode 100644 index 0000000000..0c5ff2ce5f --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/create.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.create('[FUNCTION_ID]', '[NAME]', 'node-14.5'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-deno/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..7b6468bb06 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/delete-deployment.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.deleteDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-deno/examples/functions/delete-variable.md new file mode 100644 index 0000000000..16bf385a4c --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/delete-variable.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.deleteVariable('[FUNCTION_ID]', '[VARIABLE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/delete.md b/docs/examples/1.4.x/server-deno/examples/functions/delete.md new file mode 100644 index 0000000000..48ec374bf2 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/delete.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.delete('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-deno/examples/functions/download-deployment.md new file mode 100644 index 0000000000..dc07358df1 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/download-deployment.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.downloadDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-deno/examples/functions/get-deployment.md new file mode 100644 index 0000000000..854f3897d9 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/get-deployment.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.getDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/get-execution.md b/docs/examples/1.4.x/server-deno/examples/functions/get-execution.md new file mode 100644 index 0000000000..42bcdfbfdf --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/get-execution.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.getExecution('[FUNCTION_ID]', '[EXECUTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/get-variable.md b/docs/examples/1.4.x/server-deno/examples/functions/get-variable.md new file mode 100644 index 0000000000..2b4190e0a6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/get-variable.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.getVariable('[FUNCTION_ID]', '[VARIABLE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/get.md b/docs/examples/1.4.x/server-deno/examples/functions/get.md new file mode 100644 index 0000000000..388958232a --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/get.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.get('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-deno/examples/functions/list-deployments.md new file mode 100644 index 0000000000..e84bb9cc09 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/list-deployments.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.listDeployments('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/list-executions.md b/docs/examples/1.4.x/server-deno/examples/functions/list-executions.md new file mode 100644 index 0000000000..aadd19f1ce --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/list-executions.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.listExecutions('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-deno/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..6fc7570b3a --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/list-runtimes.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.listRuntimes(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/list-variables.md b/docs/examples/1.4.x/server-deno/examples/functions/list-variables.md new file mode 100644 index 0000000000..44a9828a67 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/list-variables.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.listVariables('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/list.md b/docs/examples/1.4.x/server-deno/examples/functions/list.md new file mode 100644 index 0000000000..7c82760a39 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/list.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.list(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-deno/examples/functions/update-deployment.md new file mode 100644 index 0000000000..94be560a2d --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/update-deployment.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.updateDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/update-variable.md b/docs/examples/1.4.x/server-deno/examples/functions/update-variable.md new file mode 100644 index 0000000000..1a318f1eba --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/update-variable.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.updateVariable('[FUNCTION_ID]', '[VARIABLE_ID]', '[KEY]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/functions/update.md b/docs/examples/1.4.x/server-deno/examples/functions/update.md new file mode 100644 index 0000000000..360e7abb05 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/functions/update.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = functions.update('[FUNCTION_ID]', '[NAME]', 'node-14.5'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/graphql/mutation.md b/docs/examples/1.4.x/server-deno/examples/graphql/mutation.md new file mode 100644 index 0000000000..87beeabce6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/graphql/mutation.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let graphql = new sdk.Graphql(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = graphql.mutation({}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/graphql/query.md b/docs/examples/1.4.x/server-deno/examples/graphql/query.md new file mode 100644 index 0000000000..d2eec0a8db --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/graphql/query.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let graphql = new sdk.Graphql(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = graphql.query({}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-deno/examples/health/get-antivirus.md new file mode 100644 index 0000000000..8d51808536 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-antivirus.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getAntivirus(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-cache.md b/docs/examples/1.4.x/server-deno/examples/health/get-cache.md new file mode 100644 index 0000000000..cafc3018c0 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-cache.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getCache(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-d-b.md b/docs/examples/1.4.x/server-deno/examples/health/get-d-b.md new file mode 100644 index 0000000000..a000535051 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-d-b.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getDB(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-deno/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..979ef0b51c --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-pub-sub.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getPubSub(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-deno/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..49dab6b2e6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-queue-certificates.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getQueueCertificates(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-deno/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..74f458b9fe --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-queue-functions.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getQueueFunctions(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-deno/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..98948b9de6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-queue-logs.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getQueueLogs(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-deno/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..7b45c189cc --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-queue-webhooks.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getQueueWebhooks(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-queue.md b/docs/examples/1.4.x/server-deno/examples/health/get-queue.md new file mode 100644 index 0000000000..4c1f675bb6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-queue.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getQueue(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-deno/examples/health/get-storage-local.md new file mode 100644 index 0000000000..4c45d89aca --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-storage-local.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getStorageLocal(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get-time.md b/docs/examples/1.4.x/server-deno/examples/health/get-time.md new file mode 100644 index 0000000000..6a66a10a05 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get-time.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.getTime(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/health/get.md b/docs/examples/1.4.x/server-deno/examples/health/get.md new file mode 100644 index 0000000000..0b9af9dd15 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/health/get.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = health.get(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/locale/get.md b/docs/examples/1.4.x/server-deno/examples/locale/get.md new file mode 100644 index 0000000000..22b9a62655 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/locale/get.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = locale.get(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/locale/list-codes.md b/docs/examples/1.4.x/server-deno/examples/locale/list-codes.md new file mode 100644 index 0000000000..1ca38d4e88 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/locale/list-codes.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = locale.listCodes(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/locale/list-continents.md b/docs/examples/1.4.x/server-deno/examples/locale/list-continents.md new file mode 100644 index 0000000000..bd69f43a61 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/locale/list-continents.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = locale.listContinents(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-deno/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..3d3b7b492a --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/locale/list-countries-e-u.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = locale.listCountriesEU(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-deno/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..bc9e1754ad --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/locale/list-countries-phones.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = locale.listCountriesPhones(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/locale/list-countries.md b/docs/examples/1.4.x/server-deno/examples/locale/list-countries.md new file mode 100644 index 0000000000..0790270371 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/locale/list-countries.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = locale.listCountries(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-deno/examples/locale/list-currencies.md new file mode 100644 index 0000000000..e040312fef --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/locale/list-currencies.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = locale.listCurrencies(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/locale/list-languages.md b/docs/examples/1.4.x/server-deno/examples/locale/list-languages.md new file mode 100644 index 0000000000..be5af4d50c --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/locale/list-languages.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = locale.listLanguages(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-deno/examples/storage/create-bucket.md new file mode 100644 index 0000000000..a25211a1c7 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/create-bucket.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.createBucket('[BUCKET_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/create-file.md b/docs/examples/1.4.x/server-deno/examples/storage/create-file.md new file mode 100644 index 0000000000..c0fe4930b9 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/create-file.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.createFile('[BUCKET_ID]', '[FILE_ID]', InputFile.fromPath('/path/to/file.png', 'file.png')); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-deno/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..d468428141 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/delete-bucket.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.deleteBucket('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/delete-file.md b/docs/examples/1.4.x/server-deno/examples/storage/delete-file.md new file mode 100644 index 0000000000..e86da1763b --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/delete-file.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.deleteFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-deno/examples/storage/get-bucket.md new file mode 100644 index 0000000000..35d22b941a --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/get-bucket.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.getBucket('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-deno/examples/storage/get-file-download.md new file mode 100644 index 0000000000..206b860e25 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/get-file-download.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.getFileDownload('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-deno/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..4815c6b40b --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/get-file-preview.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.getFilePreview('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-deno/examples/storage/get-file-view.md new file mode 100644 index 0000000000..11ca8fdc6c --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/get-file-view.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.getFileView('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/get-file.md b/docs/examples/1.4.x/server-deno/examples/storage/get-file.md new file mode 100644 index 0000000000..04aa43a5b1 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/get-file.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.getFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-deno/examples/storage/list-buckets.md new file mode 100644 index 0000000000..0c31feffe3 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/list-buckets.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.listBuckets(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/list-files.md b/docs/examples/1.4.x/server-deno/examples/storage/list-files.md new file mode 100644 index 0000000000..00178aa874 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/list-files.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.listFiles('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-deno/examples/storage/update-bucket.md new file mode 100644 index 0000000000..aca746145e --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/update-bucket.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.updateBucket('[BUCKET_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/storage/update-file.md b/docs/examples/1.4.x/server-deno/examples/storage/update-file.md new file mode 100644 index 0000000000..79f31c3b03 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/storage/update-file.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = storage.updateFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/create-membership.md b/docs/examples/1.4.x/server-deno/examples/teams/create-membership.md new file mode 100644 index 0000000000..c4169a306b --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/create-membership.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.createMembership('[TEAM_ID]', [], 'https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/create.md b/docs/examples/1.4.x/server-deno/examples/teams/create.md new file mode 100644 index 0000000000..8272adb4d0 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/create.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.create('[TEAM_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-deno/examples/teams/delete-membership.md new file mode 100644 index 0000000000..402deb0b8a --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/delete-membership.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.deleteMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/delete.md b/docs/examples/1.4.x/server-deno/examples/teams/delete.md new file mode 100644 index 0000000000..3b30934bea --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/delete.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.delete('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/get-membership.md b/docs/examples/1.4.x/server-deno/examples/teams/get-membership.md new file mode 100644 index 0000000000..7d50599b67 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/get-membership.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.getMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-deno/examples/teams/get-prefs.md new file mode 100644 index 0000000000..5a7fa4d98f --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/get-prefs.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = teams.getPrefs('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/get.md b/docs/examples/1.4.x/server-deno/examples/teams/get.md new file mode 100644 index 0000000000..44ecdab949 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/get.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.get('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-deno/examples/teams/list-memberships.md new file mode 100644 index 0000000000..7d730021a6 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/list-memberships.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.listMemberships('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/list.md b/docs/examples/1.4.x/server-deno/examples/teams/list.md new file mode 100644 index 0000000000..c45ffdc066 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/list.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.list(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-deno/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..7bb57d8974 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/update-membership-status.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = teams.updateMembershipStatus('[TEAM_ID]', '[MEMBERSHIP_ID]', '[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/update-membership.md b/docs/examples/1.4.x/server-deno/examples/teams/update-membership.md new file mode 100644 index 0000000000..3ada2f4745 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/update-membership.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.updateMembership('[TEAM_ID]', '[MEMBERSHIP_ID]', []); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/update-name.md b/docs/examples/1.4.x/server-deno/examples/teams/update-name.md new file mode 100644 index 0000000000..47c3fc2765 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/update-name.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = teams.updateName('[TEAM_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-deno/examples/teams/update-prefs.md new file mode 100644 index 0000000000..83845be036 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/teams/update-prefs.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + + +let promise = teams.updatePrefs('[TEAM_ID]', {}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-deno/examples/users/create-argon2user.md new file mode 100644 index 0000000000..e55b644b62 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/create-argon2user.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.createArgon2User('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-deno/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..325fbe46d5 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/create-bcrypt-user.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.createBcryptUser('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-deno/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..8892688594 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/create-m-d5user.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.createMD5User('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-deno/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..d7a3428fd5 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/create-p-h-pass-user.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.createPHPassUser('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-deno/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..c3ade982ef --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/create-s-h-a-user.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.createSHAUser('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-deno/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..8039a970c2 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.createScryptModifiedUser('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', '[PASSWORD_SALT_SEPARATOR]', '[PASSWORD_SIGNER_KEY]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-deno/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..9889855e7c --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/create-scrypt-user.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.createScryptUser('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', null, null, null, null); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/create.md b/docs/examples/1.4.x/server-deno/examples/users/create.md new file mode 100644 index 0000000000..c56f8d8f88 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/create.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.create('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/delete-identity.md b/docs/examples/1.4.x/server-deno/examples/users/delete-identity.md new file mode 100644 index 0000000000..7d7b88a7f9 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/delete-identity.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.deleteIdentity('[IDENTITY_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/delete-session.md b/docs/examples/1.4.x/server-deno/examples/users/delete-session.md new file mode 100644 index 0000000000..e4ea45ba73 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/delete-session.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.deleteSession('[USER_ID]', '[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-deno/examples/users/delete-sessions.md new file mode 100644 index 0000000000..0e12d6dacf --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/delete-sessions.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.deleteSessions('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/delete.md b/docs/examples/1.4.x/server-deno/examples/users/delete.md new file mode 100644 index 0000000000..f0223024a3 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/delete.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.delete('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/get-prefs.md b/docs/examples/1.4.x/server-deno/examples/users/get-prefs.md new file mode 100644 index 0000000000..63953f9d24 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/get-prefs.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.getPrefs('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/get.md b/docs/examples/1.4.x/server-deno/examples/users/get.md new file mode 100644 index 0000000000..c9300c5060 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/get.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.get('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/list-identities.md b/docs/examples/1.4.x/server-deno/examples/users/list-identities.md new file mode 100644 index 0000000000..687770178c --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/list-identities.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.listIdentities(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/list-logs.md b/docs/examples/1.4.x/server-deno/examples/users/list-logs.md new file mode 100644 index 0000000000..7d0841fc77 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/list-logs.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.listLogs('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/list-memberships.md b/docs/examples/1.4.x/server-deno/examples/users/list-memberships.md new file mode 100644 index 0000000000..74f2fb7f1e --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/list-memberships.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.listMemberships('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/list-sessions.md b/docs/examples/1.4.x/server-deno/examples/users/list-sessions.md new file mode 100644 index 0000000000..1aa4ca7d78 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/list-sessions.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.listSessions('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/list.md b/docs/examples/1.4.x/server-deno/examples/users/list.md new file mode 100644 index 0000000000..369ccd7b29 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/list.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.list(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-deno/examples/users/update-email-verification.md new file mode 100644 index 0000000000..146cea5027 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/update-email-verification.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.updateEmailVerification('[USER_ID]', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/update-email.md b/docs/examples/1.4.x/server-deno/examples/users/update-email.md new file mode 100644 index 0000000000..bd7f0ffbd8 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/update-email.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.updateEmail('[USER_ID]', 'email@example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/update-labels.md b/docs/examples/1.4.x/server-deno/examples/users/update-labels.md new file mode 100644 index 0000000000..73aee6485b --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/update-labels.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.updateLabels('[USER_ID]', []); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/update-name.md b/docs/examples/1.4.x/server-deno/examples/users/update-name.md new file mode 100644 index 0000000000..071c948201 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/update-name.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.updateName('[USER_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/update-password.md b/docs/examples/1.4.x/server-deno/examples/users/update-password.md new file mode 100644 index 0000000000..e6ae8b725e --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/update-password.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.updatePassword('[USER_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-deno/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..293f876152 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/update-phone-verification.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.updatePhoneVerification('[USER_ID]', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/update-phone.md b/docs/examples/1.4.x/server-deno/examples/users/update-phone.md new file mode 100644 index 0000000000..e634f59719 --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/update-phone.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.updatePhone('[USER_ID]', '+12065550100'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/update-prefs.md b/docs/examples/1.4.x/server-deno/examples/users/update-prefs.md new file mode 100644 index 0000000000..248fdb10ab --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/update-prefs.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.updatePrefs('[USER_ID]', {}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-deno/examples/users/update-status.md b/docs/examples/1.4.x/server-deno/examples/users/update-status.md new file mode 100644 index 0000000000..2f142596fd --- /dev/null +++ b/docs/examples/1.4.x/server-deno/examples/users/update-status.md @@ -0,0 +1,21 @@ +import * as sdk from "https://deno.land/x/appwrite/mod.ts"; + +// Init SDK +let client = new sdk.Client(); + +let users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + + +let promise = users.updateStatus('[USER_ID]', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-dotnet/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..570bb20f5e --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/create-phone-verification.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +Token result = await account.CreatePhoneVerification(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/create-recovery.md b/docs/examples/1.4.x/server-dotnet/examples/account/create-recovery.md new file mode 100644 index 0000000000..1edc79bc50 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/create-recovery.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +Token result = await account.CreateRecovery( + email: "email@example.com", + url: "https://example.com"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/create-verification.md b/docs/examples/1.4.x/server-dotnet/examples/account/create-verification.md new file mode 100644 index 0000000000..928fcb8561 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/create-verification.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +Token result = await account.CreateVerification( + url: "https://example.com"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/delete-identity.md b/docs/examples/1.4.x/server-dotnet/examples/account/delete-identity.md new file mode 100644 index 0000000000..c5ff987822 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/delete-identity.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +await account.DeleteIdentity( + identityId: "[IDENTITY_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/delete-session.md b/docs/examples/1.4.x/server-dotnet/examples/account/delete-session.md new file mode 100644 index 0000000000..c880a4f88d --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/delete-session.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +await account.DeleteSession( + sessionId: "[SESSION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-dotnet/examples/account/delete-sessions.md new file mode 100644 index 0000000000..8dcefaf71c --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/delete-sessions.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +await account.DeleteSessions(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/get-prefs.md b/docs/examples/1.4.x/server-dotnet/examples/account/get-prefs.md new file mode 100644 index 0000000000..ce3ecc1179 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/get-prefs.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +Preferences result = await account.GetPrefs(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/get-session.md b/docs/examples/1.4.x/server-dotnet/examples/account/get-session.md new file mode 100644 index 0000000000..9560b6a78a --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/get-session.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +Session result = await account.GetSession( + sessionId: "[SESSION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/get.md b/docs/examples/1.4.x/server-dotnet/examples/account/get.md new file mode 100644 index 0000000000..5a50299c73 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/get.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +User result = await account.Get(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/list-identities.md b/docs/examples/1.4.x/server-dotnet/examples/account/list-identities.md new file mode 100644 index 0000000000..3a25342e5d --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/list-identities.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +IdentityList result = await account.ListIdentities(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/list-logs.md b/docs/examples/1.4.x/server-dotnet/examples/account/list-logs.md new file mode 100644 index 0000000000..03b50407f5 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/list-logs.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +LogList result = await account.ListLogs(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/list-sessions.md b/docs/examples/1.4.x/server-dotnet/examples/account/list-sessions.md new file mode 100644 index 0000000000..aa813bc1dd --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/list-sessions.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +SessionList result = await account.ListSessions(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-email.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-email.md new file mode 100644 index 0000000000..0b457e0abb --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-email.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +User result = await account.UpdateEmail( + email: "email@example.com", + password: "password"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-name.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-name.md new file mode 100644 index 0000000000..b41ba37289 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-name.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +User result = await account.UpdateName( + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-password.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-password.md new file mode 100644 index 0000000000..d8bab0b4d2 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-password.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +User result = await account.UpdatePassword( + password: ""); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..6914e7805f --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-phone-verification.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +Token result = await account.UpdatePhoneVerification( + userId: "[USER_ID]", + secret: "[SECRET]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-phone.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-phone.md new file mode 100644 index 0000000000..f3e2f14df7 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-phone.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +User result = await account.UpdatePhone( + phone: "+12065550100", + password: "password"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-prefs.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-prefs.md new file mode 100644 index 0000000000..7a4f2378e4 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-prefs.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +User result = await account.UpdatePrefs( + prefs: [object]); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-recovery.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-recovery.md new file mode 100644 index 0000000000..d26f4ab8da --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-recovery.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +Token result = await account.UpdateRecovery( + userId: "[USER_ID]", + secret: "[SECRET]", + password: "password", + passwordAgain: "password"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-session.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-session.md new file mode 100644 index 0000000000..f3365bb96b --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-session.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +Session result = await account.UpdateSession( + sessionId: "[SESSION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-status.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-status.md new file mode 100644 index 0000000000..c5e3e2c576 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-status.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +User result = await account.UpdateStatus(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/account/update-verification.md b/docs/examples/1.4.x/server-dotnet/examples/account/update-verification.md new file mode 100644 index 0000000000..697d2dffa4 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/account/update-verification.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var account = new Account(client); + +Token result = await account.UpdateVerification( + userId: "[USER_ID]", + secret: "[SECRET]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-browser.md new file mode 100644 index 0000000000..3ac58f8b47 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-browser.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var avatars = new Avatars(client); + +byte[] result = await avatars.GetBrowser( + code: "aa"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..89f36fe35d --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-credit-card.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var avatars = new Avatars(client); + +byte[] result = await avatars.GetCreditCard( + code: "amex"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..dbabf05d57 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-favicon.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var avatars = new Avatars(client); + +byte[] result = await avatars.GetFavicon( + url: "https://example.com"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-flag.md new file mode 100644 index 0000000000..fc20581c1c --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-flag.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var avatars = new Avatars(client); + +byte[] result = await avatars.GetFlag( + code: "af"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/avatars/get-image.md b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-image.md new file mode 100644 index 0000000000..35bf382f12 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-image.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var avatars = new Avatars(client); + +byte[] result = await avatars.GetImage( + url: "https://example.com"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-initials.md new file mode 100644 index 0000000000..20ea37a3a4 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-initials.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var avatars = new Avatars(client); + +byte[] result = await avatars.GetInitials(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..33dcac6f91 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/avatars/get-q-r.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var avatars = new Avatars(client); + +byte[] result = await avatars.GetQR( + text: "[TEXT]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..439537a9cb --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-boolean-attribute.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeBoolean result = await databases.CreateBooleanAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-collection.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-collection.md new file mode 100644 index 0000000000..1b7aa198a6 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-collection.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Collection result = await databases.CreateCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..1fff2965ff --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-datetime-attribute.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeDatetime result = await databases.CreateDatetimeAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-document.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-document.md new file mode 100644 index 0000000000..c0081f1f20 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-document.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Document result = await databases.CreateDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]", + data: [object]); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..e22ed7ddca --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-email-attribute.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeEmail result = await databases.CreateEmailAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..773d41e9fa --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-enum-attribute.md @@ -0,0 +1,17 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeEnum result = await databases.CreateEnumAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + elements: new List {}, + required: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..d0915184e8 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-float-attribute.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeFloat result = await databases.CreateFloatAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-index.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-index.md new file mode 100644 index 0000000000..b13de722aa --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-index.md @@ -0,0 +1,17 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Index result = await databases.CreateIndex( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + type: "key", + attributes: new List {}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..0d84ea7868 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-integer-attribute.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeInteger result = await databases.CreateIntegerAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..ca571d00bd --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-ip-attribute.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeIp result = await databases.CreateIpAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..9c4a8c3604 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-relationship-attribute.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeRelationship result = await databases.CreateRelationshipAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + relatedCollectionId: "[RELATED_COLLECTION_ID]", + type: "oneToOne"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..645492eeab --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-string-attribute.md @@ -0,0 +1,17 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeString result = await databases.CreateStringAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + size: 1, + required: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..9425882dec --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create-url-attribute.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeUrl result = await databases.CreateUrlAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/create.md b/docs/examples/1.4.x/server-dotnet/examples/databases/create.md new file mode 100644 index 0000000000..61ba46c03a --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/create.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Database result = await databases.Create( + databaseId: "[DATABASE_ID]", + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..8ebde257c5 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/delete-attribute.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +await databases.DeleteAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: ""); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-dotnet/examples/databases/delete-collection.md new file mode 100644 index 0000000000..398185c509 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/delete-collection.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +await databases.DeleteCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/delete-document.md b/docs/examples/1.4.x/server-dotnet/examples/databases/delete-document.md new file mode 100644 index 0000000000..6892b25438 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/delete-document.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +await databases.DeleteDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/delete-index.md b/docs/examples/1.4.x/server-dotnet/examples/databases/delete-index.md new file mode 100644 index 0000000000..c5dab69e0f --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/delete-index.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +await databases.DeleteIndex( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: ""); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/delete.md b/docs/examples/1.4.x/server-dotnet/examples/databases/delete.md new file mode 100644 index 0000000000..cc8b4317e1 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/delete.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +await databases.Delete( + databaseId: "[DATABASE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/get-attribute.md new file mode 100644 index 0000000000..13eae946e9 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/get-attribute.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + + result = await databases.GetAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: ""); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/get-collection.md b/docs/examples/1.4.x/server-dotnet/examples/databases/get-collection.md new file mode 100644 index 0000000000..b617da7810 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/get-collection.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Collection result = await databases.GetCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/get-document.md b/docs/examples/1.4.x/server-dotnet/examples/databases/get-document.md new file mode 100644 index 0000000000..079f93a403 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/get-document.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Document result = await databases.GetDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/get-index.md b/docs/examples/1.4.x/server-dotnet/examples/databases/get-index.md new file mode 100644 index 0000000000..d989ed4651 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/get-index.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Index result = await databases.GetIndex( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: ""); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/get.md b/docs/examples/1.4.x/server-dotnet/examples/databases/get.md new file mode 100644 index 0000000000..5dfa70eec1 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/get.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Database result = await databases.Get( + databaseId: "[DATABASE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-dotnet/examples/databases/list-attributes.md new file mode 100644 index 0000000000..8af529df41 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/list-attributes.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeList result = await databases.ListAttributes( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/list-collections.md b/docs/examples/1.4.x/server-dotnet/examples/databases/list-collections.md new file mode 100644 index 0000000000..ed0d7bb56f --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/list-collections.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +CollectionList result = await databases.ListCollections( + databaseId: "[DATABASE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/list-documents.md b/docs/examples/1.4.x/server-dotnet/examples/databases/list-documents.md new file mode 100644 index 0000000000..92895692f0 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/list-documents.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +DocumentList result = await databases.ListDocuments( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-dotnet/examples/databases/list-indexes.md new file mode 100644 index 0000000000..dbbed3ca53 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/list-indexes.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +IndexList result = await databases.ListIndexes( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/list.md b/docs/examples/1.4.x/server-dotnet/examples/databases/list.md new file mode 100644 index 0000000000..ec234ddbab --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/list.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +DatabaseList result = await databases.List(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..2d6fa80849 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-boolean-attribute.md @@ -0,0 +1,17 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeBoolean result = await databases.UpdateBooleanAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-collection.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-collection.md new file mode 100644 index 0000000000..aa477e4ce0 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-collection.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Collection result = await databases.UpdateCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..81966f05f1 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-datetime-attribute.md @@ -0,0 +1,17 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeDatetime result = await databases.UpdateDatetimeAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: ""); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-document.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-document.md new file mode 100644 index 0000000000..b19d9226c6 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-document.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Document result = await databases.UpdateDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..5baf67fd72 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-email-attribute.md @@ -0,0 +1,17 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeEmail result = await databases.UpdateEmailAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: "email@example.com"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..184ac1820f --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-enum-attribute.md @@ -0,0 +1,18 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeEnum result = await databases.UpdateEnumAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + elements: new List {}, + required: false, + default: "[DEFAULT]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..d68815ab07 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-float-attribute.md @@ -0,0 +1,19 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeFloat result = await databases.UpdateFloatAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + min: 0, + max: 0, + default: 0); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..2ad0e05754 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-integer-attribute.md @@ -0,0 +1,19 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeInteger result = await databases.UpdateIntegerAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + min: 0, + max: 0, + default: 0); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..10fd34b306 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-ip-attribute.md @@ -0,0 +1,17 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeIp result = await databases.UpdateIpAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: ""); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..8a65da0a42 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-relationship-attribute.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeRelationship result = await databases.UpdateRelationshipAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: ""); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..84fc2b8da9 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-string-attribute.md @@ -0,0 +1,17 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeString result = await databases.UpdateStringAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: "[DEFAULT]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..e79812a77b --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update-url-attribute.md @@ -0,0 +1,17 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +AttributeUrl result = await databases.UpdateUrlAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: "https://example.com"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/databases/update.md b/docs/examples/1.4.x/server-dotnet/examples/databases/update.md new file mode 100644 index 0000000000..743108fc66 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/databases/update.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var databases = new Databases(client); + +Database result = await databases.Update( + databaseId: "[DATABASE_ID]", + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/create-build.md b/docs/examples/1.4.x/server-dotnet/examples/functions/create-build.md new file mode 100644 index 0000000000..71eb842c6c --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/create-build.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + + result = await functions.CreateBuild( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]", + buildId: "[BUILD_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-dotnet/examples/functions/create-deployment.md new file mode 100644 index 0000000000..9bbcc65dea --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/create-deployment.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Deployment result = await functions.CreateDeployment( + functionId: "[FUNCTION_ID]", + code: InputFile.FromPath("./path-to-files/image.jpg"), + activate: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/create-execution.md b/docs/examples/1.4.x/server-dotnet/examples/functions/create-execution.md new file mode 100644 index 0000000000..93cd65be5d --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/create-execution.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Execution result = await functions.CreateExecution( + functionId: "[FUNCTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/create-variable.md b/docs/examples/1.4.x/server-dotnet/examples/functions/create-variable.md new file mode 100644 index 0000000000..0724bc6eef --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/create-variable.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Variable result = await functions.CreateVariable( + functionId: "[FUNCTION_ID]", + key: "[KEY]", + value: "[VALUE]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/create.md b/docs/examples/1.4.x/server-dotnet/examples/functions/create.md new file mode 100644 index 0000000000..75c9b242f6 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/create.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Function result = await functions.Create( + functionId: "[FUNCTION_ID]", + name: "[NAME]", + runtime: "node-14.5"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-dotnet/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..2c17dfae9f --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/delete-deployment.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +await functions.DeleteDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-dotnet/examples/functions/delete-variable.md new file mode 100644 index 0000000000..cf201480fa --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/delete-variable.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +await functions.DeleteVariable( + functionId: "[FUNCTION_ID]", + variableId: "[VARIABLE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/delete.md b/docs/examples/1.4.x/server-dotnet/examples/functions/delete.md new file mode 100644 index 0000000000..123e307c79 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/delete.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +await functions.Delete( + functionId: "[FUNCTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-dotnet/examples/functions/download-deployment.md new file mode 100644 index 0000000000..d167c7ddfd --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/download-deployment.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +byte[] result = await functions.DownloadDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-dotnet/examples/functions/get-deployment.md new file mode 100644 index 0000000000..7d895c6d82 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/get-deployment.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Deployment result = await functions.GetDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/get-execution.md b/docs/examples/1.4.x/server-dotnet/examples/functions/get-execution.md new file mode 100644 index 0000000000..ed65d26bef --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/get-execution.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Execution result = await functions.GetExecution( + functionId: "[FUNCTION_ID]", + executionId: "[EXECUTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/get-variable.md b/docs/examples/1.4.x/server-dotnet/examples/functions/get-variable.md new file mode 100644 index 0000000000..12083e5acb --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/get-variable.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Variable result = await functions.GetVariable( + functionId: "[FUNCTION_ID]", + variableId: "[VARIABLE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/get.md b/docs/examples/1.4.x/server-dotnet/examples/functions/get.md new file mode 100644 index 0000000000..1914ccf7ac --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/get.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Function result = await functions.Get( + functionId: "[FUNCTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-dotnet/examples/functions/list-deployments.md new file mode 100644 index 0000000000..cd6a7b9446 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/list-deployments.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +DeploymentList result = await functions.ListDeployments( + functionId: "[FUNCTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/list-executions.md b/docs/examples/1.4.x/server-dotnet/examples/functions/list-executions.md new file mode 100644 index 0000000000..d4c73a0d36 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/list-executions.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +ExecutionList result = await functions.ListExecutions( + functionId: "[FUNCTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-dotnet/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..ca1d125eb2 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/list-runtimes.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +RuntimeList result = await functions.ListRuntimes(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/list-variables.md b/docs/examples/1.4.x/server-dotnet/examples/functions/list-variables.md new file mode 100644 index 0000000000..31177df9ff --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/list-variables.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +VariableList result = await functions.ListVariables( + functionId: "[FUNCTION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/list.md b/docs/examples/1.4.x/server-dotnet/examples/functions/list.md new file mode 100644 index 0000000000..1b8897b76f --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/list.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +FunctionList result = await functions.List(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-dotnet/examples/functions/update-deployment.md new file mode 100644 index 0000000000..8cd7fc5425 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/update-deployment.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Function result = await functions.UpdateDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/update-variable.md b/docs/examples/1.4.x/server-dotnet/examples/functions/update-variable.md new file mode 100644 index 0000000000..63eac46609 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/update-variable.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Variable result = await functions.UpdateVariable( + functionId: "[FUNCTION_ID]", + variableId: "[VARIABLE_ID]", + key: "[KEY]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/functions/update.md b/docs/examples/1.4.x/server-dotnet/examples/functions/update.md new file mode 100644 index 0000000000..1192ceb7df --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/functions/update.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var functions = new Functions(client); + +Function result = await functions.Update( + functionId: "[FUNCTION_ID]", + name: "[NAME]", + runtime: "node-14.5"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/graphql/mutation.md b/docs/examples/1.4.x/server-dotnet/examples/graphql/mutation.md new file mode 100644 index 0000000000..8ab5f0e458 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/graphql/mutation.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var graphql = new Graphql(client); + +Any result = await graphql.Mutation( + query: [object]); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/graphql/query.md b/docs/examples/1.4.x/server-dotnet/examples/graphql/query.md new file mode 100644 index 0000000000..e019f43e5b --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/graphql/query.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var graphql = new Graphql(client); + +Any result = await graphql.Query( + query: [object]); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-antivirus.md new file mode 100644 index 0000000000..b8b0d5d95e --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-antivirus.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthAntivirus result = await health.GetAntivirus(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-cache.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-cache.md new file mode 100644 index 0000000000..2f36c10f3b --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-cache.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthStatus result = await health.GetCache(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-d-b.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-d-b.md new file mode 100644 index 0000000000..a263709073 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-d-b.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthStatus result = await health.GetDB(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..7850a7555c --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-pub-sub.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthStatus result = await health.GetPubSub(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..b2f945cbc7 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-certificates.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthQueue result = await health.GetQueueCertificates(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..cf2ed7fc08 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-functions.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthQueue result = await health.GetQueueFunctions(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..8821509dbc --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-logs.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthQueue result = await health.GetQueueLogs(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..d2ffb01c4d --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue-webhooks.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthQueue result = await health.GetQueueWebhooks(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-queue.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue.md new file mode 100644 index 0000000000..1087bc12c8 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-queue.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthStatus result = await health.GetQueue(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-storage-local.md new file mode 100644 index 0000000000..bc60cc6ccd --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-storage-local.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthStatus result = await health.GetStorageLocal(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get-time.md b/docs/examples/1.4.x/server-dotnet/examples/health/get-time.md new file mode 100644 index 0000000000..15f1745453 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get-time.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthTime result = await health.GetTime(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/health/get.md b/docs/examples/1.4.x/server-dotnet/examples/health/get.md new file mode 100644 index 0000000000..d1ddd8fdf0 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/health/get.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var health = new Health(client); + +HealthStatus result = await health.Get(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/locale/get.md b/docs/examples/1.4.x/server-dotnet/examples/locale/get.md new file mode 100644 index 0000000000..f049a92072 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/locale/get.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var locale = new Locale(client); + +Locale result = await locale.Get(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/locale/list-codes.md b/docs/examples/1.4.x/server-dotnet/examples/locale/list-codes.md new file mode 100644 index 0000000000..9eaab83462 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/locale/list-codes.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var locale = new Locale(client); + +LocaleCodeList result = await locale.ListCodes(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/locale/list-continents.md b/docs/examples/1.4.x/server-dotnet/examples/locale/list-continents.md new file mode 100644 index 0000000000..dd91caba9d --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/locale/list-continents.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var locale = new Locale(client); + +ContinentList result = await locale.ListContinents(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-dotnet/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..8692c7b78e --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/locale/list-countries-e-u.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var locale = new Locale(client); + +CountryList result = await locale.ListCountriesEU(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-dotnet/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..8607ae90f5 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/locale/list-countries-phones.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var locale = new Locale(client); + +PhoneList result = await locale.ListCountriesPhones(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/locale/list-countries.md b/docs/examples/1.4.x/server-dotnet/examples/locale/list-countries.md new file mode 100644 index 0000000000..c67d863856 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/locale/list-countries.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var locale = new Locale(client); + +CountryList result = await locale.ListCountries(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-dotnet/examples/locale/list-currencies.md new file mode 100644 index 0000000000..1bb3c427e0 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/locale/list-currencies.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var locale = new Locale(client); + +CurrencyList result = await locale.ListCurrencies(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/locale/list-languages.md b/docs/examples/1.4.x/server-dotnet/examples/locale/list-languages.md new file mode 100644 index 0000000000..1c2897d4fb --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/locale/list-languages.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var locale = new Locale(client); + +LanguageList result = await locale.ListLanguages(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-dotnet/examples/storage/create-bucket.md new file mode 100644 index 0000000000..b1da6cb0bd --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/create-bucket.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +Bucket result = await storage.CreateBucket( + bucketId: "[BUCKET_ID]", + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/create-file.md b/docs/examples/1.4.x/server-dotnet/examples/storage/create-file.md new file mode 100644 index 0000000000..f7d7315209 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/create-file.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +File result = await storage.CreateFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]", + file: InputFile.FromPath("./path-to-files/image.jpg")); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-dotnet/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..c8825f3063 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/delete-bucket.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +await storage.DeleteBucket( + bucketId: "[BUCKET_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/delete-file.md b/docs/examples/1.4.x/server-dotnet/examples/storage/delete-file.md new file mode 100644 index 0000000000..8b70175d97 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/delete-file.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +await storage.DeleteFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-dotnet/examples/storage/get-bucket.md new file mode 100644 index 0000000000..aca9020f28 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/get-bucket.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +Bucket result = await storage.GetBucket( + bucketId: "[BUCKET_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-dotnet/examples/storage/get-file-download.md new file mode 100644 index 0000000000..e6aa24bea3 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/get-file-download.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +byte[] result = await storage.GetFileDownload( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-dotnet/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..92565ae5ef --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/get-file-preview.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +byte[] result = await storage.GetFilePreview( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-dotnet/examples/storage/get-file-view.md new file mode 100644 index 0000000000..081f2dce7b --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/get-file-view.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +byte[] result = await storage.GetFileView( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/get-file.md b/docs/examples/1.4.x/server-dotnet/examples/storage/get-file.md new file mode 100644 index 0000000000..0299a91bbe --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/get-file.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +File result = await storage.GetFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-dotnet/examples/storage/list-buckets.md new file mode 100644 index 0000000000..2caae5e0af --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/list-buckets.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +BucketList result = await storage.ListBuckets(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/list-files.md b/docs/examples/1.4.x/server-dotnet/examples/storage/list-files.md new file mode 100644 index 0000000000..9d861171ac --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/list-files.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +FileList result = await storage.ListFiles( + bucketId: "[BUCKET_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-dotnet/examples/storage/update-bucket.md new file mode 100644 index 0000000000..eac7456209 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/update-bucket.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +Bucket result = await storage.UpdateBucket( + bucketId: "[BUCKET_ID]", + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/storage/update-file.md b/docs/examples/1.4.x/server-dotnet/examples/storage/update-file.md new file mode 100644 index 0000000000..c51d335eef --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/storage/update-file.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var storage = new Storage(client); + +File result = await storage.UpdateFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/create-membership.md b/docs/examples/1.4.x/server-dotnet/examples/teams/create-membership.md new file mode 100644 index 0000000000..bcc331724e --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/create-membership.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +Membership result = await teams.CreateMembership( + teamId: "[TEAM_ID]", + roles: new List {}, + url: "https://example.com"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/create.md b/docs/examples/1.4.x/server-dotnet/examples/teams/create.md new file mode 100644 index 0000000000..fa34098cb2 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/create.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +Team result = await teams.Create( + teamId: "[TEAM_ID]", + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-dotnet/examples/teams/delete-membership.md new file mode 100644 index 0000000000..e3c7562f99 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/delete-membership.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +await teams.DeleteMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/delete.md b/docs/examples/1.4.x/server-dotnet/examples/teams/delete.md new file mode 100644 index 0000000000..8229839b1c --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/delete.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +await teams.Delete( + teamId: "[TEAM_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/get-membership.md b/docs/examples/1.4.x/server-dotnet/examples/teams/get-membership.md new file mode 100644 index 0000000000..108dbadbe0 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/get-membership.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +Membership result = await teams.GetMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-dotnet/examples/teams/get-prefs.md new file mode 100644 index 0000000000..08be12ba83 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/get-prefs.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var teams = new Teams(client); + +Preferences result = await teams.GetPrefs( + teamId: "[TEAM_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/get.md b/docs/examples/1.4.x/server-dotnet/examples/teams/get.md new file mode 100644 index 0000000000..f6c92a007b --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/get.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +Team result = await teams.Get( + teamId: "[TEAM_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-dotnet/examples/teams/list-memberships.md new file mode 100644 index 0000000000..145376cfb9 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/list-memberships.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +MembershipList result = await teams.ListMemberships( + teamId: "[TEAM_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/list.md b/docs/examples/1.4.x/server-dotnet/examples/teams/list.md new file mode 100644 index 0000000000..1acf615039 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/list.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +TeamList result = await teams.List(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-dotnet/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..bb377203cc --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/update-membership-status.md @@ -0,0 +1,16 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var teams = new Teams(client); + +Membership result = await teams.UpdateMembershipStatus( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + userId: "[USER_ID]", + secret: "[SECRET]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/update-membership.md b/docs/examples/1.4.x/server-dotnet/examples/teams/update-membership.md new file mode 100644 index 0000000000..70ad79f23f --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/update-membership.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +Membership result = await teams.UpdateMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + roles: new List {}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/update-name.md b/docs/examples/1.4.x/server-dotnet/examples/teams/update-name.md new file mode 100644 index 0000000000..1286730437 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/update-name.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var teams = new Teams(client); + +Team result = await teams.UpdateName( + teamId: "[TEAM_ID]", + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-dotnet/examples/teams/update-prefs.md new file mode 100644 index 0000000000..3dfc0a3fc1 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/teams/update-prefs.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +var teams = new Teams(client); + +Preferences result = await teams.UpdatePrefs( + teamId: "[TEAM_ID]", + prefs: [object]); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-dotnet/examples/users/create-argon2user.md new file mode 100644 index 0000000000..6038594547 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/create-argon2user.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.CreateArgon2User( + userId: "[USER_ID]", + email: "email@example.com", + password: "password"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-dotnet/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..954e1ad1cc --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/create-bcrypt-user.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.CreateBcryptUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-dotnet/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..de54ee98fe --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/create-m-d5user.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.CreateMD5User( + userId: "[USER_ID]", + email: "email@example.com", + password: "password"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-dotnet/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..e8ede042da --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/create-p-h-pass-user.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.CreatePHPassUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-dotnet/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..f381619651 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/create-s-h-a-user.md @@ -0,0 +1,15 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.CreateSHAUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-dotnet/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..c16cfe97f9 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,18 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.CreateScryptModifiedUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password", + passwordSalt: "[PASSWORD_SALT]", + passwordSaltSeparator: "[PASSWORD_SALT_SEPARATOR]", + passwordSignerKey: "[PASSWORD_SIGNER_KEY]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-dotnet/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..1d6e60dd2d --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/create-scrypt-user.md @@ -0,0 +1,20 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.CreateScryptUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password", + passwordSalt: "[PASSWORD_SALT]", + passwordCpu: 0, + passwordMemory: 0, + passwordParallel: 0, + passwordLength: 0); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/create.md b/docs/examples/1.4.x/server-dotnet/examples/users/create.md new file mode 100644 index 0000000000..0a8421a544 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/create.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.Create( + userId: "[USER_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/delete-identity.md b/docs/examples/1.4.x/server-dotnet/examples/users/delete-identity.md new file mode 100644 index 0000000000..f1425a9ab3 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/delete-identity.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +await users.DeleteIdentity( + identityId: "[IDENTITY_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/delete-session.md b/docs/examples/1.4.x/server-dotnet/examples/users/delete-session.md new file mode 100644 index 0000000000..841bd456c8 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/delete-session.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +await users.DeleteSession( + userId: "[USER_ID]", + sessionId: "[SESSION_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-dotnet/examples/users/delete-sessions.md new file mode 100644 index 0000000000..8ff8f76522 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/delete-sessions.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +await users.DeleteSessions( + userId: "[USER_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/delete.md b/docs/examples/1.4.x/server-dotnet/examples/users/delete.md new file mode 100644 index 0000000000..7833a7950f --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/delete.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +await users.Delete( + userId: "[USER_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/get-prefs.md b/docs/examples/1.4.x/server-dotnet/examples/users/get-prefs.md new file mode 100644 index 0000000000..c19f5e0778 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/get-prefs.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +Preferences result = await users.GetPrefs( + userId: "[USER_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/get.md b/docs/examples/1.4.x/server-dotnet/examples/users/get.md new file mode 100644 index 0000000000..9c315e6021 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/get.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.Get( + userId: "[USER_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/list-identities.md b/docs/examples/1.4.x/server-dotnet/examples/users/list-identities.md new file mode 100644 index 0000000000..af8f99620f --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/list-identities.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +IdentityList result = await users.ListIdentities(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/list-logs.md b/docs/examples/1.4.x/server-dotnet/examples/users/list-logs.md new file mode 100644 index 0000000000..277addcd25 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/list-logs.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +LogList result = await users.ListLogs( + userId: "[USER_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/list-memberships.md b/docs/examples/1.4.x/server-dotnet/examples/users/list-memberships.md new file mode 100644 index 0000000000..c25d98b41d --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/list-memberships.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +MembershipList result = await users.ListMemberships( + userId: "[USER_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/list-sessions.md b/docs/examples/1.4.x/server-dotnet/examples/users/list-sessions.md new file mode 100644 index 0000000000..fcd87f01ad --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/list-sessions.md @@ -0,0 +1,13 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +SessionList result = await users.ListSessions( + userId: "[USER_ID]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/list.md b/docs/examples/1.4.x/server-dotnet/examples/users/list.md new file mode 100644 index 0000000000..9cb177b692 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/list.md @@ -0,0 +1,12 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +UserList result = await users.List(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-dotnet/examples/users/update-email-verification.md new file mode 100644 index 0000000000..2b7a5b8674 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/update-email-verification.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.UpdateEmailVerification( + userId: "[USER_ID]", + emailVerification: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/update-email.md b/docs/examples/1.4.x/server-dotnet/examples/users/update-email.md new file mode 100644 index 0000000000..0d371b13fc --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/update-email.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.UpdateEmail( + userId: "[USER_ID]", + email: "email@example.com"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/update-labels.md b/docs/examples/1.4.x/server-dotnet/examples/users/update-labels.md new file mode 100644 index 0000000000..97d5db356a --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/update-labels.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.UpdateLabels( + userId: "[USER_ID]", + labels: new List {}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/update-name.md b/docs/examples/1.4.x/server-dotnet/examples/users/update-name.md new file mode 100644 index 0000000000..f846543117 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/update-name.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.UpdateName( + userId: "[USER_ID]", + name: "[NAME]"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/update-password.md b/docs/examples/1.4.x/server-dotnet/examples/users/update-password.md new file mode 100644 index 0000000000..ce3241dfd5 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/update-password.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.UpdatePassword( + userId: "[USER_ID]", + password: ""); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-dotnet/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..c2fd1673de --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/update-phone-verification.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.UpdatePhoneVerification( + userId: "[USER_ID]", + phoneVerification: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/update-phone.md b/docs/examples/1.4.x/server-dotnet/examples/users/update-phone.md new file mode 100644 index 0000000000..90728d76c7 --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/update-phone.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.UpdatePhone( + userId: "[USER_ID]", + number: "+12065550100"); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/update-prefs.md b/docs/examples/1.4.x/server-dotnet/examples/users/update-prefs.md new file mode 100644 index 0000000000..a39d54565a --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/update-prefs.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +Preferences result = await users.UpdatePrefs( + userId: "[USER_ID]", + prefs: [object]); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-dotnet/examples/users/update-status.md b/docs/examples/1.4.x/server-dotnet/examples/users/update-status.md new file mode 100644 index 0000000000..713ece02ba --- /dev/null +++ b/docs/examples/1.4.x/server-dotnet/examples/users/update-status.md @@ -0,0 +1,14 @@ +using Appwrite; +using Appwrite.Services; +using Appwrite.Models; + +var client = new Client() + .SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("5df5acd0d48c2") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +var users = new Users(client); + +User result = await users.UpdateStatus( + userId: "[USER_ID]", + status: false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-graphql/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-graphql/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..200e1c6d3a --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/create-phone-verification.md @@ -0,0 +1,9 @@ +mutation { + accountCreatePhoneVerification { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/create-recovery.md b/docs/examples/1.4.x/server-graphql/examples/account/create-recovery.md new file mode 100644 index 0000000000..865add6cc5 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/create-recovery.md @@ -0,0 +1,12 @@ +mutation { + accountCreateRecovery( + email: "email@example.com", + url: "https://example.com" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/create-verification.md b/docs/examples/1.4.x/server-graphql/examples/account/create-verification.md new file mode 100644 index 0000000000..22490be6b0 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/create-verification.md @@ -0,0 +1,11 @@ +mutation { + accountCreateVerification( + url: "https://example.com" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/delete-identity.md b/docs/examples/1.4.x/server-graphql/examples/account/delete-identity.md new file mode 100644 index 0000000000..9bd9f0fa80 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/delete-identity.md @@ -0,0 +1,7 @@ +mutation { + accountDeleteIdentity( + identityId: "[IDENTITY_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/delete-session.md b/docs/examples/1.4.x/server-graphql/examples/account/delete-session.md new file mode 100644 index 0000000000..013bfa5946 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/delete-session.md @@ -0,0 +1,7 @@ +mutation { + accountDeleteSession( + sessionId: "[SESSION_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-graphql/examples/account/delete-sessions.md new file mode 100644 index 0000000000..b0d61daa81 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/delete-sessions.md @@ -0,0 +1,5 @@ +mutation { + accountDeleteSessions { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/get-prefs.md b/docs/examples/1.4.x/server-graphql/examples/account/get-prefs.md new file mode 100644 index 0000000000..6cb48d2b58 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/get-prefs.md @@ -0,0 +1,5 @@ +query { + accountGetPrefs { + data + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/get-session.md b/docs/examples/1.4.x/server-graphql/examples/account/get-session.md new file mode 100644 index 0000000000..2bf4e28c77 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/get-session.md @@ -0,0 +1,31 @@ +query { + accountGetSession( + sessionId: "[SESSION_ID]" + ) { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/get.md b/docs/examples/1.4.x/server-graphql/examples/account/get.md new file mode 100644 index 0000000000..39d06b1e1f --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/get.md @@ -0,0 +1,20 @@ +query { + accountGet { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/list-identities.md b/docs/examples/1.4.x/server-graphql/examples/account/list-identities.md new file mode 100644 index 0000000000..25c7e71462 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/list-identities.md @@ -0,0 +1,17 @@ +query { + accountListIdentities { + total + identities { + _id + _createdAt + _updatedAt + userId + provider + providerUid + providerEmail + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/list-logs.md b/docs/examples/1.4.x/server-graphql/examples/account/list-logs.md new file mode 100644 index 0000000000..95fd3bd7f3 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/list-logs.md @@ -0,0 +1,28 @@ +query { + accountListLogs { + total + logs { + event + userId + userEmail + userName + mode + ip + time + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/list-sessions.md b/docs/examples/1.4.x/server-graphql/examples/account/list-sessions.md new file mode 100644 index 0000000000..a089bf0b99 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/list-sessions.md @@ -0,0 +1,32 @@ +query { + accountListSessions { + total + sessions { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-email.md b/docs/examples/1.4.x/server-graphql/examples/account/update-email.md new file mode 100644 index 0000000000..1c11d65eae --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-email.md @@ -0,0 +1,23 @@ +mutation { + accountUpdateEmail( + email: "email@example.com", + password: "password" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-name.md b/docs/examples/1.4.x/server-graphql/examples/account/update-name.md new file mode 100644 index 0000000000..0bfa34f84f --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-name.md @@ -0,0 +1,22 @@ +mutation { + accountUpdateName( + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-password.md b/docs/examples/1.4.x/server-graphql/examples/account/update-password.md new file mode 100644 index 0000000000..35e1db66ec --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-password.md @@ -0,0 +1,22 @@ +mutation { + accountUpdatePassword( + password: "" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-graphql/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..103c2faf18 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-phone-verification.md @@ -0,0 +1,12 @@ +mutation { + accountUpdatePhoneVerification( + userId: "[USER_ID]", + secret: "[SECRET]" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-phone.md b/docs/examples/1.4.x/server-graphql/examples/account/update-phone.md new file mode 100644 index 0000000000..e1870ed451 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-phone.md @@ -0,0 +1,23 @@ +mutation { + accountUpdatePhone( + phone: "+12065550100", + password: "password" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-prefs.md b/docs/examples/1.4.x/server-graphql/examples/account/update-prefs.md new file mode 100644 index 0000000000..11e500c343 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-prefs.md @@ -0,0 +1,22 @@ +mutation { + accountUpdatePrefs( + prefs: "{}" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-recovery.md b/docs/examples/1.4.x/server-graphql/examples/account/update-recovery.md new file mode 100644 index 0000000000..a0c985d7db --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-recovery.md @@ -0,0 +1,14 @@ +mutation { + accountUpdateRecovery( + userId: "[USER_ID]", + secret: "[SECRET]", + password: "password", + passwordAgain: "password" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-session.md b/docs/examples/1.4.x/server-graphql/examples/account/update-session.md new file mode 100644 index 0000000000..0358f49588 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-session.md @@ -0,0 +1,31 @@ +mutation { + accountUpdateSession( + sessionId: "[SESSION_ID]" + ) { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-status.md b/docs/examples/1.4.x/server-graphql/examples/account/update-status.md new file mode 100644 index 0000000000..6f68c7d054 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-status.md @@ -0,0 +1,20 @@ +mutation { + accountUpdateStatus { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/account/update-verification.md b/docs/examples/1.4.x/server-graphql/examples/account/update-verification.md new file mode 100644 index 0000000000..47abb20d34 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/account/update-verification.md @@ -0,0 +1,12 @@ +mutation { + accountUpdateVerification( + userId: "[USER_ID]", + secret: "[SECRET]" + ) { + _id + _createdAt + userId + secret + expire + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-graphql/examples/avatars/get-browser.md new file mode 100644 index 0000000000..a76df8a6a2 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/avatars/get-browser.md @@ -0,0 +1,7 @@ +query { + avatarsGetBrowser( + code: "aa" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-graphql/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..84a56c1eaa --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/avatars/get-credit-card.md @@ -0,0 +1,7 @@ +query { + avatarsGetCreditCard( + code: "amex" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-graphql/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..bfea71f498 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/avatars/get-favicon.md @@ -0,0 +1,7 @@ +query { + avatarsGetFavicon( + url: "https://example.com" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-graphql/examples/avatars/get-flag.md new file mode 100644 index 0000000000..6f3b6b5421 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/avatars/get-flag.md @@ -0,0 +1,7 @@ +query { + avatarsGetFlag( + code: "af" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/avatars/get-image.md b/docs/examples/1.4.x/server-graphql/examples/avatars/get-image.md new file mode 100644 index 0000000000..3371036d31 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/avatars/get-image.md @@ -0,0 +1,7 @@ +query { + avatarsGetImage( + url: "https://example.com" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-graphql/examples/avatars/get-initials.md new file mode 100644 index 0000000000..a1d8bef89c --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/avatars/get-initials.md @@ -0,0 +1,5 @@ +query { + avatarsGetInitials { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-graphql/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..d2cc1f7f2c --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/avatars/get-q-r.md @@ -0,0 +1,7 @@ +query { + avatarsGetQR( + text: "[TEXT]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..8359b45f2b --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-boolean-attribute.md @@ -0,0 +1,14 @@ +mutation { + databasesCreateBooleanAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false + ) { + key + type + status + error + required + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-collection.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-collection.md new file mode 100644 index 0000000000..52514e2125 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-collection.md @@ -0,0 +1,24 @@ +mutation { + databasesCreateCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + _permissions + databaseId + name + enabled + documentSecurity + attributes + indexes { + key + type + status + error + attributes + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..d39a0520ed --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-datetime-attribute.md @@ -0,0 +1,15 @@ +mutation { + databasesCreateDatetimeAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false + ) { + key + type + status + error + required + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-document.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-document.md new file mode 100644 index 0000000000..6ef546c0de --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-document.md @@ -0,0 +1,16 @@ +mutation { + databasesCreateDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]", + data: "{}" + ) { + _id + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..4fcc20de15 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-email-attribute.md @@ -0,0 +1,15 @@ +mutation { + databasesCreateEmailAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false + ) { + key + type + status + error + required + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..8f35d10cae --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-enum-attribute.md @@ -0,0 +1,17 @@ +mutation { + databasesCreateEnumAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + elements: [], + required: false + ) { + key + type + status + error + required + elements + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..f85b778390 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-float-attribute.md @@ -0,0 +1,14 @@ +mutation { + databasesCreateFloatAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false + ) { + key + type + status + error + required + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-index.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-index.md new file mode 100644 index 0000000000..46ab3439ff --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-index.md @@ -0,0 +1,15 @@ +mutation { + databasesCreateIndex( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + type: "key", + attributes: [] + ) { + key + type + status + error + attributes + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..04c2ae7ede --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-integer-attribute.md @@ -0,0 +1,14 @@ +mutation { + databasesCreateIntegerAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false + ) { + key + type + status + error + required + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..442732bfa0 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-ip-attribute.md @@ -0,0 +1,15 @@ +mutation { + databasesCreateIpAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false + ) { + key + type + status + error + required + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..93fb7ca0dc --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-relationship-attribute.md @@ -0,0 +1,20 @@ +mutation { + databasesCreateRelationshipAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + relatedCollectionId: "[RELATED_COLLECTION_ID]", + type: "oneToOne" + ) { + key + type + status + error + required + relatedCollection + relationType + twoWay + twoWayKey + onDelete + side + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..aca9171e07 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-string-attribute.md @@ -0,0 +1,16 @@ +mutation { + databasesCreateStringAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + size: 1, + required: false + ) { + key + type + status + error + required + size + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..65cbbaa819 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create-url-attribute.md @@ -0,0 +1,15 @@ +mutation { + databasesCreateUrlAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false + ) { + key + type + status + error + required + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/create.md b/docs/examples/1.4.x/server-graphql/examples/databases/create.md new file mode 100644 index 0000000000..e784d95975 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/create.md @@ -0,0 +1,12 @@ +mutation { + databasesCreate( + databaseId: "[DATABASE_ID]", + name: "[NAME]" + ) { + _id + name + _createdAt + _updatedAt + enabled + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..f2cac81fce --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/delete-attribute.md @@ -0,0 +1,9 @@ +mutation { + databasesDeleteAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-graphql/examples/databases/delete-collection.md new file mode 100644 index 0000000000..bb7673840d --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/delete-collection.md @@ -0,0 +1,8 @@ +mutation { + databasesDeleteCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/delete-document.md b/docs/examples/1.4.x/server-graphql/examples/databases/delete-document.md new file mode 100644 index 0000000000..74954bb61b --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/delete-document.md @@ -0,0 +1,9 @@ +mutation { + databasesDeleteDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/delete-index.md b/docs/examples/1.4.x/server-graphql/examples/databases/delete-index.md new file mode 100644 index 0000000000..36764b61da --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/delete-index.md @@ -0,0 +1,9 @@ +mutation { + databasesDeleteIndex( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/delete.md b/docs/examples/1.4.x/server-graphql/examples/databases/delete.md new file mode 100644 index 0000000000..184f3a3c68 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/delete.md @@ -0,0 +1,7 @@ +mutation { + databasesDelete( + databaseId: "[DATABASE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/get-attribute.md new file mode 100644 index 0000000000..e93dd7e52d --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/get-attribute.md @@ -0,0 +1,9 @@ +query { + databasesGetAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/get-collection.md b/docs/examples/1.4.x/server-graphql/examples/databases/get-collection.md new file mode 100644 index 0000000000..dc4b9701f6 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/get-collection.md @@ -0,0 +1,23 @@ +query { + databasesGetCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" + ) { + _id + _createdAt + _updatedAt + _permissions + databaseId + name + enabled + documentSecurity + attributes + indexes { + key + type + status + error + attributes + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/get-document.md b/docs/examples/1.4.x/server-graphql/examples/databases/get-document.md new file mode 100644 index 0000000000..94b30290a2 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/get-document.md @@ -0,0 +1,15 @@ +query { + databasesGetDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" + ) { + _id + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/get-index.md b/docs/examples/1.4.x/server-graphql/examples/databases/get-index.md new file mode 100644 index 0000000000..d14377d11d --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/get-index.md @@ -0,0 +1,13 @@ +query { + databasesGetIndex( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" + ) { + key + type + status + error + attributes + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/get.md b/docs/examples/1.4.x/server-graphql/examples/databases/get.md new file mode 100644 index 0000000000..42a8fe54e3 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/get.md @@ -0,0 +1,11 @@ +query { + databasesGet( + databaseId: "[DATABASE_ID]" + ) { + _id + name + _createdAt + _updatedAt + enabled + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-graphql/examples/databases/list-attributes.md new file mode 100644 index 0000000000..6b5caa6195 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/list-attributes.md @@ -0,0 +1,9 @@ +query { + databasesListAttributes( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" + ) { + total + attributes + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/list-collections.md b/docs/examples/1.4.x/server-graphql/examples/databases/list-collections.md new file mode 100644 index 0000000000..52060fd119 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/list-collections.md @@ -0,0 +1,25 @@ +query { + databasesListCollections( + databaseId: "[DATABASE_ID]" + ) { + total + collections { + _id + _createdAt + _updatedAt + _permissions + databaseId + name + enabled + documentSecurity + attributes + indexes { + key + type + status + error + attributes + } + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/list-documents.md b/docs/examples/1.4.x/server-graphql/examples/databases/list-documents.md new file mode 100644 index 0000000000..62d799ad91 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/list-documents.md @@ -0,0 +1,17 @@ +query { + databasesListDocuments( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" + ) { + total + documents { + _id + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-graphql/examples/databases/list-indexes.md new file mode 100644 index 0000000000..9f831d6fd1 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/list-indexes.md @@ -0,0 +1,15 @@ +query { + databasesListIndexes( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" + ) { + total + indexes { + key + type + status + error + attributes + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/list.md b/docs/examples/1.4.x/server-graphql/examples/databases/list.md new file mode 100644 index 0000000000..6438ed4ca8 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/list.md @@ -0,0 +1,12 @@ +query { + databasesList { + total + databases { + _id + name + _createdAt + _updatedAt + enabled + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..840c7c07d0 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-boolean-attribute.md @@ -0,0 +1,15 @@ +mutation { + databasesUpdateBooleanAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: false + ) { + key + type + status + error + required + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-collection.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-collection.md new file mode 100644 index 0000000000..ee3f46d6bb --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-collection.md @@ -0,0 +1,24 @@ +mutation { + databasesUpdateCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + _permissions + databaseId + name + enabled + documentSecurity + attributes + indexes { + key + type + status + error + attributes + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..bb818b6364 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-datetime-attribute.md @@ -0,0 +1,16 @@ +mutation { + databasesUpdateDatetimeAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: "" + ) { + key + type + status + error + required + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-document.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-document.md new file mode 100644 index 0000000000..0476c4ce40 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-document.md @@ -0,0 +1,15 @@ +mutation { + databasesUpdateDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" + ) { + _id + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..8f568b1469 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-email-attribute.md @@ -0,0 +1,16 @@ +mutation { + databasesUpdateEmailAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: "email@example.com" + ) { + key + type + status + error + required + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..5fa4c7d56b --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-enum-attribute.md @@ -0,0 +1,18 @@ +mutation { + databasesUpdateEnumAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + elements: [], + required: false, + default: "[DEFAULT]" + ) { + key + type + status + error + required + elements + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..4268d921ce --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-float-attribute.md @@ -0,0 +1,17 @@ +mutation { + databasesUpdateFloatAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + min: 0, + max: 0, + default: 0 + ) { + key + type + status + error + required + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..141d5d1c17 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-integer-attribute.md @@ -0,0 +1,17 @@ +mutation { + databasesUpdateIntegerAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + min: 0, + max: 0, + default: 0 + ) { + key + type + status + error + required + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..c54f342769 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-ip-attribute.md @@ -0,0 +1,16 @@ +mutation { + databasesUpdateIpAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: "" + ) { + key + type + status + error + required + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..9d17811a7f --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-relationship-attribute.md @@ -0,0 +1,19 @@ +mutation { + databasesUpdateRelationshipAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" + ) { + key + type + status + error + required + relatedCollection + relationType + twoWay + twoWayKey + onDelete + side + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..ad0a5e696d --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-string-attribute.md @@ -0,0 +1,16 @@ +mutation { + databasesUpdateStringAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: "[DEFAULT]" + ) { + key + type + status + error + required + size + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-graphql/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..e40549b01f --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update-url-attribute.md @@ -0,0 +1,16 @@ +mutation { + databasesUpdateUrlAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: false, + default: "https://example.com" + ) { + key + type + status + error + required + format + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/databases/update.md b/docs/examples/1.4.x/server-graphql/examples/databases/update.md new file mode 100644 index 0000000000..8ee59ddfd4 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/databases/update.md @@ -0,0 +1,12 @@ +mutation { + databasesUpdate( + databaseId: "[DATABASE_ID]", + name: "[NAME]" + ) { + _id + name + _createdAt + _updatedAt + enabled + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/create-build.md b/docs/examples/1.4.x/server-graphql/examples/functions/create-build.md new file mode 100644 index 0000000000..7828c633d0 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/create-build.md @@ -0,0 +1,9 @@ +mutation { + functionsCreateBuild( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]", + buildId: "[BUILD_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-graphql/examples/functions/create-deployment.md new file mode 100644 index 0000000000..13b224afec --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/create-deployment.md @@ -0,0 +1,24 @@ +POST /v1/functions/{functionId}/deployments HTTP/1.1 +Host: HOSTNAME +Content-Type: multipart/form-data; boundary="cec8e8123c05ba25" +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +Content-Length: *Length of your entity body in bytes* + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="operations" + +{ "query": "mutation { functionsCreateDeployment(functionId: $functionId, code: $code, activate: $activate) { id }" }, "variables": { "functionId": "[FUNCTION_ID]", "code": null, "activate": false } } + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="map" + +{ "0": ["variables.code"], } + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="0"; filename="code.ext" + +File contents + +--cec8e8123c05ba25-- diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/create-execution.md b/docs/examples/1.4.x/server-graphql/examples/functions/create-execution.md new file mode 100644 index 0000000000..56e58db014 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/create-execution.md @@ -0,0 +1,28 @@ +mutation { + functionsCreateExecution( + functionId: "[FUNCTION_ID]" + ) { + _id + _createdAt + _updatedAt + _permissions + functionId + trigger + status + requestMethod + requestPath + requestHeaders { + name + value + } + responseStatusCode + responseBody + responseHeaders { + name + value + } + logs + errors + duration + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/create-variable.md b/docs/examples/1.4.x/server-graphql/examples/functions/create-variable.md new file mode 100644 index 0000000000..640cac2f38 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/create-variable.md @@ -0,0 +1,15 @@ +mutation { + functionsCreateVariable( + functionId: "[FUNCTION_ID]", + key: "[KEY]", + value: "[VALUE]" + ) { + _id + _createdAt + _updatedAt + key + value + resourceType + resourceId + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/create.md b/docs/examples/1.4.x/server-graphql/examples/functions/create.md new file mode 100644 index 0000000000..b7b6c8fcd4 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/create.md @@ -0,0 +1,38 @@ +mutation { + functionsCreate( + functionId: "[FUNCTION_ID]", + name: "[NAME]", + runtime: "node-14.5" + ) { + _id + _createdAt + _updatedAt + execute + name + enabled + live + logging + runtime + deployment + vars { + _id + _createdAt + _updatedAt + key + value + resourceType + resourceId + } + events + schedule + timeout + entrypoint + commands + version + installationId + providerRepositoryId + providerBranch + providerRootDirectory + providerSilentMode + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-graphql/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..524d3fb36a --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/delete-deployment.md @@ -0,0 +1,8 @@ +mutation { + functionsDeleteDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-graphql/examples/functions/delete-variable.md new file mode 100644 index 0000000000..bfa7018f38 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/delete-variable.md @@ -0,0 +1,8 @@ +mutation { + functionsDeleteVariable( + functionId: "[FUNCTION_ID]", + variableId: "[VARIABLE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/delete.md b/docs/examples/1.4.x/server-graphql/examples/functions/delete.md new file mode 100644 index 0000000000..84c70f4dcc --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/delete.md @@ -0,0 +1,7 @@ +mutation { + functionsDelete( + functionId: "[FUNCTION_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-graphql/examples/functions/download-deployment.md new file mode 100644 index 0000000000..02666132cf --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/download-deployment.md @@ -0,0 +1,8 @@ +query { + functionsDownloadDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-graphql/examples/functions/get-deployment.md new file mode 100644 index 0000000000..480b9dd944 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/get-deployment.md @@ -0,0 +1,30 @@ +query { + functionsGetDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]" + ) { + _id + _createdAt + _updatedAt + type + resourceId + resourceType + entrypoint + size + buildId + activate + status + buildLogs + buildTime + providerRepositoryName + providerRepositoryOwner + providerRepositoryUrl + providerBranch + providerCommitHash + providerCommitAuthorUrl + providerCommitAuthor + providerCommitMessage + providerCommitUrl + providerBranchUrl + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/get-execution.md b/docs/examples/1.4.x/server-graphql/examples/functions/get-execution.md new file mode 100644 index 0000000000..bf19fca107 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/get-execution.md @@ -0,0 +1,29 @@ +query { + functionsGetExecution( + functionId: "[FUNCTION_ID]", + executionId: "[EXECUTION_ID]" + ) { + _id + _createdAt + _updatedAt + _permissions + functionId + trigger + status + requestMethod + requestPath + requestHeaders { + name + value + } + responseStatusCode + responseBody + responseHeaders { + name + value + } + logs + errors + duration + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/get-variable.md b/docs/examples/1.4.x/server-graphql/examples/functions/get-variable.md new file mode 100644 index 0000000000..c41e88391b --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/get-variable.md @@ -0,0 +1,14 @@ +query { + functionsGetVariable( + functionId: "[FUNCTION_ID]", + variableId: "[VARIABLE_ID]" + ) { + _id + _createdAt + _updatedAt + key + value + resourceType + resourceId + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/get.md b/docs/examples/1.4.x/server-graphql/examples/functions/get.md new file mode 100644 index 0000000000..ffb3d6e29c --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/get.md @@ -0,0 +1,36 @@ +query { + functionsGet( + functionId: "[FUNCTION_ID]" + ) { + _id + _createdAt + _updatedAt + execute + name + enabled + live + logging + runtime + deployment + vars { + _id + _createdAt + _updatedAt + key + value + resourceType + resourceId + } + events + schedule + timeout + entrypoint + commands + version + installationId + providerRepositoryId + providerBranch + providerRootDirectory + providerSilentMode + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-graphql/examples/functions/list-deployments.md new file mode 100644 index 0000000000..ed12c37e19 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/list-deployments.md @@ -0,0 +1,32 @@ +query { + functionsListDeployments( + functionId: "[FUNCTION_ID]" + ) { + total + deployments { + _id + _createdAt + _updatedAt + type + resourceId + resourceType + entrypoint + size + buildId + activate + status + buildLogs + buildTime + providerRepositoryName + providerRepositoryOwner + providerRepositoryUrl + providerBranch + providerCommitHash + providerCommitAuthorUrl + providerCommitAuthor + providerCommitMessage + providerCommitUrl + providerBranchUrl + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/list-executions.md b/docs/examples/1.4.x/server-graphql/examples/functions/list-executions.md new file mode 100644 index 0000000000..86b656d428 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/list-executions.md @@ -0,0 +1,31 @@ +query { + functionsListExecutions( + functionId: "[FUNCTION_ID]" + ) { + total + executions { + _id + _createdAt + _updatedAt + _permissions + functionId + trigger + status + requestMethod + requestPath + requestHeaders { + name + value + } + responseStatusCode + responseBody + responseHeaders { + name + value + } + logs + errors + duration + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-graphql/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..2c2b207e60 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/list-runtimes.md @@ -0,0 +1,14 @@ +query { + functionsListRuntimes { + total + runtimes { + _id + name + version + base + image + logo + supports + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/list-variables.md b/docs/examples/1.4.x/server-graphql/examples/functions/list-variables.md new file mode 100644 index 0000000000..477d8abc7a --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/list-variables.md @@ -0,0 +1,16 @@ +query { + functionsListVariables( + functionId: "[FUNCTION_ID]" + ) { + total + variables { + _id + _createdAt + _updatedAt + key + value + resourceType + resourceId + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/list.md b/docs/examples/1.4.x/server-graphql/examples/functions/list.md new file mode 100644 index 0000000000..49d6271882 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/list.md @@ -0,0 +1,37 @@ +query { + functionsList { + total + functions { + _id + _createdAt + _updatedAt + execute + name + enabled + live + logging + runtime + deployment + vars { + _id + _createdAt + _updatedAt + key + value + resourceType + resourceId + } + events + schedule + timeout + entrypoint + commands + version + installationId + providerRepositoryId + providerBranch + providerRootDirectory + providerSilentMode + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-graphql/examples/functions/update-deployment.md new file mode 100644 index 0000000000..8486a7a0d8 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/update-deployment.md @@ -0,0 +1,37 @@ +mutation { + functionsUpdateDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]" + ) { + _id + _createdAt + _updatedAt + execute + name + enabled + live + logging + runtime + deployment + vars { + _id + _createdAt + _updatedAt + key + value + resourceType + resourceId + } + events + schedule + timeout + entrypoint + commands + version + installationId + providerRepositoryId + providerBranch + providerRootDirectory + providerSilentMode + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/update-variable.md b/docs/examples/1.4.x/server-graphql/examples/functions/update-variable.md new file mode 100644 index 0000000000..d070afb34d --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/update-variable.md @@ -0,0 +1,15 @@ +mutation { + functionsUpdateVariable( + functionId: "[FUNCTION_ID]", + variableId: "[VARIABLE_ID]", + key: "[KEY]" + ) { + _id + _createdAt + _updatedAt + key + value + resourceType + resourceId + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/functions/update.md b/docs/examples/1.4.x/server-graphql/examples/functions/update.md new file mode 100644 index 0000000000..15903b2080 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/functions/update.md @@ -0,0 +1,38 @@ +mutation { + functionsUpdate( + functionId: "[FUNCTION_ID]", + name: "[NAME]", + runtime: "node-14.5" + ) { + _id + _createdAt + _updatedAt + execute + name + enabled + live + logging + runtime + deployment + vars { + _id + _createdAt + _updatedAt + key + value + resourceType + resourceId + } + events + schedule + timeout + entrypoint + commands + version + installationId + providerRepositoryId + providerBranch + providerRootDirectory + providerSilentMode + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-graphql/examples/health/get-antivirus.md new file mode 100644 index 0000000000..3634dc11c1 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-antivirus.md @@ -0,0 +1,6 @@ +query { + healthGetAntivirus { + version + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-cache.md b/docs/examples/1.4.x/server-graphql/examples/health/get-cache.md new file mode 100644 index 0000000000..3db4076257 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-cache.md @@ -0,0 +1,7 @@ +query { + healthGetCache { + name + ping + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-d-b.md b/docs/examples/1.4.x/server-graphql/examples/health/get-d-b.md new file mode 100644 index 0000000000..16e67c674e --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-d-b.md @@ -0,0 +1,7 @@ +query { + healthGetDB { + name + ping + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-graphql/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..cec6469b31 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-pub-sub.md @@ -0,0 +1,7 @@ +query { + healthGetPubSub { + name + ping + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-graphql/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..2a65b7fbcf --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-queue-certificates.md @@ -0,0 +1,5 @@ +query { + healthGetQueueCertificates { + size + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-graphql/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..93503aa8c5 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-queue-functions.md @@ -0,0 +1,5 @@ +query { + healthGetQueueFunctions { + size + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-graphql/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..14f68cd02e --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-queue-logs.md @@ -0,0 +1,5 @@ +query { + healthGetQueueLogs { + size + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-graphql/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..fdbe435bf8 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-queue-webhooks.md @@ -0,0 +1,5 @@ +query { + healthGetQueueWebhooks { + size + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-queue.md b/docs/examples/1.4.x/server-graphql/examples/health/get-queue.md new file mode 100644 index 0000000000..721501e4bb --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-queue.md @@ -0,0 +1,7 @@ +query { + healthGetQueue { + name + ping + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-graphql/examples/health/get-storage-local.md new file mode 100644 index 0000000000..953af346ae --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-storage-local.md @@ -0,0 +1,7 @@ +query { + healthGetStorageLocal { + name + ping + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get-time.md b/docs/examples/1.4.x/server-graphql/examples/health/get-time.md new file mode 100644 index 0000000000..0def76b9ad --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get-time.md @@ -0,0 +1,7 @@ +query { + healthGetTime { + remoteTime + localTime + diff + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/health/get.md b/docs/examples/1.4.x/server-graphql/examples/health/get.md new file mode 100644 index 0000000000..8481d3625a --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/health/get.md @@ -0,0 +1,7 @@ +query { + healthGet { + name + ping + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/locale/get.md b/docs/examples/1.4.x/server-graphql/examples/locale/get.md new file mode 100644 index 0000000000..2b2bbcc1f1 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/locale/get.md @@ -0,0 +1,11 @@ +query { + localeGet { + ip + countryCode + country + continentCode + continent + eu + currency + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/locale/list-codes.md b/docs/examples/1.4.x/server-graphql/examples/locale/list-codes.md new file mode 100644 index 0000000000..0164cc3782 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/locale/list-codes.md @@ -0,0 +1,9 @@ +query { + localeListCodes { + total + localeCodes { + code + name + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/locale/list-continents.md b/docs/examples/1.4.x/server-graphql/examples/locale/list-continents.md new file mode 100644 index 0000000000..41f672c565 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/locale/list-continents.md @@ -0,0 +1,9 @@ +query { + localeListContinents { + total + continents { + name + code + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-graphql/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..00cd4652f9 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/locale/list-countries-e-u.md @@ -0,0 +1,9 @@ +query { + localeListCountriesEU { + total + countries { + name + code + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-graphql/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..33d2296850 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/locale/list-countries-phones.md @@ -0,0 +1,10 @@ +query { + localeListCountriesPhones { + total + phones { + code + countryCode + countryName + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/locale/list-countries.md b/docs/examples/1.4.x/server-graphql/examples/locale/list-countries.md new file mode 100644 index 0000000000..9312bc94b1 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/locale/list-countries.md @@ -0,0 +1,9 @@ +query { + localeListCountries { + total + countries { + name + code + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-graphql/examples/locale/list-currencies.md new file mode 100644 index 0000000000..cde3ab488a --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/locale/list-currencies.md @@ -0,0 +1,14 @@ +query { + localeListCurrencies { + total + currencies { + symbol + name + symbolNative + decimalDigits + rounding + code + namePlural + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/locale/list-languages.md b/docs/examples/1.4.x/server-graphql/examples/locale/list-languages.md new file mode 100644 index 0000000000..b0d76c522b --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/locale/list-languages.md @@ -0,0 +1,10 @@ +query { + localeListLanguages { + total + languages { + name + code + nativeName + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-graphql/examples/storage/create-bucket.md new file mode 100644 index 0000000000..3edf18d127 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/create-bucket.md @@ -0,0 +1,19 @@ +mutation { + storageCreateBucket( + bucketId: "[BUCKET_ID]", + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + _permissions + fileSecurity + name + enabled + maximumFileSize + allowedFileExtensions + compression + encryption + antivirus + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/create-file.md b/docs/examples/1.4.x/server-graphql/examples/storage/create-file.md new file mode 100644 index 0000000000..120ac452f3 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/create-file.md @@ -0,0 +1,25 @@ +POST /v1/storage/buckets/{bucketId}/files HTTP/1.1 +Host: HOSTNAME +Content-Type: multipart/form-data; boundary="cec8e8123c05ba25" +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... +Content-Length: *Length of your entity body in bytes* + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="operations" + +{ "query": "mutation { storageCreateFile(bucketId: $bucketId, fileId: $fileId, file: $file) { id }" }, "variables": { "bucketId": "[BUCKET_ID]", "fileId": "[FILE_ID]", "file": null } } + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="map" + +{ "0": ["variables.file"] } + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="0"; filename="file.ext" + +File contents + +--cec8e8123c05ba25-- diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-graphql/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..aaf33a9671 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/delete-bucket.md @@ -0,0 +1,7 @@ +mutation { + storageDeleteBucket( + bucketId: "[BUCKET_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/delete-file.md b/docs/examples/1.4.x/server-graphql/examples/storage/delete-file.md new file mode 100644 index 0000000000..7ec3757a8c --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/delete-file.md @@ -0,0 +1,8 @@ +mutation { + storageDeleteFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-graphql/examples/storage/get-bucket.md new file mode 100644 index 0000000000..02656ece76 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/get-bucket.md @@ -0,0 +1,18 @@ +query { + storageGetBucket( + bucketId: "[BUCKET_ID]" + ) { + _id + _createdAt + _updatedAt + _permissions + fileSecurity + name + enabled + maximumFileSize + allowedFileExtensions + compression + encryption + antivirus + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-graphql/examples/storage/get-file-download.md new file mode 100644 index 0000000000..845547f09b --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/get-file-download.md @@ -0,0 +1,8 @@ +query { + storageGetFileDownload( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-graphql/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..c26e90dac2 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/get-file-preview.md @@ -0,0 +1,8 @@ +query { + storageGetFilePreview( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-graphql/examples/storage/get-file-view.md new file mode 100644 index 0000000000..72e9ec20d2 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/get-file-view.md @@ -0,0 +1,8 @@ +query { + storageGetFileView( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/get-file.md b/docs/examples/1.4.x/server-graphql/examples/storage/get-file.md new file mode 100644 index 0000000000..61182e1f02 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/get-file.md @@ -0,0 +1,18 @@ +query { + storageGetFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + _id + bucketId + _createdAt + _updatedAt + _permissions + name + signature + mimeType + sizeOriginal + chunksTotal + chunksUploaded + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-graphql/examples/storage/list-buckets.md new file mode 100644 index 0000000000..5665a215b7 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/list-buckets.md @@ -0,0 +1,19 @@ +query { + storageListBuckets { + total + buckets { + _id + _createdAt + _updatedAt + _permissions + fileSecurity + name + enabled + maximumFileSize + allowedFileExtensions + compression + encryption + antivirus + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/list-files.md b/docs/examples/1.4.x/server-graphql/examples/storage/list-files.md new file mode 100644 index 0000000000..430fc1dbdf --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/list-files.md @@ -0,0 +1,20 @@ +query { + storageListFiles( + bucketId: "[BUCKET_ID]" + ) { + total + files { + _id + bucketId + _createdAt + _updatedAt + _permissions + name + signature + mimeType + sizeOriginal + chunksTotal + chunksUploaded + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-graphql/examples/storage/update-bucket.md new file mode 100644 index 0000000000..b6372efc0f --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/update-bucket.md @@ -0,0 +1,19 @@ +mutation { + storageUpdateBucket( + bucketId: "[BUCKET_ID]", + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + _permissions + fileSecurity + name + enabled + maximumFileSize + allowedFileExtensions + compression + encryption + antivirus + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/storage/update-file.md b/docs/examples/1.4.x/server-graphql/examples/storage/update-file.md new file mode 100644 index 0000000000..0a4c98d087 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/storage/update-file.md @@ -0,0 +1,18 @@ +mutation { + storageUpdateFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" + ) { + _id + bucketId + _createdAt + _updatedAt + _permissions + name + signature + mimeType + sizeOriginal + chunksTotal + chunksUploaded + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/create-membership.md b/docs/examples/1.4.x/server-graphql/examples/teams/create-membership.md new file mode 100644 index 0000000000..045a0ae7a8 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/create-membership.md @@ -0,0 +1,20 @@ +mutation { + teamsCreateMembership( + teamId: "[TEAM_ID]", + roles: [], + url: "https://example.com" + ) { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/create.md b/docs/examples/1.4.x/server-graphql/examples/teams/create.md new file mode 100644 index 0000000000..2dd3ca74fb --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/create.md @@ -0,0 +1,15 @@ +mutation { + teamsCreate( + teamId: "[TEAM_ID]", + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + name + total + prefs { + data + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-graphql/examples/teams/delete-membership.md new file mode 100644 index 0000000000..b8a5252fcf --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/delete-membership.md @@ -0,0 +1,8 @@ +mutation { + teamsDeleteMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/delete.md b/docs/examples/1.4.x/server-graphql/examples/teams/delete.md new file mode 100644 index 0000000000..161f8a3454 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/delete.md @@ -0,0 +1,7 @@ +mutation { + teamsDelete( + teamId: "[TEAM_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/get-membership.md b/docs/examples/1.4.x/server-graphql/examples/teams/get-membership.md new file mode 100644 index 0000000000..d28ef798fa --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/get-membership.md @@ -0,0 +1,19 @@ +query { + teamsGetMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]" + ) { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-graphql/examples/teams/get-prefs.md new file mode 100644 index 0000000000..ce6b851e9e --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/get-prefs.md @@ -0,0 +1,7 @@ +query { + teamsGetPrefs( + teamId: "[TEAM_ID]" + ) { + data + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/get.md b/docs/examples/1.4.x/server-graphql/examples/teams/get.md new file mode 100644 index 0000000000..aa83e30e73 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/get.md @@ -0,0 +1,14 @@ +query { + teamsGet( + teamId: "[TEAM_ID]" + ) { + _id + _createdAt + _updatedAt + name + total + prefs { + data + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-graphql/examples/teams/list-memberships.md new file mode 100644 index 0000000000..8ac82c1faf --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/list-memberships.md @@ -0,0 +1,21 @@ +query { + teamsListMemberships( + teamId: "[TEAM_ID]" + ) { + total + memberships { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/list.md b/docs/examples/1.4.x/server-graphql/examples/teams/list.md new file mode 100644 index 0000000000..47117c5627 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/list.md @@ -0,0 +1,15 @@ +query { + teamsList { + total + teams { + _id + _createdAt + _updatedAt + name + total + prefs { + data + } + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-graphql/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..ca6cec12e1 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/update-membership-status.md @@ -0,0 +1,21 @@ +mutation { + teamsUpdateMembershipStatus( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + userId: "[USER_ID]", + secret: "[SECRET]" + ) { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/update-membership.md b/docs/examples/1.4.x/server-graphql/examples/teams/update-membership.md new file mode 100644 index 0000000000..e56e0c46af --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/update-membership.md @@ -0,0 +1,20 @@ +mutation { + teamsUpdateMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + roles: [] + ) { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/update-name.md b/docs/examples/1.4.x/server-graphql/examples/teams/update-name.md new file mode 100644 index 0000000000..88e994b63a --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/update-name.md @@ -0,0 +1,15 @@ +mutation { + teamsUpdateName( + teamId: "[TEAM_ID]", + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + name + total + prefs { + data + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-graphql/examples/teams/update-prefs.md new file mode 100644 index 0000000000..55ed909fe3 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/teams/update-prefs.md @@ -0,0 +1,8 @@ +mutation { + teamsUpdatePrefs( + teamId: "[TEAM_ID]", + prefs: "{}" + ) { + data + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-graphql/examples/users/create-argon2user.md new file mode 100644 index 0000000000..80530225e8 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/create-argon2user.md @@ -0,0 +1,24 @@ +mutation { + usersCreateArgon2User( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-graphql/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..9f1c22448d --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/create-bcrypt-user.md @@ -0,0 +1,24 @@ +mutation { + usersCreateBcryptUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-graphql/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..111a5783d9 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/create-m-d5user.md @@ -0,0 +1,24 @@ +mutation { + usersCreateMD5User( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-graphql/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..b4012cc222 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/create-p-h-pass-user.md @@ -0,0 +1,24 @@ +mutation { + usersCreatePHPassUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-graphql/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..799093d994 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/create-s-h-a-user.md @@ -0,0 +1,24 @@ +mutation { + usersCreateSHAUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-graphql/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..b6d6e5dab9 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,27 @@ +mutation { + usersCreateScryptModifiedUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password", + passwordSalt: "[PASSWORD_SALT]", + passwordSaltSeparator: "[PASSWORD_SALT_SEPARATOR]", + passwordSignerKey: "[PASSWORD_SIGNER_KEY]" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-graphql/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..b817509f5c --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/create-scrypt-user.md @@ -0,0 +1,29 @@ +mutation { + usersCreateScryptUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password", + passwordSalt: "[PASSWORD_SALT]", + passwordCpu: 0, + passwordMemory: 0, + passwordParallel: 0, + passwordLength: 0 + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/create.md b/docs/examples/1.4.x/server-graphql/examples/users/create.md new file mode 100644 index 0000000000..eaf12dafb2 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/create.md @@ -0,0 +1,22 @@ +mutation { + usersCreate( + userId: "[USER_ID]" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/delete-identity.md b/docs/examples/1.4.x/server-graphql/examples/users/delete-identity.md new file mode 100644 index 0000000000..722caa7147 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/delete-identity.md @@ -0,0 +1,7 @@ +mutation { + usersDeleteIdentity( + identityId: "[IDENTITY_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/delete-session.md b/docs/examples/1.4.x/server-graphql/examples/users/delete-session.md new file mode 100644 index 0000000000..72cb167b00 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/delete-session.md @@ -0,0 +1,8 @@ +mutation { + usersDeleteSession( + userId: "[USER_ID]", + sessionId: "[SESSION_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-graphql/examples/users/delete-sessions.md new file mode 100644 index 0000000000..28ed911611 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/delete-sessions.md @@ -0,0 +1,7 @@ +mutation { + usersDeleteSessions( + userId: "[USER_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/delete.md b/docs/examples/1.4.x/server-graphql/examples/users/delete.md new file mode 100644 index 0000000000..39673f1c85 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/delete.md @@ -0,0 +1,7 @@ +mutation { + usersDelete( + userId: "[USER_ID]" + ) { + status + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/get-prefs.md b/docs/examples/1.4.x/server-graphql/examples/users/get-prefs.md new file mode 100644 index 0000000000..e492952676 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/get-prefs.md @@ -0,0 +1,7 @@ +query { + usersGetPrefs( + userId: "[USER_ID]" + ) { + data + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/get.md b/docs/examples/1.4.x/server-graphql/examples/users/get.md new file mode 100644 index 0000000000..52bba40d3a --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/get.md @@ -0,0 +1,22 @@ +query { + usersGet( + userId: "[USER_ID]" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/list-identities.md b/docs/examples/1.4.x/server-graphql/examples/users/list-identities.md new file mode 100644 index 0000000000..c06ad8941e --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/list-identities.md @@ -0,0 +1,17 @@ +query { + usersListIdentities { + total + identities { + _id + _createdAt + _updatedAt + userId + provider + providerUid + providerEmail + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/list-logs.md b/docs/examples/1.4.x/server-graphql/examples/users/list-logs.md new file mode 100644 index 0000000000..d13a8321ed --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/list-logs.md @@ -0,0 +1,30 @@ +query { + usersListLogs( + userId: "[USER_ID]" + ) { + total + logs { + event + userId + userEmail + userName + mode + ip + time + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/list-memberships.md b/docs/examples/1.4.x/server-graphql/examples/users/list-memberships.md new file mode 100644 index 0000000000..33b7a56d02 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/list-memberships.md @@ -0,0 +1,21 @@ +query { + usersListMemberships( + userId: "[USER_ID]" + ) { + total + memberships { + _id + _createdAt + _updatedAt + userId + userName + userEmail + teamId + teamName + invited + joined + confirm + roles + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/list-sessions.md b/docs/examples/1.4.x/server-graphql/examples/users/list-sessions.md new file mode 100644 index 0000000000..d1b608f43d --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/list-sessions.md @@ -0,0 +1,34 @@ +query { + usersListSessions( + userId: "[USER_ID]" + ) { + total + sessions { + _id + _createdAt + userId + expire + provider + providerUid + providerAccessToken + providerAccessTokenExpiry + providerRefreshToken + ip + osCode + osName + osVersion + clientType + clientCode + clientName + clientVersion + clientEngine + clientEngineVersion + deviceName + deviceBrand + deviceModel + countryCode + countryName + current + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/list.md b/docs/examples/1.4.x/server-graphql/examples/users/list.md new file mode 100644 index 0000000000..407e2e4df3 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/list.md @@ -0,0 +1,23 @@ +query { + usersList { + total + users { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-graphql/examples/users/update-email-verification.md new file mode 100644 index 0000000000..e376522e18 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/update-email-verification.md @@ -0,0 +1,23 @@ +mutation { + usersUpdateEmailVerification( + userId: "[USER_ID]", + emailVerification: false + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/update-email.md b/docs/examples/1.4.x/server-graphql/examples/users/update-email.md new file mode 100644 index 0000000000..7a28a129cf --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/update-email.md @@ -0,0 +1,23 @@ +mutation { + usersUpdateEmail( + userId: "[USER_ID]", + email: "email@example.com" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/update-labels.md b/docs/examples/1.4.x/server-graphql/examples/users/update-labels.md new file mode 100644 index 0000000000..82da4b8584 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/update-labels.md @@ -0,0 +1,23 @@ +mutation { + usersUpdateLabels( + userId: "[USER_ID]", + labels: [] + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/update-name.md b/docs/examples/1.4.x/server-graphql/examples/users/update-name.md new file mode 100644 index 0000000000..5007fe46d1 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/update-name.md @@ -0,0 +1,23 @@ +mutation { + usersUpdateName( + userId: "[USER_ID]", + name: "[NAME]" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/update-password.md b/docs/examples/1.4.x/server-graphql/examples/users/update-password.md new file mode 100644 index 0000000000..1e93b1cede --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/update-password.md @@ -0,0 +1,23 @@ +mutation { + usersUpdatePassword( + userId: "[USER_ID]", + password: "" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-graphql/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..7c0c556d6a --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/update-phone-verification.md @@ -0,0 +1,23 @@ +mutation { + usersUpdatePhoneVerification( + userId: "[USER_ID]", + phoneVerification: false + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/update-phone.md b/docs/examples/1.4.x/server-graphql/examples/users/update-phone.md new file mode 100644 index 0000000000..673274faec --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/update-phone.md @@ -0,0 +1,23 @@ +mutation { + usersUpdatePhone( + userId: "[USER_ID]", + number: "+12065550100" + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/update-prefs.md b/docs/examples/1.4.x/server-graphql/examples/users/update-prefs.md new file mode 100644 index 0000000000..06954a8ac5 --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/update-prefs.md @@ -0,0 +1,8 @@ +mutation { + usersUpdatePrefs( + userId: "[USER_ID]", + prefs: "{}" + ) { + data + } +} diff --git a/docs/examples/1.4.x/server-graphql/examples/users/update-status.md b/docs/examples/1.4.x/server-graphql/examples/users/update-status.md new file mode 100644 index 0000000000..050bcbf7af --- /dev/null +++ b/docs/examples/1.4.x/server-graphql/examples/users/update-status.md @@ -0,0 +1,23 @@ +mutation { + usersUpdateStatus( + userId: "[USER_ID]", + status: false + ) { + _id + _createdAt + _updatedAt + name + registration + status + labels + passwordUpdate + email + phone + emailVerification + phoneVerification + prefs { + data + } + accessedAt + } +} diff --git a/docs/examples/1.4.x/server-kotlin/java/account/create-phone-verification.md b/docs/examples/1.4.x/server-kotlin/java/account/create-phone-verification.md new file mode 100644 index 0000000000..013b357f88 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/create-phone-verification.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.createPhoneVerification(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/create-recovery.md b/docs/examples/1.4.x/server-kotlin/java/account/create-recovery.md new file mode 100644 index 0000000000..284efc8107 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/create-recovery.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.createRecovery( + "email@example.com", + "https://example.com" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/create-verification.md b/docs/examples/1.4.x/server-kotlin/java/account/create-verification.md new file mode 100644 index 0000000000..0280b4b15b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/create-verification.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.createVerification( + "https://example.com" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/delete-identity.md b/docs/examples/1.4.x/server-kotlin/java/account/delete-identity.md new file mode 100644 index 0000000000..54bad5a9f0 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/delete-identity.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.deleteIdentity( + "[IDENTITY_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/delete-session.md b/docs/examples/1.4.x/server-kotlin/java/account/delete-session.md new file mode 100644 index 0000000000..2cd069eaa1 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/delete-session.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.deleteSession( + "[SESSION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/delete-sessions.md b/docs/examples/1.4.x/server-kotlin/java/account/delete-sessions.md new file mode 100644 index 0000000000..7a9999d398 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/delete-sessions.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.deleteSessions(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/get-prefs.md b/docs/examples/1.4.x/server-kotlin/java/account/get-prefs.md new file mode 100644 index 0000000000..3f6cd20c9d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/get-prefs.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.getPrefs(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/get-session.md b/docs/examples/1.4.x/server-kotlin/java/account/get-session.md new file mode 100644 index 0000000000..17229e29de --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/get-session.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.getSession( + "[SESSION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/get.md b/docs/examples/1.4.x/server-kotlin/java/account/get.md new file mode 100644 index 0000000000..80a4988af5 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/get.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.get(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/list-identities.md b/docs/examples/1.4.x/server-kotlin/java/account/list-identities.md new file mode 100644 index 0000000000..d6fcb68127 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/list-identities.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.listIdentities( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/list-logs.md b/docs/examples/1.4.x/server-kotlin/java/account/list-logs.md new file mode 100644 index 0000000000..971ac866e1 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/list-logs.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.listLogs( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/list-sessions.md b/docs/examples/1.4.x/server-kotlin/java/account/list-sessions.md new file mode 100644 index 0000000000..9d7e6308e5 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/list-sessions.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.listSessions(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-email.md b/docs/examples/1.4.x/server-kotlin/java/account/update-email.md new file mode 100644 index 0000000000..67ab31ad88 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-email.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updateEmail( + "email@example.com", + "password" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-name.md b/docs/examples/1.4.x/server-kotlin/java/account/update-name.md new file mode 100644 index 0000000000..6900f12174 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-name.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updateName( + "[NAME]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-password.md b/docs/examples/1.4.x/server-kotlin/java/account/update-password.md new file mode 100644 index 0000000000..ace01fcc9a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-password.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updatePassword( + "", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-phone-verification.md b/docs/examples/1.4.x/server-kotlin/java/account/update-phone-verification.md new file mode 100644 index 0000000000..8c3c9756de --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-phone-verification.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updatePhoneVerification( + "[USER_ID]", + "[SECRET]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-phone.md b/docs/examples/1.4.x/server-kotlin/java/account/update-phone.md new file mode 100644 index 0000000000..9365a0f0b9 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-phone.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updatePhone( + "+12065550100", + "password" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-prefs.md b/docs/examples/1.4.x/server-kotlin/java/account/update-prefs.md new file mode 100644 index 0000000000..24a3625834 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-prefs.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updatePrefs( + mapOf( "a" to "b" ) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-recovery.md b/docs/examples/1.4.x/server-kotlin/java/account/update-recovery.md new file mode 100644 index 0000000000..bc3251d160 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-recovery.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updateRecovery( + "[USER_ID]", + "[SECRET]", + "password", + "password" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-session.md b/docs/examples/1.4.x/server-kotlin/java/account/update-session.md new file mode 100644 index 0000000000..62d77e1366 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-session.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updateSession( + "[SESSION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-status.md b/docs/examples/1.4.x/server-kotlin/java/account/update-status.md new file mode 100644 index 0000000000..4af2cf1083 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-status.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updateStatus(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/account/update-verification.md b/docs/examples/1.4.x/server-kotlin/java/account/update-verification.md new file mode 100644 index 0000000000..2190daf1b7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/account/update-verification.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Account; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Account account = new Account(client); + +account.updateVerification( + "[USER_ID]", + "[SECRET]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/avatars/get-browser.md b/docs/examples/1.4.x/server-kotlin/java/avatars/get-browser.md new file mode 100644 index 0000000000..42e8e57ee1 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/avatars/get-browser.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Avatars avatars = new Avatars(client); + +avatars.getBrowser( + "aa", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/avatars/get-credit-card.md b/docs/examples/1.4.x/server-kotlin/java/avatars/get-credit-card.md new file mode 100644 index 0000000000..5e3b32b527 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/avatars/get-credit-card.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Avatars avatars = new Avatars(client); + +avatars.getCreditCard( + "amex", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/avatars/get-favicon.md b/docs/examples/1.4.x/server-kotlin/java/avatars/get-favicon.md new file mode 100644 index 0000000000..109f88f719 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/avatars/get-favicon.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Avatars avatars = new Avatars(client); + +avatars.getFavicon( + "https://example.com" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/avatars/get-flag.md b/docs/examples/1.4.x/server-kotlin/java/avatars/get-flag.md new file mode 100644 index 0000000000..6ad820ae7a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/avatars/get-flag.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Avatars avatars = new Avatars(client); + +avatars.getFlag( + "af", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/avatars/get-image.md b/docs/examples/1.4.x/server-kotlin/java/avatars/get-image.md new file mode 100644 index 0000000000..2680544988 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/avatars/get-image.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Avatars avatars = new Avatars(client); + +avatars.getImage( + "https://example.com", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/avatars/get-initials.md b/docs/examples/1.4.x/server-kotlin/java/avatars/get-initials.md new file mode 100644 index 0000000000..8a86e7a01b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/avatars/get-initials.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Avatars avatars = new Avatars(client); + +avatars.getInitials( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/avatars/get-q-r.md b/docs/examples/1.4.x/server-kotlin/java/avatars/get-q-r.md new file mode 100644 index 0000000000..c57d70a840 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/avatars/get-q-r.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Avatars; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Avatars avatars = new Avatars(client); + +avatars.getQR( + "[TEXT]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..6e79f0a917 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-boolean-attribute.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createBooleanAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-collection.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-collection.md new file mode 100644 index 0000000000..96b5d9b974 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-collection.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createCollection( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[NAME]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..307a8ffb65 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-datetime-attribute.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createDatetimeAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-document.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-document.md new file mode 100644 index 0000000000..029c3f7a25 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-document.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[DOCUMENT_ID]", + mapOf( "a" to "b" ), + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-email-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-email-attribute.md new file mode 100644 index 0000000000..8774c550b7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-email-attribute.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createEmailAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-enum-attribute.md new file mode 100644 index 0000000000..e2cf6a28df --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-enum-attribute.md @@ -0,0 +1,26 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createEnumAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + listOf(), + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-float-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-float-attribute.md new file mode 100644 index 0000000000..0fba6ac073 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-float-attribute.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createFloatAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-index.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-index.md new file mode 100644 index 0000000000..5dbdce895b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-index.md @@ -0,0 +1,26 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createIndex( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + "key", + listOf(), + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-integer-attribute.md new file mode 100644 index 0000000000..5446862fdb --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-integer-attribute.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createIntegerAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-ip-attribute.md new file mode 100644 index 0000000000..fe37da96d5 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-ip-attribute.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createIpAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..0b7e5f999f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-relationship-attribute.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createRelationshipAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[RELATED_COLLECTION_ID]", + "oneToOne", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-string-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-string-attribute.md new file mode 100644 index 0000000000..a9b1916066 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-string-attribute.md @@ -0,0 +1,26 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createStringAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + 1, + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create-url-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/create-url-attribute.md new file mode 100644 index 0000000000..9c504d862b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create-url-attribute.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.createUrlAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/create.md b/docs/examples/1.4.x/server-kotlin/java/databases/create.md new file mode 100644 index 0000000000..a323434059 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/create.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.create( + "[DATABASE_ID]", + "[NAME]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/delete-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/delete-attribute.md new file mode 100644 index 0000000000..68aeecd93b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/delete-attribute.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.deleteAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/delete-collection.md b/docs/examples/1.4.x/server-kotlin/java/databases/delete-collection.md new file mode 100644 index 0000000000..cd328b48a6 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/delete-collection.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.deleteCollection( + "[DATABASE_ID]", + "[COLLECTION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/delete-document.md b/docs/examples/1.4.x/server-kotlin/java/databases/delete-document.md new file mode 100644 index 0000000000..4f4c8495c3 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/delete-document.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.deleteDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[DOCUMENT_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/delete-index.md b/docs/examples/1.4.x/server-kotlin/java/databases/delete-index.md new file mode 100644 index 0000000000..640bd0fc31 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/delete-index.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.deleteIndex( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/delete.md b/docs/examples/1.4.x/server-kotlin/java/databases/delete.md new file mode 100644 index 0000000000..897a450fa4 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/delete.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.delete( + "[DATABASE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/get-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/get-attribute.md new file mode 100644 index 0000000000..79c1d2b2ad --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/get-attribute.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.getAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/get-collection.md b/docs/examples/1.4.x/server-kotlin/java/databases/get-collection.md new file mode 100644 index 0000000000..3ecfa0ca80 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/get-collection.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.getCollection( + "[DATABASE_ID]", + "[COLLECTION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/get-document.md b/docs/examples/1.4.x/server-kotlin/java/databases/get-document.md new file mode 100644 index 0000000000..2061bed202 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/get-document.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.getDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[DOCUMENT_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/get-index.md b/docs/examples/1.4.x/server-kotlin/java/databases/get-index.md new file mode 100644 index 0000000000..2bf036a057 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/get-index.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.getIndex( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/get.md b/docs/examples/1.4.x/server-kotlin/java/databases/get.md new file mode 100644 index 0000000000..066ec4d262 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/get.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.get( + "[DATABASE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/list-attributes.md b/docs/examples/1.4.x/server-kotlin/java/databases/list-attributes.md new file mode 100644 index 0000000000..f42baa02f4 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/list-attributes.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.listAttributes( + "[DATABASE_ID]", + "[COLLECTION_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/list-collections.md b/docs/examples/1.4.x/server-kotlin/java/databases/list-collections.md new file mode 100644 index 0000000000..67c343f38a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/list-collections.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.listCollections( + "[DATABASE_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/list-documents.md b/docs/examples/1.4.x/server-kotlin/java/databases/list-documents.md new file mode 100644 index 0000000000..7a4a1b70b2 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/list-documents.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.listDocuments( + "[DATABASE_ID]", + "[COLLECTION_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/list-indexes.md b/docs/examples/1.4.x/server-kotlin/java/databases/list-indexes.md new file mode 100644 index 0000000000..be50cdd900 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/list-indexes.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.listIndexes( + "[DATABASE_ID]", + "[COLLECTION_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/list.md b/docs/examples/1.4.x/server-kotlin/java/databases/list.md new file mode 100644 index 0000000000..04f81867f0 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/list.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.list( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..97cee2d548 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-boolean-attribute.md @@ -0,0 +1,26 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateBooleanAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + false + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-collection.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-collection.md new file mode 100644 index 0000000000..3f25c5047e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-collection.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateCollection( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[NAME]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..503f2debdf --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-datetime-attribute.md @@ -0,0 +1,26 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateDatetimeAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + "" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-document.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-document.md new file mode 100644 index 0000000000..e9a596d3d4 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-document.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateDocument( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "[DOCUMENT_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-email-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-email-attribute.md new file mode 100644 index 0000000000..39ea153834 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-email-attribute.md @@ -0,0 +1,26 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateEmailAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + "email@example.com" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-enum-attribute.md new file mode 100644 index 0000000000..969ea4eece --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-enum-attribute.md @@ -0,0 +1,27 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateEnumAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + listOf(), + false, + "[DEFAULT]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-float-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-float-attribute.md new file mode 100644 index 0000000000..67d76e425f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-float-attribute.md @@ -0,0 +1,28 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateFloatAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + 0, + 0, + 0 + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-integer-attribute.md new file mode 100644 index 0000000000..b9308dc22b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-integer-attribute.md @@ -0,0 +1,28 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateIntegerAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + 0, + 0, + 0 + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-ip-attribute.md new file mode 100644 index 0000000000..6a936a5f36 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-ip-attribute.md @@ -0,0 +1,26 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateIpAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + "" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..272952b597 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-relationship-attribute.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateRelationshipAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-string-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-string-attribute.md new file mode 100644 index 0000000000..aba0d0e53c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-string-attribute.md @@ -0,0 +1,26 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateStringAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + "[DEFAULT]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update-url-attribute.md b/docs/examples/1.4.x/server-kotlin/java/databases/update-url-attribute.md new file mode 100644 index 0000000000..87ab384929 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update-url-attribute.md @@ -0,0 +1,26 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.updateUrlAttribute( + "[DATABASE_ID]", + "[COLLECTION_ID]", + "", + false, + "https://example.com" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/databases/update.md b/docs/examples/1.4.x/server-kotlin/java/databases/update.md new file mode 100644 index 0000000000..b706df6524 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/databases/update.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Databases databases = new Databases(client); + +databases.update( + "[DATABASE_ID]", + "[NAME]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/create-build.md b/docs/examples/1.4.x/server-kotlin/java/functions/create-build.md new file mode 100644 index 0000000000..10c8d2fc80 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/create-build.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.createBuild( + "[FUNCTION_ID]", + "[DEPLOYMENT_ID]", + "[BUILD_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/create-deployment.md b/docs/examples/1.4.x/server-kotlin/java/functions/create-deployment.md new file mode 100644 index 0000000000..4e6da33482 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/create-deployment.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.models.InputFile; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.createDeployment( + "[FUNCTION_ID]", + InputFile.fromPath("file.png"), + false, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/create-execution.md b/docs/examples/1.4.x/server-kotlin/java/functions/create-execution.md new file mode 100644 index 0000000000..315f57d5cb --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/create-execution.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.createExecution( + "[FUNCTION_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/create-variable.md b/docs/examples/1.4.x/server-kotlin/java/functions/create-variable.md new file mode 100644 index 0000000000..5e9c5a66bd --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/create-variable.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.createVariable( + "[FUNCTION_ID]", + "[KEY]", + "[VALUE]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/create.md b/docs/examples/1.4.x/server-kotlin/java/functions/create.md new file mode 100644 index 0000000000..2386c1bbad --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/create.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.create( + "[FUNCTION_ID]", + "[NAME]", + "node-14.5", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/delete-deployment.md b/docs/examples/1.4.x/server-kotlin/java/functions/delete-deployment.md new file mode 100644 index 0000000000..703dce63aa --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/delete-deployment.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.deleteDeployment( + "[FUNCTION_ID]", + "[DEPLOYMENT_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/delete-variable.md b/docs/examples/1.4.x/server-kotlin/java/functions/delete-variable.md new file mode 100644 index 0000000000..d36615092d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/delete-variable.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.deleteVariable( + "[FUNCTION_ID]", + "[VARIABLE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/delete.md b/docs/examples/1.4.x/server-kotlin/java/functions/delete.md new file mode 100644 index 0000000000..8f39896411 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/delete.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.delete( + "[FUNCTION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/download-deployment.md b/docs/examples/1.4.x/server-kotlin/java/functions/download-deployment.md new file mode 100644 index 0000000000..91898dc07a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/download-deployment.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.downloadDeployment( + "[FUNCTION_ID]", + "[DEPLOYMENT_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/get-deployment.md b/docs/examples/1.4.x/server-kotlin/java/functions/get-deployment.md new file mode 100644 index 0000000000..5b539d2801 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/get-deployment.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.getDeployment( + "[FUNCTION_ID]", + "[DEPLOYMENT_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/get-execution.md b/docs/examples/1.4.x/server-kotlin/java/functions/get-execution.md new file mode 100644 index 0000000000..b1ff9485e8 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/get-execution.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.getExecution( + "[FUNCTION_ID]", + "[EXECUTION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/get-variable.md b/docs/examples/1.4.x/server-kotlin/java/functions/get-variable.md new file mode 100644 index 0000000000..2be25a5c73 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/get-variable.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.getVariable( + "[FUNCTION_ID]", + "[VARIABLE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/get.md b/docs/examples/1.4.x/server-kotlin/java/functions/get.md new file mode 100644 index 0000000000..8ad5ea3522 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/get.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.get( + "[FUNCTION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/list-deployments.md b/docs/examples/1.4.x/server-kotlin/java/functions/list-deployments.md new file mode 100644 index 0000000000..61f48c88c3 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/list-deployments.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.listDeployments( + "[FUNCTION_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/list-executions.md b/docs/examples/1.4.x/server-kotlin/java/functions/list-executions.md new file mode 100644 index 0000000000..392e9c82c5 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/list-executions.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.listExecutions( + "[FUNCTION_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/list-runtimes.md b/docs/examples/1.4.x/server-kotlin/java/functions/list-runtimes.md new file mode 100644 index 0000000000..46d0446310 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/list-runtimes.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.listRuntimes(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/list-variables.md b/docs/examples/1.4.x/server-kotlin/java/functions/list-variables.md new file mode 100644 index 0000000000..4fa47e8c57 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/list-variables.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.listVariables( + "[FUNCTION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/list.md b/docs/examples/1.4.x/server-kotlin/java/functions/list.md new file mode 100644 index 0000000000..4224cf52b7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/list.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.list( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/update-deployment.md b/docs/examples/1.4.x/server-kotlin/java/functions/update-deployment.md new file mode 100644 index 0000000000..2af0637379 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/update-deployment.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.updateDeployment( + "[FUNCTION_ID]", + "[DEPLOYMENT_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/update-variable.md b/docs/examples/1.4.x/server-kotlin/java/functions/update-variable.md new file mode 100644 index 0000000000..f30bbf8e4e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/update-variable.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.updateVariable( + "[FUNCTION_ID]", + "[VARIABLE_ID]", + "[KEY]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/functions/update.md b/docs/examples/1.4.x/server-kotlin/java/functions/update.md new file mode 100644 index 0000000000..355aa4e326 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/functions/update.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Functions; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Functions functions = new Functions(client); + +functions.update( + "[FUNCTION_ID]", + "[NAME]", + "node-14.5", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/graphql/mutation.md b/docs/examples/1.4.x/server-kotlin/java/graphql/mutation.md new file mode 100644 index 0000000000..d689c62e60 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/graphql/mutation.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Graphql; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Graphql graphql = new Graphql(client); + +graphql.mutation( + mapOf( "a" to "b" ) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/graphql/query.md b/docs/examples/1.4.x/server-kotlin/java/graphql/query.md new file mode 100644 index 0000000000..e4b8693b4f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/graphql/query.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Graphql; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Graphql graphql = new Graphql(client); + +graphql.query( + mapOf( "a" to "b" ) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-antivirus.md b/docs/examples/1.4.x/server-kotlin/java/health/get-antivirus.md new file mode 100644 index 0000000000..334563fd1c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-antivirus.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getAntivirus(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-cache.md b/docs/examples/1.4.x/server-kotlin/java/health/get-cache.md new file mode 100644 index 0000000000..9a2981253a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-cache.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getCache(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-d-b.md b/docs/examples/1.4.x/server-kotlin/java/health/get-d-b.md new file mode 100644 index 0000000000..22a5a6b5bb --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-d-b.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getDB(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-pub-sub.md b/docs/examples/1.4.x/server-kotlin/java/health/get-pub-sub.md new file mode 100644 index 0000000000..ba94519084 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-pub-sub.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getPubSub(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-queue-certificates.md b/docs/examples/1.4.x/server-kotlin/java/health/get-queue-certificates.md new file mode 100644 index 0000000000..a0a3a22f8a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-queue-certificates.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getQueueCertificates(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-queue-functions.md b/docs/examples/1.4.x/server-kotlin/java/health/get-queue-functions.md new file mode 100644 index 0000000000..54b425f63c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-queue-functions.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getQueueFunctions(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-queue-logs.md b/docs/examples/1.4.x/server-kotlin/java/health/get-queue-logs.md new file mode 100644 index 0000000000..371c98f06d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-queue-logs.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getQueueLogs(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-kotlin/java/health/get-queue-webhooks.md new file mode 100644 index 0000000000..cbd6919d72 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-queue-webhooks.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getQueueWebhooks(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-queue.md b/docs/examples/1.4.x/server-kotlin/java/health/get-queue.md new file mode 100644 index 0000000000..90b7eb35ad --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-queue.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getQueue(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-storage-local.md b/docs/examples/1.4.x/server-kotlin/java/health/get-storage-local.md new file mode 100644 index 0000000000..a57f34520d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-storage-local.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getStorageLocal(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get-time.md b/docs/examples/1.4.x/server-kotlin/java/health/get-time.md new file mode 100644 index 0000000000..36b276b4d7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get-time.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.getTime(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/health/get.md b/docs/examples/1.4.x/server-kotlin/java/health/get.md new file mode 100644 index 0000000000..59badb0543 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/health/get.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Health; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Health health = new Health(client); + +health.get(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/locale/get.md b/docs/examples/1.4.x/server-kotlin/java/locale/get.md new file mode 100644 index 0000000000..4fb6be9416 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/locale/get.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Locale locale = new Locale(client); + +locale.get(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/locale/list-codes.md b/docs/examples/1.4.x/server-kotlin/java/locale/list-codes.md new file mode 100644 index 0000000000..a3feffe066 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/locale/list-codes.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Locale locale = new Locale(client); + +locale.listCodes(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/locale/list-continents.md b/docs/examples/1.4.x/server-kotlin/java/locale/list-continents.md new file mode 100644 index 0000000000..661fcc3583 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/locale/list-continents.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Locale locale = new Locale(client); + +locale.listContinents(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-kotlin/java/locale/list-countries-e-u.md new file mode 100644 index 0000000000..6164ca02d2 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/locale/list-countries-e-u.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Locale locale = new Locale(client); + +locale.listCountriesEU(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/locale/list-countries-phones.md b/docs/examples/1.4.x/server-kotlin/java/locale/list-countries-phones.md new file mode 100644 index 0000000000..2cb41c19f2 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/locale/list-countries-phones.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Locale locale = new Locale(client); + +locale.listCountriesPhones(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/locale/list-countries.md b/docs/examples/1.4.x/server-kotlin/java/locale/list-countries.md new file mode 100644 index 0000000000..74d3b5d402 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/locale/list-countries.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Locale locale = new Locale(client); + +locale.listCountries(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/locale/list-currencies.md b/docs/examples/1.4.x/server-kotlin/java/locale/list-currencies.md new file mode 100644 index 0000000000..54a0e4de40 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/locale/list-currencies.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Locale locale = new Locale(client); + +locale.listCurrencies(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/locale/list-languages.md b/docs/examples/1.4.x/server-kotlin/java/locale/list-languages.md new file mode 100644 index 0000000000..54976c5c08 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/locale/list-languages.md @@ -0,0 +1,19 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Locale; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Locale locale = new Locale(client); + +locale.listLanguages(new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); +})); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/create-bucket.md b/docs/examples/1.4.x/server-kotlin/java/storage/create-bucket.md new file mode 100644 index 0000000000..c9ebc9178c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/create-bucket.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.createBucket( + "[BUCKET_ID]", + "[NAME]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/create-file.md b/docs/examples/1.4.x/server-kotlin/java/storage/create-file.md new file mode 100644 index 0000000000..c83557bf28 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/create-file.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.models.InputFile; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.createFile( + "[BUCKET_ID]", + "[FILE_ID]", + InputFile.fromPath("file.png"), + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/delete-bucket.md b/docs/examples/1.4.x/server-kotlin/java/storage/delete-bucket.md new file mode 100644 index 0000000000..f26e9ee5a1 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/delete-bucket.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.deleteBucket( + "[BUCKET_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/delete-file.md b/docs/examples/1.4.x/server-kotlin/java/storage/delete-file.md new file mode 100644 index 0000000000..eb00b9706c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/delete-file.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.deleteFile( + "[BUCKET_ID]", + "[FILE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/get-bucket.md b/docs/examples/1.4.x/server-kotlin/java/storage/get-bucket.md new file mode 100644 index 0000000000..2157dd7424 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/get-bucket.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.getBucket( + "[BUCKET_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/get-file-download.md b/docs/examples/1.4.x/server-kotlin/java/storage/get-file-download.md new file mode 100644 index 0000000000..8eef7e347e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/get-file-download.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.getFileDownload( + "[BUCKET_ID]", + "[FILE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/get-file-preview.md b/docs/examples/1.4.x/server-kotlin/java/storage/get-file-preview.md new file mode 100644 index 0000000000..275e803000 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/get-file-preview.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.getFilePreview( + "[BUCKET_ID]", + "[FILE_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/get-file-view.md b/docs/examples/1.4.x/server-kotlin/java/storage/get-file-view.md new file mode 100644 index 0000000000..adc0407c35 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/get-file-view.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.getFileView( + "[BUCKET_ID]", + "[FILE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/get-file.md b/docs/examples/1.4.x/server-kotlin/java/storage/get-file.md new file mode 100644 index 0000000000..4cb6fe6db3 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/get-file.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.getFile( + "[BUCKET_ID]", + "[FILE_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/list-buckets.md b/docs/examples/1.4.x/server-kotlin/java/storage/list-buckets.md new file mode 100644 index 0000000000..49c29cad2d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/list-buckets.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.listBuckets( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/list-files.md b/docs/examples/1.4.x/server-kotlin/java/storage/list-files.md new file mode 100644 index 0000000000..59719e530f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/list-files.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.listFiles( + "[BUCKET_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/update-bucket.md b/docs/examples/1.4.x/server-kotlin/java/storage/update-bucket.md new file mode 100644 index 0000000000..05483ea725 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/update-bucket.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.updateBucket( + "[BUCKET_ID]", + "[NAME]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/storage/update-file.md b/docs/examples/1.4.x/server-kotlin/java/storage/update-file.md new file mode 100644 index 0000000000..05385c2b88 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/storage/update-file.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Storage; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Storage storage = new Storage(client); + +storage.updateFile( + "[BUCKET_ID]", + "[FILE_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/create-membership.md b/docs/examples/1.4.x/server-kotlin/java/teams/create-membership.md new file mode 100644 index 0000000000..0ad2dd1bf0 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/create-membership.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.createMembership( + "[TEAM_ID]", + listOf(), + "https://example.com", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/create.md b/docs/examples/1.4.x/server-kotlin/java/teams/create.md new file mode 100644 index 0000000000..4f3be33609 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/create.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.create( + "[TEAM_ID]", + "[NAME]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/delete-membership.md b/docs/examples/1.4.x/server-kotlin/java/teams/delete-membership.md new file mode 100644 index 0000000000..e82ab293be --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/delete-membership.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.deleteMembership( + "[TEAM_ID]", + "[MEMBERSHIP_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/delete.md b/docs/examples/1.4.x/server-kotlin/java/teams/delete.md new file mode 100644 index 0000000000..fa805ebd4d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/delete.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.delete( + "[TEAM_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/get-membership.md b/docs/examples/1.4.x/server-kotlin/java/teams/get-membership.md new file mode 100644 index 0000000000..fc00d43873 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/get-membership.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.getMembership( + "[TEAM_ID]", + "[MEMBERSHIP_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/get-prefs.md b/docs/examples/1.4.x/server-kotlin/java/teams/get-prefs.md new file mode 100644 index 0000000000..b14dfc94d3 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/get-prefs.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Teams teams = new Teams(client); + +teams.getPrefs( + "[TEAM_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/get.md b/docs/examples/1.4.x/server-kotlin/java/teams/get.md new file mode 100644 index 0000000000..6be034b418 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/get.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.get( + "[TEAM_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/list-memberships.md b/docs/examples/1.4.x/server-kotlin/java/teams/list-memberships.md new file mode 100644 index 0000000000..0b9055f816 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/list-memberships.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.listMemberships( + "[TEAM_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/list.md b/docs/examples/1.4.x/server-kotlin/java/teams/list.md new file mode 100644 index 0000000000..22a9d51d5f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/list.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.list( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/update-membership-status.md b/docs/examples/1.4.x/server-kotlin/java/teams/update-membership-status.md new file mode 100644 index 0000000000..64e69663d4 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/update-membership-status.md @@ -0,0 +1,25 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Teams teams = new Teams(client); + +teams.updateMembershipStatus( + "[TEAM_ID]", + "[MEMBERSHIP_ID]", + "[USER_ID]", + "[SECRET]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/update-membership.md b/docs/examples/1.4.x/server-kotlin/java/teams/update-membership.md new file mode 100644 index 0000000000..e1fd4325ee --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/update-membership.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.updateMembership( + "[TEAM_ID]", + "[MEMBERSHIP_ID]", + listOf() + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/update-name.md b/docs/examples/1.4.x/server-kotlin/java/teams/update-name.md new file mode 100644 index 0000000000..3d95ccb9d2 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/update-name.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Teams teams = new Teams(client); + +teams.updateName( + "[TEAM_ID]", + "[NAME]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/teams/update-prefs.md b/docs/examples/1.4.x/server-kotlin/java/teams/update-prefs.md new file mode 100644 index 0000000000..674bc6424d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/teams/update-prefs.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Teams; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token + +Teams teams = new Teams(client); + +teams.updatePrefs( + "[TEAM_ID]", + mapOf( "a" to "b" ) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/create-argon2user.md b/docs/examples/1.4.x/server-kotlin/java/users/create-argon2user.md new file mode 100644 index 0000000000..47ac52c086 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/create-argon2user.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.createArgon2User( + "[USER_ID]", + "email@example.com", + "password", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-kotlin/java/users/create-bcrypt-user.md new file mode 100644 index 0000000000..91989dff0f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/create-bcrypt-user.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.createBcryptUser( + "[USER_ID]", + "email@example.com", + "password", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/create-m-d5user.md b/docs/examples/1.4.x/server-kotlin/java/users/create-m-d5user.md new file mode 100644 index 0000000000..35de18d1a3 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/create-m-d5user.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.createMD5User( + "[USER_ID]", + "email@example.com", + "password", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-kotlin/java/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..7501f02f2f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/create-p-h-pass-user.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.createPHPassUser( + "[USER_ID]", + "email@example.com", + "password", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-kotlin/java/users/create-s-h-a-user.md new file mode 100644 index 0000000000..ae26de5543 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/create-s-h-a-user.md @@ -0,0 +1,24 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.createSHAUser( + "[USER_ID]", + "email@example.com", + "password", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-kotlin/java/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..da0936a01b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/create-scrypt-modified-user.md @@ -0,0 +1,27 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.createScryptModifiedUser( + "[USER_ID]", + "email@example.com", + "password", + "[PASSWORD_SALT]", + "[PASSWORD_SALT_SEPARATOR]", + "[PASSWORD_SIGNER_KEY]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/create-scrypt-user.md b/docs/examples/1.4.x/server-kotlin/java/users/create-scrypt-user.md new file mode 100644 index 0000000000..9b48e06fbd --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/create-scrypt-user.md @@ -0,0 +1,29 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.createScryptUser( + "[USER_ID]", + "email@example.com", + "password", + "[PASSWORD_SALT]", + 0, + 0, + 0, + 0, + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/create.md b/docs/examples/1.4.x/server-kotlin/java/users/create.md new file mode 100644 index 0000000000..97aad15302 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/create.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.create( + "[USER_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/delete-identity.md b/docs/examples/1.4.x/server-kotlin/java/users/delete-identity.md new file mode 100644 index 0000000000..cd165a6dc0 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/delete-identity.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.deleteIdentity( + "[IDENTITY_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/delete-session.md b/docs/examples/1.4.x/server-kotlin/java/users/delete-session.md new file mode 100644 index 0000000000..8415328406 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/delete-session.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.deleteSession( + "[USER_ID]", + "[SESSION_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/delete-sessions.md b/docs/examples/1.4.x/server-kotlin/java/users/delete-sessions.md new file mode 100644 index 0000000000..9a2284c493 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/delete-sessions.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.deleteSessions( + "[USER_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/delete.md b/docs/examples/1.4.x/server-kotlin/java/users/delete.md new file mode 100644 index 0000000000..893a4d3794 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/delete.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.delete( + "[USER_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/get-prefs.md b/docs/examples/1.4.x/server-kotlin/java/users/get-prefs.md new file mode 100644 index 0000000000..664843e32c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/get-prefs.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.getPrefs( + "[USER_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/get.md b/docs/examples/1.4.x/server-kotlin/java/users/get.md new file mode 100644 index 0000000000..1be96aee11 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/get.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.get( + "[USER_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/list-identities.md b/docs/examples/1.4.x/server-kotlin/java/users/list-identities.md new file mode 100644 index 0000000000..011f3a6ca2 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/list-identities.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.listIdentities( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/list-logs.md b/docs/examples/1.4.x/server-kotlin/java/users/list-logs.md new file mode 100644 index 0000000000..08ace35a19 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/list-logs.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.listLogs( + "[USER_ID]", + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/list-memberships.md b/docs/examples/1.4.x/server-kotlin/java/users/list-memberships.md new file mode 100644 index 0000000000..503dbcb10a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/list-memberships.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.listMemberships( + "[USER_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/list-sessions.md b/docs/examples/1.4.x/server-kotlin/java/users/list-sessions.md new file mode 100644 index 0000000000..efe091fe74 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/list-sessions.md @@ -0,0 +1,22 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.listSessions( + "[USER_ID]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/list.md b/docs/examples/1.4.x/server-kotlin/java/users/list.md new file mode 100644 index 0000000000..d591bce79e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/list.md @@ -0,0 +1,21 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.list( + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/update-email-verification.md b/docs/examples/1.4.x/server-kotlin/java/users/update-email-verification.md new file mode 100644 index 0000000000..3d6d205bce --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/update-email-verification.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.updateEmailVerification( + "[USER_ID]", + false + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/update-email.md b/docs/examples/1.4.x/server-kotlin/java/users/update-email.md new file mode 100644 index 0000000000..d0e9b17c1d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/update-email.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.updateEmail( + "[USER_ID]", + "email@example.com" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/update-labels.md b/docs/examples/1.4.x/server-kotlin/java/users/update-labels.md new file mode 100644 index 0000000000..e0c7bdc5b8 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/update-labels.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.updateLabels( + "[USER_ID]", + listOf() + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/update-name.md b/docs/examples/1.4.x/server-kotlin/java/users/update-name.md new file mode 100644 index 0000000000..e16f539bdc --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/update-name.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.updateName( + "[USER_ID]", + "[NAME]" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/update-password.md b/docs/examples/1.4.x/server-kotlin/java/users/update-password.md new file mode 100644 index 0000000000..c94e6dd77b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/update-password.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.updatePassword( + "[USER_ID]", + "" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/update-phone-verification.md b/docs/examples/1.4.x/server-kotlin/java/users/update-phone-verification.md new file mode 100644 index 0000000000..8c9a26d609 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/update-phone-verification.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.updatePhoneVerification( + "[USER_ID]", + false + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/update-phone.md b/docs/examples/1.4.x/server-kotlin/java/users/update-phone.md new file mode 100644 index 0000000000..4a2accb793 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/update-phone.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.updatePhone( + "[USER_ID]", + "+12065550100" + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/update-prefs.md b/docs/examples/1.4.x/server-kotlin/java/users/update-prefs.md new file mode 100644 index 0000000000..b12a5d8e4f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/update-prefs.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.updatePrefs( + "[USER_ID]", + mapOf( "a" to "b" ) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/java/users/update-status.md b/docs/examples/1.4.x/server-kotlin/java/users/update-status.md new file mode 100644 index 0000000000..012142cad7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/java/users/update-status.md @@ -0,0 +1,23 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Users; + +Client client = new Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key + +Users users = new Users(client); + +users.updateStatus( + "[USER_ID]", + false + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/create-phone-verification.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/create-phone-verification.md new file mode 100644 index 0000000000..e18d4ce13b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/create-phone-verification.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.createPhoneVerification() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/create-recovery.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/create-recovery.md new file mode 100644 index 0000000000..a219cb8196 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/create-recovery.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.createRecovery( + email = "email@example.com", + url = "https://example.com" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/create-verification.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/create-verification.md new file mode 100644 index 0000000000..33846f1dba --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/create-verification.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.createVerification( + url = "https://example.com" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/delete-identity.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/delete-identity.md new file mode 100644 index 0000000000..c21ccdab4a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/delete-identity.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.deleteIdentity( + identityId = "[IDENTITY_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/delete-session.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/delete-session.md new file mode 100644 index 0000000000..60aa4f2604 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/delete-session.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.deleteSession( + sessionId = "[SESSION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/delete-sessions.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/delete-sessions.md new file mode 100644 index 0000000000..a16622a526 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/delete-sessions.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.deleteSessions() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/get-prefs.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/get-prefs.md new file mode 100644 index 0000000000..dbbba1d98f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/get-prefs.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.getPrefs() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/get-session.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/get-session.md new file mode 100644 index 0000000000..07861109b6 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/get-session.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.getSession( + sessionId = "[SESSION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/get.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/get.md new file mode 100644 index 0000000000..1fb002ae24 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/get.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.get() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/list-identities.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/list-identities.md new file mode 100644 index 0000000000..c300e28f7d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/list-identities.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.listIdentities( +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/list-logs.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/list-logs.md new file mode 100644 index 0000000000..daddd75843 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/list-logs.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.listLogs( +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/list-sessions.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/list-sessions.md new file mode 100644 index 0000000000..132a5da23b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/list-sessions.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.listSessions() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-email.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-email.md new file mode 100644 index 0000000000..1127bbc2b2 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-email.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updateEmail( + email = "email@example.com", + password = "password" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-name.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-name.md new file mode 100644 index 0000000000..3de89a503e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-name.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updateName( + name = "[NAME]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-password.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-password.md new file mode 100644 index 0000000000..df92d9e928 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-password.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updatePassword( + password = "", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-phone-verification.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-phone-verification.md new file mode 100644 index 0000000000..0ed51d30c2 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-phone-verification.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updatePhoneVerification( + userId = "[USER_ID]", + secret = "[SECRET]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-phone.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-phone.md new file mode 100644 index 0000000000..9c823bb6ac --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-phone.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updatePhone( + phone = "+12065550100", + password = "password" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-prefs.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-prefs.md new file mode 100644 index 0000000000..6226269a1f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-prefs.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updatePrefs( + prefs = mapOf( "a" to "b" ) +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-recovery.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-recovery.md new file mode 100644 index 0000000000..1b676c1ad5 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-recovery.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updateRecovery( + userId = "[USER_ID]", + secret = "[SECRET]", + password = "password", + passwordAgain = "password" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-session.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-session.md new file mode 100644 index 0000000000..bd3d28e3b8 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-session.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updateSession( + sessionId = "[SESSION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-status.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-status.md new file mode 100644 index 0000000000..3ed0627906 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-status.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updateStatus() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/account/update-verification.md b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-verification.md new file mode 100644 index 0000000000..e73e555c60 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/account/update-verification.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Account + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val account = Account(client) + +val response = account.updateVerification( + userId = "[USER_ID]", + secret = "[SECRET]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-browser.md b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-browser.md new file mode 100644 index 0000000000..e9f6eb2919 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-browser.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val avatars = Avatars(client) + +val result = avatars.getBrowser( + code = "aa", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-credit-card.md b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-credit-card.md new file mode 100644 index 0000000000..c3413ac644 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-credit-card.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val avatars = Avatars(client) + +val result = avatars.getCreditCard( + code = "amex", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-favicon.md b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-favicon.md new file mode 100644 index 0000000000..cd1ea0c7b3 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-favicon.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val avatars = Avatars(client) + +val result = avatars.getFavicon( + url = "https://example.com" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-flag.md b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-flag.md new file mode 100644 index 0000000000..a81c59ae60 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-flag.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val avatars = Avatars(client) + +val result = avatars.getFlag( + code = "af", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-image.md b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-image.md new file mode 100644 index 0000000000..09cacde6f8 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-image.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val avatars = Avatars(client) + +val result = avatars.getImage( + url = "https://example.com", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-initials.md b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-initials.md new file mode 100644 index 0000000000..ba46fb0d29 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-initials.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val avatars = Avatars(client) + +val result = avatars.getInitials( +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-q-r.md b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-q-r.md new file mode 100644 index 0000000000..c43aabcfe3 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/avatars/get-q-r.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Avatars + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val avatars = Avatars(client) + +val result = avatars.getQR( + text = "[TEXT]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..22de12384d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-boolean-attribute.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createBooleanAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-collection.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-collection.md new file mode 100644 index 0000000000..9ba70cf2fe --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-collection.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createCollection( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + name = "[NAME]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..d410244ec8 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-datetime-attribute.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createDatetimeAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-document.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-document.md new file mode 100644 index 0000000000..95e5977b12 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-document.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = "[DOCUMENT_ID]", + data = mapOf( "a" to "b" ), +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-email-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-email-attribute.md new file mode 100644 index 0000000000..292f31f525 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-email-attribute.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createEmailAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-enum-attribute.md new file mode 100644 index 0000000000..99008a479b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-enum-attribute.md @@ -0,0 +1,17 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createEnumAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + elements = listOf(), + required = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-float-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-float-attribute.md new file mode 100644 index 0000000000..6814962502 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-float-attribute.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createFloatAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-index.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-index.md new file mode 100644 index 0000000000..42b3dbe7e1 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-index.md @@ -0,0 +1,17 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createIndex( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + type = "key", + attributes = listOf(), +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-integer-attribute.md new file mode 100644 index 0000000000..57b2ff66a7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-integer-attribute.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createIntegerAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-ip-attribute.md new file mode 100644 index 0000000000..f941b82c9e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-ip-attribute.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createIpAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..22ebc4a5c7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-relationship-attribute.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createRelationshipAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + relatedCollectionId = "[RELATED_COLLECTION_ID]", + type = "oneToOne", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-string-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-string-attribute.md new file mode 100644 index 0000000000..c5d3d52853 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-string-attribute.md @@ -0,0 +1,17 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createStringAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + size = 1, + required = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-url-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-url-attribute.md new file mode 100644 index 0000000000..8cd0731da1 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create-url-attribute.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.createUrlAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/create.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create.md new file mode 100644 index 0000000000..d7d462a3ce --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/create.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.create( + databaseId = "[DATABASE_ID]", + name = "[NAME]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-attribute.md new file mode 100644 index 0000000000..fef7a45cc4 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-attribute.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.deleteAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-collection.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-collection.md new file mode 100644 index 0000000000..676359331a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-collection.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.deleteCollection( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-document.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-document.md new file mode 100644 index 0000000000..2bf047fe4e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-document.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.deleteDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = "[DOCUMENT_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-index.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-index.md new file mode 100644 index 0000000000..59bd149224 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete-index.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.deleteIndex( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete.md new file mode 100644 index 0000000000..f927901f09 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/delete.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.delete( + databaseId = "[DATABASE_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-attribute.md new file mode 100644 index 0000000000..4bba2dfa16 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-attribute.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.getAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-collection.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-collection.md new file mode 100644 index 0000000000..76ff9a1962 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-collection.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.getCollection( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-document.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-document.md new file mode 100644 index 0000000000..8bacaa57c2 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-document.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.getDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = "[DOCUMENT_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-index.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-index.md new file mode 100644 index 0000000000..2d588dee73 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get-index.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.getIndex( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/get.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get.md new file mode 100644 index 0000000000..5584d4dd87 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/get.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.get( + databaseId = "[DATABASE_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-attributes.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-attributes.md new file mode 100644 index 0000000000..4057571393 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-attributes.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.listAttributes( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-collections.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-collections.md new file mode 100644 index 0000000000..f563c431a7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-collections.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.listCollections( + databaseId = "[DATABASE_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-documents.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-documents.md new file mode 100644 index 0000000000..c081013fa0 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-documents.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.listDocuments( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-indexes.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-indexes.md new file mode 100644 index 0000000000..431d7acbff --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list-indexes.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.listIndexes( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/list.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list.md new file mode 100644 index 0000000000..6ffece0bd5 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/list.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.list( +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..b74ad79547 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-boolean-attribute.md @@ -0,0 +1,17 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateBooleanAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, + default = false +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-collection.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-collection.md new file mode 100644 index 0000000000..f6ccffef9d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-collection.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateCollection( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + name = "[NAME]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..013e437db5 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-datetime-attribute.md @@ -0,0 +1,17 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateDatetimeAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, + default = "" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-document.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-document.md new file mode 100644 index 0000000000..10ff4c4b4c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-document.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateDocument( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + documentId = "[DOCUMENT_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-email-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-email-attribute.md new file mode 100644 index 0000000000..39ca4939ce --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-email-attribute.md @@ -0,0 +1,17 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateEmailAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, + default = "email@example.com" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-enum-attribute.md new file mode 100644 index 0000000000..ece9f22c76 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-enum-attribute.md @@ -0,0 +1,18 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateEnumAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + elements = listOf(), + required = false, + default = "[DEFAULT]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-float-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-float-attribute.md new file mode 100644 index 0000000000..ed9ec055e8 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-float-attribute.md @@ -0,0 +1,19 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateFloatAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, + min = 0, + max = 0, + default = 0 +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-integer-attribute.md new file mode 100644 index 0000000000..e881b01fa6 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-integer-attribute.md @@ -0,0 +1,19 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateIntegerAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, + min = 0, + max = 0, + default = 0 +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-ip-attribute.md new file mode 100644 index 0000000000..5ebe893ed5 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-ip-attribute.md @@ -0,0 +1,17 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateIpAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, + default = "" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..9c0ffecae6 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-relationship-attribute.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateRelationshipAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-string-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-string-attribute.md new file mode 100644 index 0000000000..c8db170954 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-string-attribute.md @@ -0,0 +1,17 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateStringAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, + default = "[DEFAULT]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-url-attribute.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-url-attribute.md new file mode 100644 index 0000000000..71d9bde848 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update-url-attribute.md @@ -0,0 +1,17 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.updateUrlAttribute( + databaseId = "[DATABASE_ID]", + collectionId = "[COLLECTION_ID]", + key = "", + required = false, + default = "https://example.com" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/databases/update.md b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update.md new file mode 100644 index 0000000000..3a4c608942 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/databases/update.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val databases = Databases(client) + +val response = databases.update( + databaseId = "[DATABASE_ID]", + name = "[NAME]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-build.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-build.md new file mode 100644 index 0000000000..62f9d1addd --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-build.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.createBuild( + functionId = "[FUNCTION_ID]", + deploymentId = "[DEPLOYMENT_ID]", + buildId = "[BUILD_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-deployment.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-deployment.md new file mode 100644 index 0000000000..28b89a69f7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-deployment.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.models.InputFile +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.createDeployment( + functionId = "[FUNCTION_ID]", + code = InputFile.fromPath("file.png"), + activate = false, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-execution.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-execution.md new file mode 100644 index 0000000000..62bce1fde0 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-execution.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.createExecution( + functionId = "[FUNCTION_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-variable.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-variable.md new file mode 100644 index 0000000000..6b23614d11 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create-variable.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.createVariable( + functionId = "[FUNCTION_ID]", + key = "[KEY]", + value = "[VALUE]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/create.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create.md new file mode 100644 index 0000000000..fa10f995ed --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/create.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.create( + functionId = "[FUNCTION_ID]", + name = "[NAME]", + runtime = "node-14.5", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/delete-deployment.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/delete-deployment.md new file mode 100644 index 0000000000..5187ba4419 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/delete-deployment.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.deleteDeployment( + functionId = "[FUNCTION_ID]", + deploymentId = "[DEPLOYMENT_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/delete-variable.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/delete-variable.md new file mode 100644 index 0000000000..f0fe4a3d86 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/delete-variable.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.deleteVariable( + functionId = "[FUNCTION_ID]", + variableId = "[VARIABLE_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/delete.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/delete.md new file mode 100644 index 0000000000..f12095b5a8 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/delete.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.delete( + functionId = "[FUNCTION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/download-deployment.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/download-deployment.md new file mode 100644 index 0000000000..2388e829c9 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/download-deployment.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val result = functions.downloadDeployment( + functionId = "[FUNCTION_ID]", + deploymentId = "[DEPLOYMENT_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/get-deployment.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/get-deployment.md new file mode 100644 index 0000000000..4653e61f0e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/get-deployment.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.getDeployment( + functionId = "[FUNCTION_ID]", + deploymentId = "[DEPLOYMENT_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/get-execution.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/get-execution.md new file mode 100644 index 0000000000..929a003a18 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/get-execution.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.getExecution( + functionId = "[FUNCTION_ID]", + executionId = "[EXECUTION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/get-variable.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/get-variable.md new file mode 100644 index 0000000000..ce42276921 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/get-variable.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.getVariable( + functionId = "[FUNCTION_ID]", + variableId = "[VARIABLE_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/get.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/get.md new file mode 100644 index 0000000000..9261ab897a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/get.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.get( + functionId = "[FUNCTION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-deployments.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-deployments.md new file mode 100644 index 0000000000..3ec2c810ee --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-deployments.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.listDeployments( + functionId = "[FUNCTION_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-executions.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-executions.md new file mode 100644 index 0000000000..5378c79dbc --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-executions.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.listExecutions( + functionId = "[FUNCTION_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-runtimes.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-runtimes.md new file mode 100644 index 0000000000..0e777cd1fe --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-runtimes.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.listRuntimes() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-variables.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-variables.md new file mode 100644 index 0000000000..10e74534f4 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list-variables.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.listVariables( + functionId = "[FUNCTION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/list.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list.md new file mode 100644 index 0000000000..a5f4f0d325 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/list.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.list( +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/update-deployment.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/update-deployment.md new file mode 100644 index 0000000000..14b147384f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/update-deployment.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.updateDeployment( + functionId = "[FUNCTION_ID]", + deploymentId = "[DEPLOYMENT_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/update-variable.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/update-variable.md new file mode 100644 index 0000000000..1e0f3bbe5f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/update-variable.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.updateVariable( + functionId = "[FUNCTION_ID]", + variableId = "[VARIABLE_ID]", + key = "[KEY]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/functions/update.md b/docs/examples/1.4.x/server-kotlin/kotlin/functions/update.md new file mode 100644 index 0000000000..72f15af42d --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/functions/update.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Functions + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val functions = Functions(client) + +val response = functions.update( + functionId = "[FUNCTION_ID]", + name = "[NAME]", + runtime = "node-14.5", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/graphql/mutation.md b/docs/examples/1.4.x/server-kotlin/kotlin/graphql/mutation.md new file mode 100644 index 0000000000..aed06cd7a6 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/graphql/mutation.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Graphql + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val graphql = Graphql(client) + +val response = graphql.mutation( + query = mapOf( "a" to "b" ) +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/graphql/query.md b/docs/examples/1.4.x/server-kotlin/kotlin/graphql/query.md new file mode 100644 index 0000000000..bd29d431c4 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/graphql/query.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Graphql + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val graphql = Graphql(client) + +val response = graphql.query( + query = mapOf( "a" to "b" ) +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-antivirus.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-antivirus.md new file mode 100644 index 0000000000..e387fe0d95 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-antivirus.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getAntivirus() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-cache.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-cache.md new file mode 100644 index 0000000000..7aca9dd008 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-cache.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getCache() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-d-b.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-d-b.md new file mode 100644 index 0000000000..8e719142bb --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-d-b.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getDB() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-pub-sub.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-pub-sub.md new file mode 100644 index 0000000000..421407a831 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-pub-sub.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getPubSub() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-certificates.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-certificates.md new file mode 100644 index 0000000000..f416351705 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-certificates.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getQueueCertificates() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-functions.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-functions.md new file mode 100644 index 0000000000..b55241d8f2 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-functions.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getQueueFunctions() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-logs.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-logs.md new file mode 100644 index 0000000000..fb634ec63c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-logs.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getQueueLogs() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-webhooks.md new file mode 100644 index 0000000000..bf4629d259 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue-webhooks.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getQueueWebhooks() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue.md new file mode 100644 index 0000000000..ead51857ac --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-queue.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getQueue() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-storage-local.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-storage-local.md new file mode 100644 index 0000000000..f204168bc4 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-storage-local.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getStorageLocal() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get-time.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-time.md new file mode 100644 index 0000000000..35f3bb9bd6 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get-time.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.getTime() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/health/get.md b/docs/examples/1.4.x/server-kotlin/kotlin/health/get.md new file mode 100644 index 0000000000..b547be9aa5 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/health/get.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Health + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val health = Health(client) + +val response = health.get() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/locale/get.md b/docs/examples/1.4.x/server-kotlin/kotlin/locale/get.md new file mode 100644 index 0000000000..1d84651fea --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/locale/get.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val locale = Locale(client) + +val response = locale.get() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-codes.md b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-codes.md new file mode 100644 index 0000000000..28f02027e7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-codes.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val locale = Locale(client) + +val response = locale.listCodes() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-continents.md b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-continents.md new file mode 100644 index 0000000000..bd9ad1825b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-continents.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val locale = Locale(client) + +val response = locale.listContinents() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries-e-u.md new file mode 100644 index 0000000000..5d3258335e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries-e-u.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val locale = Locale(client) + +val response = locale.listCountriesEU() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries-phones.md b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries-phones.md new file mode 100644 index 0000000000..e0f2ae3c6b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries-phones.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val locale = Locale(client) + +val response = locale.listCountriesPhones() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries.md b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries.md new file mode 100644 index 0000000000..626d38133e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-countries.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val locale = Locale(client) + +val response = locale.listCountries() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-currencies.md b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-currencies.md new file mode 100644 index 0000000000..6457056d70 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-currencies.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val locale = Locale(client) + +val response = locale.listCurrencies() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-languages.md b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-languages.md new file mode 100644 index 0000000000..437b1c3fe9 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/locale/list-languages.md @@ -0,0 +1,11 @@ +import io.appwrite.Client +import io.appwrite.services.Locale + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val locale = Locale(client) + +val response = locale.listLanguages() diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/create-bucket.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/create-bucket.md new file mode 100644 index 0000000000..27d73ffd07 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/create-bucket.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.createBucket( + bucketId = "[BUCKET_ID]", + name = "[NAME]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/create-file.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/create-file.md new file mode 100644 index 0000000000..1bdf5e4893 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/create-file.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.models.InputFile +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.createFile( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]", + file = InputFile.fromPath("file.png"), +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/delete-bucket.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/delete-bucket.md new file mode 100644 index 0000000000..3730a05298 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/delete-bucket.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.deleteBucket( + bucketId = "[BUCKET_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/delete-file.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/delete-file.md new file mode 100644 index 0000000000..dabf805e8b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/delete-file.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.deleteFile( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-bucket.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-bucket.md new file mode 100644 index 0000000000..0c7fcc137c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-bucket.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.getBucket( + bucketId = "[BUCKET_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-download.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-download.md new file mode 100644 index 0000000000..6c3c1fb4ae --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-download.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val result = storage.getFileDownload( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-preview.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-preview.md new file mode 100644 index 0000000000..372416ed12 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-preview.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val result = storage.getFilePreview( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-view.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-view.md new file mode 100644 index 0000000000..4b23cfc9c6 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file-view.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val result = storage.getFileView( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file.md new file mode 100644 index 0000000000..211713c7b6 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/get-file.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.getFile( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/list-buckets.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/list-buckets.md new file mode 100644 index 0000000000..8c4c7bdaac --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/list-buckets.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.listBuckets( +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/list-files.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/list-files.md new file mode 100644 index 0000000000..5243ed74cc --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/list-files.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.listFiles( + bucketId = "[BUCKET_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/update-bucket.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/update-bucket.md new file mode 100644 index 0000000000..3de3b5460e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/update-bucket.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.updateBucket( + bucketId = "[BUCKET_ID]", + name = "[NAME]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/storage/update-file.md b/docs/examples/1.4.x/server-kotlin/kotlin/storage/update-file.md new file mode 100644 index 0000000000..3d7fb9ab26 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/storage/update-file.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Storage + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val storage = Storage(client) + +val response = storage.updateFile( + bucketId = "[BUCKET_ID]", + fileId = "[FILE_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/create-membership.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/create-membership.md new file mode 100644 index 0000000000..44f444bc10 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/create-membership.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.createMembership( + teamId = "[TEAM_ID]", + roles = listOf(), + url = "https://example.com", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/create.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/create.md new file mode 100644 index 0000000000..9e080a1346 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/create.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.create( + teamId = "[TEAM_ID]", + name = "[NAME]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/delete-membership.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/delete-membership.md new file mode 100644 index 0000000000..16e73e4884 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/delete-membership.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.deleteMembership( + teamId = "[TEAM_ID]", + membershipId = "[MEMBERSHIP_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/delete.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/delete.md new file mode 100644 index 0000000000..c015a772c8 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/delete.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.delete( + teamId = "[TEAM_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/get-membership.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/get-membership.md new file mode 100644 index 0000000000..4f2bed3800 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/get-membership.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.getMembership( + teamId = "[TEAM_ID]", + membershipId = "[MEMBERSHIP_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/get-prefs.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/get-prefs.md new file mode 100644 index 0000000000..1bfcf07f7a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/get-prefs.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val teams = Teams(client) + +val response = teams.getPrefs( + teamId = "[TEAM_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/get.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/get.md new file mode 100644 index 0000000000..402aeb1beb --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/get.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.get( + teamId = "[TEAM_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/list-memberships.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/list-memberships.md new file mode 100644 index 0000000000..e9eae80f0b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/list-memberships.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.listMemberships( + teamId = "[TEAM_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/list.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/list.md new file mode 100644 index 0000000000..aa10ca58fd --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/list.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.list( +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-membership-status.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-membership-status.md new file mode 100644 index 0000000000..7fa6bd837c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-membership-status.md @@ -0,0 +1,16 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val teams = Teams(client) + +val response = teams.updateMembershipStatus( + teamId = "[TEAM_ID]", + membershipId = "[MEMBERSHIP_ID]", + userId = "[USER_ID]", + secret = "[SECRET]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-membership.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-membership.md new file mode 100644 index 0000000000..9ca3a30f40 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-membership.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.updateMembership( + teamId = "[TEAM_ID]", + membershipId = "[MEMBERSHIP_ID]", + roles = listOf() +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-name.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-name.md new file mode 100644 index 0000000000..d717c371bc --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-name.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val teams = Teams(client) + +val response = teams.updateName( + teamId = "[TEAM_ID]", + name = "[NAME]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-prefs.md b/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-prefs.md new file mode 100644 index 0000000000..62fc925415 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/teams/update-prefs.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Teams + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +val teams = Teams(client) + +val response = teams.updatePrefs( + teamId = "[TEAM_ID]", + prefs = mapOf( "a" to "b" ) +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/create-argon2user.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-argon2user.md new file mode 100644 index 0000000000..438363aed3 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-argon2user.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.createArgon2User( + userId = "[USER_ID]", + email = "email@example.com", + password = "password", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-bcrypt-user.md new file mode 100644 index 0000000000..977782ce3c --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-bcrypt-user.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.createBcryptUser( + userId = "[USER_ID]", + email = "email@example.com", + password = "password", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/create-m-d5user.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-m-d5user.md new file mode 100644 index 0000000000..6d6451f376 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-m-d5user.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.createMD5User( + userId = "[USER_ID]", + email = "email@example.com", + password = "password", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..c50b2c1da4 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-p-h-pass-user.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.createPHPassUser( + userId = "[USER_ID]", + email = "email@example.com", + password = "password", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-s-h-a-user.md new file mode 100644 index 0000000000..708935c970 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-s-h-a-user.md @@ -0,0 +1,15 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.createSHAUser( + userId = "[USER_ID]", + email = "email@example.com", + password = "password", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..d49f7db471 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-scrypt-modified-user.md @@ -0,0 +1,18 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.createScryptModifiedUser( + userId = "[USER_ID]", + email = "email@example.com", + password = "password", + passwordSalt = "[PASSWORD_SALT]", + passwordSaltSeparator = "[PASSWORD_SALT_SEPARATOR]", + passwordSignerKey = "[PASSWORD_SIGNER_KEY]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/create-scrypt-user.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-scrypt-user.md new file mode 100644 index 0000000000..aa006fb0db --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/create-scrypt-user.md @@ -0,0 +1,20 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.createScryptUser( + userId = "[USER_ID]", + email = "email@example.com", + password = "password", + passwordSalt = "[PASSWORD_SALT]", + passwordCpu = 0, + passwordMemory = 0, + passwordParallel = 0, + passwordLength = 0, +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/create.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/create.md new file mode 100644 index 0000000000..ae319d8cd8 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/create.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.create( + userId = "[USER_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/delete-identity.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/delete-identity.md new file mode 100644 index 0000000000..7b4de829c7 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/delete-identity.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.deleteIdentity( + identityId = "[IDENTITY_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/delete-session.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/delete-session.md new file mode 100644 index 0000000000..f3a0264aa1 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/delete-session.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.deleteSession( + userId = "[USER_ID]", + sessionId = "[SESSION_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/delete-sessions.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/delete-sessions.md new file mode 100644 index 0000000000..5c0070c027 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/delete-sessions.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.deleteSessions( + userId = "[USER_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/delete.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/delete.md new file mode 100644 index 0000000000..30ee8f3d7a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/delete.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.delete( + userId = "[USER_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/get-prefs.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/get-prefs.md new file mode 100644 index 0000000000..564489c398 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/get-prefs.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.getPrefs( + userId = "[USER_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/get.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/get.md new file mode 100644 index 0000000000..fd7e4b7a1b --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/get.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.get( + userId = "[USER_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/list-identities.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/list-identities.md new file mode 100644 index 0000000000..0135fb1c23 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/list-identities.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.listIdentities( +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/list-logs.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/list-logs.md new file mode 100644 index 0000000000..691007588e --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/list-logs.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.listLogs( + userId = "[USER_ID]", +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/list-memberships.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/list-memberships.md new file mode 100644 index 0000000000..316889e894 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/list-memberships.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.listMemberships( + userId = "[USER_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/list-sessions.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/list-sessions.md new file mode 100644 index 0000000000..1d7e950425 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/list-sessions.md @@ -0,0 +1,13 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.listSessions( + userId = "[USER_ID]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/list.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/list.md new file mode 100644 index 0000000000..e973a26e52 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/list.md @@ -0,0 +1,12 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.list( +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/update-email-verification.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-email-verification.md new file mode 100644 index 0000000000..b4f97bbcab --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-email-verification.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.updateEmailVerification( + userId = "[USER_ID]", + emailVerification = false +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/update-email.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-email.md new file mode 100644 index 0000000000..c6dfaefd2f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-email.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.updateEmail( + userId = "[USER_ID]", + email = "email@example.com" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/update-labels.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-labels.md new file mode 100644 index 0000000000..4e869f8237 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-labels.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.updateLabels( + userId = "[USER_ID]", + labels = listOf() +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/update-name.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-name.md new file mode 100644 index 0000000000..1d46c7a8fc --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-name.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.updateName( + userId = "[USER_ID]", + name = "[NAME]" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/update-password.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-password.md new file mode 100644 index 0000000000..f96158faa9 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-password.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.updatePassword( + userId = "[USER_ID]", + password = "" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/update-phone-verification.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-phone-verification.md new file mode 100644 index 0000000000..909803bd94 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-phone-verification.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.updatePhoneVerification( + userId = "[USER_ID]", + phoneVerification = false +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/update-phone.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-phone.md new file mode 100644 index 0000000000..073dd6640a --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-phone.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.updatePhone( + userId = "[USER_ID]", + number = "+12065550100" +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/update-prefs.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-prefs.md new file mode 100644 index 0000000000..127035ca48 --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-prefs.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.updatePrefs( + userId = "[USER_ID]", + prefs = mapOf( "a" to "b" ) +) diff --git a/docs/examples/1.4.x/server-kotlin/kotlin/users/update-status.md b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-status.md new file mode 100644 index 0000000000..5899ed360f --- /dev/null +++ b/docs/examples/1.4.x/server-kotlin/kotlin/users/update-status.md @@ -0,0 +1,14 @@ +import io.appwrite.Client +import io.appwrite.services.Users + +val client = Client(context) + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +val users = Users(client) + +val response = users.updateStatus( + userId = "[USER_ID]", + status = false +) diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-nodejs/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..f381495f24 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/create-phone-verification.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.createPhoneVerification(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/create-recovery.md b/docs/examples/1.4.x/server-nodejs/examples/account/create-recovery.md new file mode 100644 index 0000000000..f4c5ae98de --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/create-recovery.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.createRecovery('email@example.com', 'https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/create-verification.md b/docs/examples/1.4.x/server-nodejs/examples/account/create-verification.md new file mode 100644 index 0000000000..04585621eb --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/create-verification.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.createVerification('https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/delete-identity.md b/docs/examples/1.4.x/server-nodejs/examples/account/delete-identity.md new file mode 100644 index 0000000000..2900aa1716 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/delete-identity.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.deleteIdentity('[IDENTITY_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/delete-session.md b/docs/examples/1.4.x/server-nodejs/examples/account/delete-session.md new file mode 100644 index 0000000000..74f3869859 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/delete-session.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.deleteSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-nodejs/examples/account/delete-sessions.md new file mode 100644 index 0000000000..0968c30b92 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/delete-sessions.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.deleteSessions(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/get-prefs.md b/docs/examples/1.4.x/server-nodejs/examples/account/get-prefs.md new file mode 100644 index 0000000000..8bd5d97c25 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/get-prefs.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.getPrefs(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/get-session.md b/docs/examples/1.4.x/server-nodejs/examples/account/get-session.md new file mode 100644 index 0000000000..3abb677fbe --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/get-session.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.getSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/get.md b/docs/examples/1.4.x/server-nodejs/examples/account/get.md new file mode 100644 index 0000000000..d4f4066fb1 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/get.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.get(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/list-identities.md b/docs/examples/1.4.x/server-nodejs/examples/account/list-identities.md new file mode 100644 index 0000000000..fa2013bbf6 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/list-identities.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.listIdentities(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/list-logs.md b/docs/examples/1.4.x/server-nodejs/examples/account/list-logs.md new file mode 100644 index 0000000000..890e0d12d3 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/list-logs.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.listLogs(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/list-sessions.md b/docs/examples/1.4.x/server-nodejs/examples/account/list-sessions.md new file mode 100644 index 0000000000..68e97ada31 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/list-sessions.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.listSessions(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-email.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-email.md new file mode 100644 index 0000000000..388e2581bb --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-email.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updateEmail('email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-name.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-name.md new file mode 100644 index 0000000000..0984652712 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-name.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updateName('[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-password.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-password.md new file mode 100644 index 0000000000..b46500fd3c --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-password.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updatePassword(''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..1aa4042f36 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-phone-verification.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updatePhoneVerification('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-phone.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-phone.md new file mode 100644 index 0000000000..37124d81aa --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-phone.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updatePhone('+12065550100', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-prefs.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-prefs.md new file mode 100644 index 0000000000..6948706abb --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-prefs.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updatePrefs({}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-recovery.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-recovery.md new file mode 100644 index 0000000000..74f70f59c7 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-recovery.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-session.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-session.md new file mode 100644 index 0000000000..b0b932524f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-session.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updateSession('[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-status.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-status.md new file mode 100644 index 0000000000..277243b824 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-status.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updateStatus(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/account/update-verification.md b/docs/examples/1.4.x/server-nodejs/examples/account/update-verification.md new file mode 100644 index 0000000000..6a7fbbf99c --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/account/update-verification.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const account = new sdk.Account(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = account.updateVerification('[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-browser.md new file mode 100644 index 0000000000..c05595ad67 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-browser.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = avatars.getBrowser('aa'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..8fbd37d29a --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-credit-card.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = avatars.getCreditCard('amex'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..2924e394a0 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-favicon.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = avatars.getFavicon('https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-flag.md new file mode 100644 index 0000000000..50d611c399 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-flag.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = avatars.getFlag('af'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/avatars/get-image.md b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-image.md new file mode 100644 index 0000000000..3b2bb517d1 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-image.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = avatars.getImage('https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-initials.md new file mode 100644 index 0000000000..4afda6f547 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-initials.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = avatars.getInitials(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..d2d24e2055 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/avatars/get-q-r.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const avatars = new sdk.Avatars(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = avatars.getQR('[TEXT]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..12a70102ca --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-boolean-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createBooleanAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-collection.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-collection.md new file mode 100644 index 0000000000..13ec4e037f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-collection.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createCollection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..70609a84e7 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-datetime-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createDatetimeAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-document.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-document.md new file mode 100644 index 0000000000..f5fa7a50a6 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-document.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]', {}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..2229dfe7f9 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-email-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createEmailAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..cd9daca603 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-enum-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createEnumAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..a12c4f4420 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-float-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createFloatAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-index.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-index.md new file mode 100644 index 0000000000..66c3e519fe --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-index.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createIndex('[DATABASE_ID]', '[COLLECTION_ID]', '', 'key', []); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..fa693d28de --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-integer-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createIntegerAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..1e8985a2bd --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-ip-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createIpAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..f680d1c03a --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-relationship-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createRelationshipAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '[RELATED_COLLECTION_ID]', 'oneToOne'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..bfb4fbfc3f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-string-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createStringAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', 1, false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..e6a585f76b --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create-url-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.createUrlAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/create.md b/docs/examples/1.4.x/server-nodejs/examples/databases/create.md new file mode 100644 index 0000000000..4e04f026bd --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/create.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.create('[DATABASE_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..3c65f62ef5 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/delete-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.deleteAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-nodejs/examples/databases/delete-collection.md new file mode 100644 index 0000000000..047fa26846 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/delete-collection.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.deleteCollection('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/delete-document.md b/docs/examples/1.4.x/server-nodejs/examples/databases/delete-document.md new file mode 100644 index 0000000000..a6f3fa58ca --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/delete-document.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.deleteDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/delete-index.md b/docs/examples/1.4.x/server-nodejs/examples/databases/delete-index.md new file mode 100644 index 0000000000..42d73104a0 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/delete-index.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.deleteIndex('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/delete.md b/docs/examples/1.4.x/server-nodejs/examples/databases/delete.md new file mode 100644 index 0000000000..3f39965820 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/delete.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.delete('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/get-attribute.md new file mode 100644 index 0000000000..df6c665b75 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/get-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.getAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/get-collection.md b/docs/examples/1.4.x/server-nodejs/examples/databases/get-collection.md new file mode 100644 index 0000000000..ea4ed423e8 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/get-collection.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.getCollection('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/get-document.md b/docs/examples/1.4.x/server-nodejs/examples/databases/get-document.md new file mode 100644 index 0000000000..ac07b968ae --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/get-document.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.getDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/get-index.md b/docs/examples/1.4.x/server-nodejs/examples/databases/get-index.md new file mode 100644 index 0000000000..c3a3d168c5 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/get-index.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.getIndex('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/get.md b/docs/examples/1.4.x/server-nodejs/examples/databases/get.md new file mode 100644 index 0000000000..133f496b2e --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/get.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.get('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-nodejs/examples/databases/list-attributes.md new file mode 100644 index 0000000000..b1a494b110 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/list-attributes.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.listAttributes('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/list-collections.md b/docs/examples/1.4.x/server-nodejs/examples/databases/list-collections.md new file mode 100644 index 0000000000..c1d9fd3421 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/list-collections.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.listCollections('[DATABASE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/list-documents.md b/docs/examples/1.4.x/server-nodejs/examples/databases/list-documents.md new file mode 100644 index 0000000000..bf0b9156bf --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/list-documents.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.listDocuments('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-nodejs/examples/databases/list-indexes.md new file mode 100644 index 0000000000..57787f1d3e --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/list-indexes.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.listIndexes('[DATABASE_ID]', '[COLLECTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/list.md b/docs/examples/1.4.x/server-nodejs/examples/databases/list.md new file mode 100644 index 0000000000..5652d1e032 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/list.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.list(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..3bdfc04e5f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-boolean-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateBooleanAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-collection.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-collection.md new file mode 100644 index 0000000000..db74a7b9eb --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-collection.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateCollection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..8b602d434f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-datetime-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateDatetimeAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-document.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-document.md new file mode 100644 index 0000000000..ca3cdb85e7 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-document.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..a96e89853b --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-email-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateEmailAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, 'email@example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..b0dfbb11df --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-enum-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateEnumAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], false, '[DEFAULT]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..2c0672dd99 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-float-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateFloatAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, null, null, null); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..8016aac600 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-integer-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateIntegerAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, null, null, null); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..8eab99aa35 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-ip-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateIpAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..699148f882 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-relationship-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateRelationshipAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..c7e6fe9b7f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-string-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateStringAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, '[DEFAULT]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..d8cb42aafd --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update-url-attribute.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.updateUrlAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, 'https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/databases/update.md b/docs/examples/1.4.x/server-nodejs/examples/databases/update.md new file mode 100644 index 0000000000..7abe11bf80 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/databases/update.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const databases = new sdk.Databases(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = databases.update('[DATABASE_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/create-build.md b/docs/examples/1.4.x/server-nodejs/examples/functions/create-build.md new file mode 100644 index 0000000000..fe9751e73b --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/create-build.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.createBuild('[FUNCTION_ID]', '[DEPLOYMENT_ID]', '[BUILD_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-nodejs/examples/functions/create-deployment.md new file mode 100644 index 0000000000..6d14142f2f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/create-deployment.md @@ -0,0 +1,21 @@ +const sdk = require('node-appwrite'); +const fs = require('fs'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.createDeployment('[FUNCTION_ID]', InputFile.fromPath('/path/to/file.png', 'file.png'), false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/create-execution.md b/docs/examples/1.4.x/server-nodejs/examples/functions/create-execution.md new file mode 100644 index 0000000000..dc182fdd44 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/create-execution.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.createExecution('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/create-variable.md b/docs/examples/1.4.x/server-nodejs/examples/functions/create-variable.md new file mode 100644 index 0000000000..80f3fd0257 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/create-variable.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.createVariable('[FUNCTION_ID]', '[KEY]', '[VALUE]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/create.md b/docs/examples/1.4.x/server-nodejs/examples/functions/create.md new file mode 100644 index 0000000000..8600f34b82 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/create.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.create('[FUNCTION_ID]', '[NAME]', 'node-14.5'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-nodejs/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..5affdf18b9 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/delete-deployment.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.deleteDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-nodejs/examples/functions/delete-variable.md new file mode 100644 index 0000000000..2a075fdea7 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/delete-variable.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.deleteVariable('[FUNCTION_ID]', '[VARIABLE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/delete.md b/docs/examples/1.4.x/server-nodejs/examples/functions/delete.md new file mode 100644 index 0000000000..d17f01361e --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/delete.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.delete('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-nodejs/examples/functions/download-deployment.md new file mode 100644 index 0000000000..d8bd913cc8 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/download-deployment.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.downloadDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-nodejs/examples/functions/get-deployment.md new file mode 100644 index 0000000000..d67ce4647a --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/get-deployment.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.getDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/get-execution.md b/docs/examples/1.4.x/server-nodejs/examples/functions/get-execution.md new file mode 100644 index 0000000000..bbf0788138 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/get-execution.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.getExecution('[FUNCTION_ID]', '[EXECUTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/get-variable.md b/docs/examples/1.4.x/server-nodejs/examples/functions/get-variable.md new file mode 100644 index 0000000000..11ce7e2836 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/get-variable.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.getVariable('[FUNCTION_ID]', '[VARIABLE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/get.md b/docs/examples/1.4.x/server-nodejs/examples/functions/get.md new file mode 100644 index 0000000000..54ea4812b8 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/get.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.get('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-nodejs/examples/functions/list-deployments.md new file mode 100644 index 0000000000..4819410875 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/list-deployments.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.listDeployments('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/list-executions.md b/docs/examples/1.4.x/server-nodejs/examples/functions/list-executions.md new file mode 100644 index 0000000000..f9e77a5d32 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/list-executions.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.listExecutions('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-nodejs/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..d471861374 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/list-runtimes.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.listRuntimes(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/list-variables.md b/docs/examples/1.4.x/server-nodejs/examples/functions/list-variables.md new file mode 100644 index 0000000000..e193b2b1ba --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/list-variables.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.listVariables('[FUNCTION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/list.md b/docs/examples/1.4.x/server-nodejs/examples/functions/list.md new file mode 100644 index 0000000000..4f7b45e26a --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/list.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.list(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-nodejs/examples/functions/update-deployment.md new file mode 100644 index 0000000000..25f0e79983 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/update-deployment.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.updateDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/update-variable.md b/docs/examples/1.4.x/server-nodejs/examples/functions/update-variable.md new file mode 100644 index 0000000000..86e9a698f5 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/update-variable.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.updateVariable('[FUNCTION_ID]', '[VARIABLE_ID]', '[KEY]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/functions/update.md b/docs/examples/1.4.x/server-nodejs/examples/functions/update.md new file mode 100644 index 0000000000..5ab5b1bd8b --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/functions/update.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const functions = new sdk.Functions(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = functions.update('[FUNCTION_ID]', '[NAME]', 'node-14.5'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/graphql/mutation.md b/docs/examples/1.4.x/server-nodejs/examples/graphql/mutation.md new file mode 100644 index 0000000000..6f9bed8426 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/graphql/mutation.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const graphql = new sdk.Graphql(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = graphql.mutation({}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/graphql/query.md b/docs/examples/1.4.x/server-nodejs/examples/graphql/query.md new file mode 100644 index 0000000000..35cd4060cc --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/graphql/query.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const graphql = new sdk.Graphql(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = graphql.query({}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-antivirus.md new file mode 100644 index 0000000000..b6e5e78a30 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-antivirus.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getAntivirus(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-cache.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-cache.md new file mode 100644 index 0000000000..8171c40fc6 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-cache.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getCache(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-d-b.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-d-b.md new file mode 100644 index 0000000000..ef1739fff0 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-d-b.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getDB(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..b690239910 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-pub-sub.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getPubSub(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..38dadde1b2 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-certificates.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getQueueCertificates(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..bc8668eda6 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-functions.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getQueueFunctions(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..918a9d9e6c --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-logs.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getQueueLogs(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..acf023a188 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue-webhooks.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getQueueWebhooks(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-queue.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue.md new file mode 100644 index 0000000000..4caafecfa4 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-queue.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getQueue(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-storage-local.md new file mode 100644 index 0000000000..76e51489fd --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-storage-local.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getStorageLocal(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get-time.md b/docs/examples/1.4.x/server-nodejs/examples/health/get-time.md new file mode 100644 index 0000000000..f44836ac3c --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get-time.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.getTime(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/health/get.md b/docs/examples/1.4.x/server-nodejs/examples/health/get.md new file mode 100644 index 0000000000..a66b25631f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/health/get.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const health = new sdk.Health(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = health.get(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/locale/get.md b/docs/examples/1.4.x/server-nodejs/examples/locale/get.md new file mode 100644 index 0000000000..31d90c6f11 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/locale/get.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = locale.get(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/locale/list-codes.md b/docs/examples/1.4.x/server-nodejs/examples/locale/list-codes.md new file mode 100644 index 0000000000..aa95dafc71 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/locale/list-codes.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = locale.listCodes(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/locale/list-continents.md b/docs/examples/1.4.x/server-nodejs/examples/locale/list-continents.md new file mode 100644 index 0000000000..ffe54d34da --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/locale/list-continents.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = locale.listContinents(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-nodejs/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..f9aaff666a --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/locale/list-countries-e-u.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = locale.listCountriesEU(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-nodejs/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..fdd2436dc0 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/locale/list-countries-phones.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = locale.listCountriesPhones(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/locale/list-countries.md b/docs/examples/1.4.x/server-nodejs/examples/locale/list-countries.md new file mode 100644 index 0000000000..429e188776 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/locale/list-countries.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = locale.listCountries(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-nodejs/examples/locale/list-currencies.md new file mode 100644 index 0000000000..12d82fb70f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/locale/list-currencies.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = locale.listCurrencies(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/locale/list-languages.md b/docs/examples/1.4.x/server-nodejs/examples/locale/list-languages.md new file mode 100644 index 0000000000..8ea2b40afc --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/locale/list-languages.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const locale = new sdk.Locale(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = locale.listLanguages(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-nodejs/examples/storage/create-bucket.md new file mode 100644 index 0000000000..9093b7c9a6 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/create-bucket.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.createBucket('[BUCKET_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/create-file.md b/docs/examples/1.4.x/server-nodejs/examples/storage/create-file.md new file mode 100644 index 0000000000..664005e273 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/create-file.md @@ -0,0 +1,21 @@ +const sdk = require('node-appwrite'); +const fs = require('fs'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.createFile('[BUCKET_ID]', '[FILE_ID]', InputFile.fromPath('/path/to/file.png', 'file.png')); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-nodejs/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..84486c68dc --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/delete-bucket.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.deleteBucket('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/delete-file.md b/docs/examples/1.4.x/server-nodejs/examples/storage/delete-file.md new file mode 100644 index 0000000000..c4d451c63f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/delete-file.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.deleteFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-nodejs/examples/storage/get-bucket.md new file mode 100644 index 0000000000..d0fbb94bbc --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/get-bucket.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.getBucket('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-nodejs/examples/storage/get-file-download.md new file mode 100644 index 0000000000..1503d102ba --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/get-file-download.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.getFileDownload('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-nodejs/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..19d34495ba --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/get-file-preview.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.getFilePreview('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-nodejs/examples/storage/get-file-view.md new file mode 100644 index 0000000000..1affab8bc0 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/get-file-view.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.getFileView('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/get-file.md b/docs/examples/1.4.x/server-nodejs/examples/storage/get-file.md new file mode 100644 index 0000000000..ceba42ce1e --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/get-file.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.getFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-nodejs/examples/storage/list-buckets.md new file mode 100644 index 0000000000..9945febb42 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/list-buckets.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.listBuckets(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/list-files.md b/docs/examples/1.4.x/server-nodejs/examples/storage/list-files.md new file mode 100644 index 0000000000..fea4bae61f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/list-files.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.listFiles('[BUCKET_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-nodejs/examples/storage/update-bucket.md new file mode 100644 index 0000000000..32df1f18d8 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/update-bucket.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.updateBucket('[BUCKET_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/storage/update-file.md b/docs/examples/1.4.x/server-nodejs/examples/storage/update-file.md new file mode 100644 index 0000000000..042a164501 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/storage/update-file.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const storage = new sdk.Storage(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = storage.updateFile('[BUCKET_ID]', '[FILE_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/create-membership.md b/docs/examples/1.4.x/server-nodejs/examples/teams/create-membership.md new file mode 100644 index 0000000000..34d843d934 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/create-membership.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.createMembership('[TEAM_ID]', [], 'https://example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/create.md b/docs/examples/1.4.x/server-nodejs/examples/teams/create.md new file mode 100644 index 0000000000..5552f829f9 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/create.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.create('[TEAM_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-nodejs/examples/teams/delete-membership.md new file mode 100644 index 0000000000..ef72e63138 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/delete-membership.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.deleteMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/delete.md b/docs/examples/1.4.x/server-nodejs/examples/teams/delete.md new file mode 100644 index 0000000000..6f1dfaa61d --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/delete.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.delete('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/get-membership.md b/docs/examples/1.4.x/server-nodejs/examples/teams/get-membership.md new file mode 100644 index 0000000000..d31aa9a8b6 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/get-membership.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.getMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-nodejs/examples/teams/get-prefs.md new file mode 100644 index 0000000000..0ac9e95ff1 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/get-prefs.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = teams.getPrefs('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/get.md b/docs/examples/1.4.x/server-nodejs/examples/teams/get.md new file mode 100644 index 0000000000..0d34943242 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/get.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.get('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-nodejs/examples/teams/list-memberships.md new file mode 100644 index 0000000000..ca25bcbd25 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/list-memberships.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.listMemberships('[TEAM_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/list.md b/docs/examples/1.4.x/server-nodejs/examples/teams/list.md new file mode 100644 index 0000000000..8610bc7dc4 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/list.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.list(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-nodejs/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..6c46e786a0 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/update-membership-status.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = teams.updateMembershipStatus('[TEAM_ID]', '[MEMBERSHIP_ID]', '[USER_ID]', '[SECRET]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/update-membership.md b/docs/examples/1.4.x/server-nodejs/examples/teams/update-membership.md new file mode 100644 index 0000000000..d5ba30a938 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/update-membership.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.updateMembership('[TEAM_ID]', '[MEMBERSHIP_ID]', []); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/update-name.md b/docs/examples/1.4.x/server-nodejs/examples/teams/update-name.md new file mode 100644 index 0000000000..962e18f168 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/update-name.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = teams.updateName('[TEAM_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-nodejs/examples/teams/update-prefs.md new file mode 100644 index 0000000000..eeeed6c7eb --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/teams/update-prefs.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const teams = new sdk.Teams(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +const promise = teams.updatePrefs('[TEAM_ID]', {}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-nodejs/examples/users/create-argon2user.md new file mode 100644 index 0000000000..2762cc0112 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/create-argon2user.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.createArgon2User('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-nodejs/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..7bbdd3b883 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/create-bcrypt-user.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.createBcryptUser('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-nodejs/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..0661743da2 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/create-m-d5user.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.createMD5User('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-nodejs/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..37bd7e70c5 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/create-p-h-pass-user.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.createPHPassUser('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-nodejs/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..1d0502598b --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/create-s-h-a-user.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.createSHAUser('[USER_ID]', 'email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-nodejs/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..5a0153ec9a --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.createScryptModifiedUser('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', '[PASSWORD_SALT_SEPARATOR]', '[PASSWORD_SIGNER_KEY]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-nodejs/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..83ec8d3d78 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/create-scrypt-user.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.createScryptUser('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', null, null, null, null); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/create.md b/docs/examples/1.4.x/server-nodejs/examples/users/create.md new file mode 100644 index 0000000000..65ab3fae41 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/create.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.create('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/delete-identity.md b/docs/examples/1.4.x/server-nodejs/examples/users/delete-identity.md new file mode 100644 index 0000000000..c3acfa9eca --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/delete-identity.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.deleteIdentity('[IDENTITY_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/delete-session.md b/docs/examples/1.4.x/server-nodejs/examples/users/delete-session.md new file mode 100644 index 0000000000..18617ba2e8 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/delete-session.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.deleteSession('[USER_ID]', '[SESSION_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-nodejs/examples/users/delete-sessions.md new file mode 100644 index 0000000000..c804d7ddcf --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/delete-sessions.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.deleteSessions('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/delete.md b/docs/examples/1.4.x/server-nodejs/examples/users/delete.md new file mode 100644 index 0000000000..53606a7a0a --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/delete.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.delete('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/get-prefs.md b/docs/examples/1.4.x/server-nodejs/examples/users/get-prefs.md new file mode 100644 index 0000000000..c60db8ac77 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/get-prefs.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.getPrefs('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/get.md b/docs/examples/1.4.x/server-nodejs/examples/users/get.md new file mode 100644 index 0000000000..3bad599d4d --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/get.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.get('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/list-identities.md b/docs/examples/1.4.x/server-nodejs/examples/users/list-identities.md new file mode 100644 index 0000000000..36a71b7051 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/list-identities.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.listIdentities(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/list-logs.md b/docs/examples/1.4.x/server-nodejs/examples/users/list-logs.md new file mode 100644 index 0000000000..0f76626c6e --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/list-logs.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.listLogs('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/list-memberships.md b/docs/examples/1.4.x/server-nodejs/examples/users/list-memberships.md new file mode 100644 index 0000000000..81e0c4bc8f --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/list-memberships.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.listMemberships('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/list-sessions.md b/docs/examples/1.4.x/server-nodejs/examples/users/list-sessions.md new file mode 100644 index 0000000000..b44341bcbe --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/list-sessions.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.listSessions('[USER_ID]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/list.md b/docs/examples/1.4.x/server-nodejs/examples/users/list.md new file mode 100644 index 0000000000..a9ba208d2e --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/list.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.list(); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-nodejs/examples/users/update-email-verification.md new file mode 100644 index 0000000000..29c3e26593 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/update-email-verification.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updateEmailVerification('[USER_ID]', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/update-email.md b/docs/examples/1.4.x/server-nodejs/examples/users/update-email.md new file mode 100644 index 0000000000..5cef6fb5ec --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/update-email.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updateEmail('[USER_ID]', 'email@example.com'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/update-labels.md b/docs/examples/1.4.x/server-nodejs/examples/users/update-labels.md new file mode 100644 index 0000000000..d727bf1ed2 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/update-labels.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updateLabels('[USER_ID]', []); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/update-name.md b/docs/examples/1.4.x/server-nodejs/examples/users/update-name.md new file mode 100644 index 0000000000..ea33b7ed51 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/update-name.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updateName('[USER_ID]', '[NAME]'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/update-password.md b/docs/examples/1.4.x/server-nodejs/examples/users/update-password.md new file mode 100644 index 0000000000..f08a5990f4 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/update-password.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updatePassword('[USER_ID]', ''); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-nodejs/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..e6a95f93f8 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/update-phone-verification.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updatePhoneVerification('[USER_ID]', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/update-phone.md b/docs/examples/1.4.x/server-nodejs/examples/users/update-phone.md new file mode 100644 index 0000000000..8db9863c00 --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/update-phone.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updatePhone('[USER_ID]', '+12065550100'); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/update-prefs.md b/docs/examples/1.4.x/server-nodejs/examples/users/update-prefs.md new file mode 100644 index 0000000000..75f1a4298c --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/update-prefs.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updatePrefs('[USER_ID]', {}); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-nodejs/examples/users/update-status.md b/docs/examples/1.4.x/server-nodejs/examples/users/update-status.md new file mode 100644 index 0000000000..ac52d732ea --- /dev/null +++ b/docs/examples/1.4.x/server-nodejs/examples/users/update-status.md @@ -0,0 +1,20 @@ +const sdk = require('node-appwrite'); + +// Init SDK +const client = new sdk.Client(); + +const users = new sdk.Users(client); + +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updateStatus('[USER_ID]', false); + +promise.then(function (response) { + console.log(response); +}, function (error) { + console.log(error); +}); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-php/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..1c41a30ce8 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/create-phone-verification.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->createPhoneVerification(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/create-recovery.md b/docs/examples/1.4.x/server-php/examples/account/create-recovery.md new file mode 100644 index 0000000000..8ca78fc37b --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/create-recovery.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->createRecovery('email@example.com', 'https://example.com'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/create-verification.md b/docs/examples/1.4.x/server-php/examples/account/create-verification.md new file mode 100644 index 0000000000..92fb38151c --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/create-verification.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->createVerification('https://example.com'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/delete-identity.md b/docs/examples/1.4.x/server-php/examples/account/delete-identity.md new file mode 100644 index 0000000000..0b509afdc4 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/delete-identity.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->deleteIdentity('[IDENTITY_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/delete-session.md b/docs/examples/1.4.x/server-php/examples/account/delete-session.md new file mode 100644 index 0000000000..51bf3e2d41 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/delete-session.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->deleteSession('[SESSION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-php/examples/account/delete-sessions.md new file mode 100644 index 0000000000..bf3bc2a300 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/delete-sessions.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->deleteSessions(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/get-prefs.md b/docs/examples/1.4.x/server-php/examples/account/get-prefs.md new file mode 100644 index 0000000000..a91b888723 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/get-prefs.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->getPrefs(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/get-session.md b/docs/examples/1.4.x/server-php/examples/account/get-session.md new file mode 100644 index 0000000000..9e2341ce08 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/get-session.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->getSession('[SESSION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/get.md b/docs/examples/1.4.x/server-php/examples/account/get.md new file mode 100644 index 0000000000..4333bf2e73 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/get.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->get(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/list-identities.md b/docs/examples/1.4.x/server-php/examples/account/list-identities.md new file mode 100644 index 0000000000..c522a15a3e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/list-identities.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->listIdentities(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/list-logs.md b/docs/examples/1.4.x/server-php/examples/account/list-logs.md new file mode 100644 index 0000000000..62bc86d668 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/list-logs.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->listLogs(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/list-sessions.md b/docs/examples/1.4.x/server-php/examples/account/list-sessions.md new file mode 100644 index 0000000000..7942a3de2a --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/list-sessions.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->listSessions(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-email.md b/docs/examples/1.4.x/server-php/examples/account/update-email.md new file mode 100644 index 0000000000..a7ac5ede7d --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-email.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updateEmail('email@example.com', 'password'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-name.md b/docs/examples/1.4.x/server-php/examples/account/update-name.md new file mode 100644 index 0000000000..21bac94900 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-name.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updateName('[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-password.md b/docs/examples/1.4.x/server-php/examples/account/update-password.md new file mode 100644 index 0000000000..47e4c96695 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-password.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updatePassword(''); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-php/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..02458727a5 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-phone-verification.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updatePhoneVerification('[USER_ID]', '[SECRET]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-phone.md b/docs/examples/1.4.x/server-php/examples/account/update-phone.md new file mode 100644 index 0000000000..eaa1898512 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-phone.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updatePhone('+12065550100', 'password'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-prefs.md b/docs/examples/1.4.x/server-php/examples/account/update-prefs.md new file mode 100644 index 0000000000..96d0be5781 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-prefs.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updatePrefs([]); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-recovery.md b/docs/examples/1.4.x/server-php/examples/account/update-recovery.md new file mode 100644 index 0000000000..379b219e6d --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-recovery.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-session.md b/docs/examples/1.4.x/server-php/examples/account/update-session.md new file mode 100644 index 0000000000..462be6b914 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-session.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updateSession('[SESSION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-status.md b/docs/examples/1.4.x/server-php/examples/account/update-status.md new file mode 100644 index 0000000000..b1a1f2c8ec --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-status.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updateStatus(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/account/update-verification.md b/docs/examples/1.4.x/server-php/examples/account/update-verification.md new file mode 100644 index 0000000000..ad583a422e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/account/update-verification.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$account = new Account($client); + +$result = $account->updateVerification('[USER_ID]', '[SECRET]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-php/examples/avatars/get-browser.md new file mode 100644 index 0000000000..362106f645 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/avatars/get-browser.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$avatars = new Avatars($client); + +$result = $avatars->getBrowser('aa'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-php/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..c85ebeac2e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/avatars/get-credit-card.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$avatars = new Avatars($client); + +$result = $avatars->getCreditCard('amex'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-php/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..088524e051 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/avatars/get-favicon.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$avatars = new Avatars($client); + +$result = $avatars->getFavicon('https://example.com'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-php/examples/avatars/get-flag.md new file mode 100644 index 0000000000..2f2705b61f --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/avatars/get-flag.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$avatars = new Avatars($client); + +$result = $avatars->getFlag('af'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/avatars/get-image.md b/docs/examples/1.4.x/server-php/examples/avatars/get-image.md new file mode 100644 index 0000000000..d576232a42 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/avatars/get-image.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$avatars = new Avatars($client); + +$result = $avatars->getImage('https://example.com'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-php/examples/avatars/get-initials.md new file mode 100644 index 0000000000..4e924c7062 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/avatars/get-initials.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$avatars = new Avatars($client); + +$result = $avatars->getInitials(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-php/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..fde6e35b77 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/avatars/get-q-r.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$avatars = new Avatars($client); + +$result = $avatars->getQR('[TEXT]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..17c92241b4 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-boolean-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createBooleanAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-collection.md b/docs/examples/1.4.x/server-php/examples/databases/create-collection.md new file mode 100644 index 0000000000..2fd5fb61c0 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-collection.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createCollection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..284163c266 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-datetime-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createDatetimeAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-document.md b/docs/examples/1.4.x/server-php/examples/databases/create-document.md new file mode 100644 index 0000000000..509160b9ad --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-document.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]', []); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..df68be7fb0 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-email-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createEmailAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..c469679fd7 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-enum-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createEnumAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..c182d0a774 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-float-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createFloatAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-index.md b/docs/examples/1.4.x/server-php/examples/databases/create-index.md new file mode 100644 index 0000000000..6ecd4cc58b --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-index.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createIndex('[DATABASE_ID]', '[COLLECTION_ID]', '', 'key', []); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..d86ca7056b --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-integer-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createIntegerAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..823fa99482 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-ip-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createIpAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..4840a66937 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-relationship-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createRelationshipAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '[RELATED_COLLECTION_ID]', 'oneToOne'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..50abd0a18d --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-string-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createStringAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', 1, false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..5520cb1334 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create-url-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->createUrlAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/create.md b/docs/examples/1.4.x/server-php/examples/databases/create.md new file mode 100644 index 0000000000..16176b9b40 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/create.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->create('[DATABASE_ID]', '[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..d89c7de4f7 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/delete-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->deleteAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-php/examples/databases/delete-collection.md new file mode 100644 index 0000000000..29c627bbf0 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/delete-collection.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->deleteCollection('[DATABASE_ID]', '[COLLECTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/delete-document.md b/docs/examples/1.4.x/server-php/examples/databases/delete-document.md new file mode 100644 index 0000000000..9d5f1f0d51 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/delete-document.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->deleteDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/delete-index.md b/docs/examples/1.4.x/server-php/examples/databases/delete-index.md new file mode 100644 index 0000000000..073aa3a82e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/delete-index.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->deleteIndex('[DATABASE_ID]', '[COLLECTION_ID]', ''); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/delete.md b/docs/examples/1.4.x/server-php/examples/databases/delete.md new file mode 100644 index 0000000000..3dab79bc99 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/delete.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->delete('[DATABASE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/get-attribute.md new file mode 100644 index 0000000000..c286a7692a --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/get-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->getAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/get-collection.md b/docs/examples/1.4.x/server-php/examples/databases/get-collection.md new file mode 100644 index 0000000000..7cc578df8d --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/get-collection.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->getCollection('[DATABASE_ID]', '[COLLECTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/get-document.md b/docs/examples/1.4.x/server-php/examples/databases/get-document.md new file mode 100644 index 0000000000..7637e035e2 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/get-document.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->getDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/get-index.md b/docs/examples/1.4.x/server-php/examples/databases/get-index.md new file mode 100644 index 0000000000..a674a5935e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/get-index.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->getIndex('[DATABASE_ID]', '[COLLECTION_ID]', ''); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/get.md b/docs/examples/1.4.x/server-php/examples/databases/get.md new file mode 100644 index 0000000000..adc415f9a5 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/get.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->get('[DATABASE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-php/examples/databases/list-attributes.md new file mode 100644 index 0000000000..424c4b2405 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/list-attributes.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->listAttributes('[DATABASE_ID]', '[COLLECTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/list-collections.md b/docs/examples/1.4.x/server-php/examples/databases/list-collections.md new file mode 100644 index 0000000000..3f311f3138 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/list-collections.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->listCollections('[DATABASE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/list-documents.md b/docs/examples/1.4.x/server-php/examples/databases/list-documents.md new file mode 100644 index 0000000000..c9a6bbe4ff --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/list-documents.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->listDocuments('[DATABASE_ID]', '[COLLECTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-php/examples/databases/list-indexes.md new file mode 100644 index 0000000000..733d20b933 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/list-indexes.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->listIndexes('[DATABASE_ID]', '[COLLECTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/list.md b/docs/examples/1.4.x/server-php/examples/databases/list.md new file mode 100644 index 0000000000..45963718d3 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/list.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->list(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..9e8b8699e1 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-boolean-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateBooleanAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-collection.md b/docs/examples/1.4.x/server-php/examples/databases/update-collection.md new file mode 100644 index 0000000000..878bf20986 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-collection.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateCollection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..26214fb785 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-datetime-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateDatetimeAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, ''); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-document.md b/docs/examples/1.4.x/server-php/examples/databases/update-document.md new file mode 100644 index 0000000000..796e4600eb --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-document.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateDocument('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..7278881e3b --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-email-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateEmailAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, 'email@example.com'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..a77211b0f7 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-enum-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateEnumAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], false, '[DEFAULT]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..e73793e1fd --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-float-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateFloatAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, null, null, null); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..1cff205200 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-integer-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateIntegerAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, null, null, null); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..bb49d89c39 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-ip-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateIpAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, ''); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..b68025b84c --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-relationship-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateRelationshipAttribute('[DATABASE_ID]', '[COLLECTION_ID]', ''); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..775d0fa2be --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-string-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateStringAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, '[DEFAULT]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-php/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..6d4845e7eb --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update-url-attribute.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->updateUrlAttribute('[DATABASE_ID]', '[COLLECTION_ID]', '', false, 'https://example.com'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/databases/update.md b/docs/examples/1.4.x/server-php/examples/databases/update.md new file mode 100644 index 0000000000..db1ae7688e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/databases/update.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$databases = new Databases($client); + +$result = $databases->update('[DATABASE_ID]', '[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/create-build.md b/docs/examples/1.4.x/server-php/examples/functions/create-build.md new file mode 100644 index 0000000000..ac66cc2eb2 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/create-build.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->createBuild('[FUNCTION_ID]', '[DEPLOYMENT_ID]', '[BUILD_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-php/examples/functions/create-deployment.md new file mode 100644 index 0000000000..b219b509de --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/create-deployment.md @@ -0,0 +1,17 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->createDeployment('[FUNCTION_ID]', InputFile::withPath('file.png'), false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/create-execution.md b/docs/examples/1.4.x/server-php/examples/functions/create-execution.md new file mode 100644 index 0000000000..038126a728 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/create-execution.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->createExecution('[FUNCTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/create-variable.md b/docs/examples/1.4.x/server-php/examples/functions/create-variable.md new file mode 100644 index 0000000000..f09e61861e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/create-variable.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->createVariable('[FUNCTION_ID]', '[KEY]', '[VALUE]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/create.md b/docs/examples/1.4.x/server-php/examples/functions/create.md new file mode 100644 index 0000000000..22744b7584 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/create.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->create('[FUNCTION_ID]', '[NAME]', 'node-14.5'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-php/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..7227cd995f --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/delete-deployment.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->deleteDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-php/examples/functions/delete-variable.md new file mode 100644 index 0000000000..a457846492 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/delete-variable.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->deleteVariable('[FUNCTION_ID]', '[VARIABLE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/delete.md b/docs/examples/1.4.x/server-php/examples/functions/delete.md new file mode 100644 index 0000000000..d06c732f57 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/delete.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->delete('[FUNCTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-php/examples/functions/download-deployment.md new file mode 100644 index 0000000000..d7a6d55e2a --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/download-deployment.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->downloadDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-php/examples/functions/get-deployment.md new file mode 100644 index 0000000000..4c4fe49eb3 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/get-deployment.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->getDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/get-execution.md b/docs/examples/1.4.x/server-php/examples/functions/get-execution.md new file mode 100644 index 0000000000..ff59dc1cfe --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/get-execution.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->getExecution('[FUNCTION_ID]', '[EXECUTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/get-variable.md b/docs/examples/1.4.x/server-php/examples/functions/get-variable.md new file mode 100644 index 0000000000..e80b8f9fc0 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/get-variable.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->getVariable('[FUNCTION_ID]', '[VARIABLE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/get.md b/docs/examples/1.4.x/server-php/examples/functions/get.md new file mode 100644 index 0000000000..aef5806259 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/get.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->get('[FUNCTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-php/examples/functions/list-deployments.md new file mode 100644 index 0000000000..366e5fdc71 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/list-deployments.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->listDeployments('[FUNCTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/list-executions.md b/docs/examples/1.4.x/server-php/examples/functions/list-executions.md new file mode 100644 index 0000000000..34a80ad434 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/list-executions.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->listExecutions('[FUNCTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-php/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..b35dadfec9 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/list-runtimes.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->listRuntimes(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/list-variables.md b/docs/examples/1.4.x/server-php/examples/functions/list-variables.md new file mode 100644 index 0000000000..cf74289157 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/list-variables.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->listVariables('[FUNCTION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/list.md b/docs/examples/1.4.x/server-php/examples/functions/list.md new file mode 100644 index 0000000000..f57875572e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/list.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->list(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-php/examples/functions/update-deployment.md new file mode 100644 index 0000000000..b5f09cd018 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/update-deployment.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->updateDeployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/update-variable.md b/docs/examples/1.4.x/server-php/examples/functions/update-variable.md new file mode 100644 index 0000000000..4eb52d94d3 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/update-variable.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->updateVariable('[FUNCTION_ID]', '[VARIABLE_ID]', '[KEY]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/functions/update.md b/docs/examples/1.4.x/server-php/examples/functions/update.md new file mode 100644 index 0000000000..f76fbfa4d7 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/functions/update.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$functions = new Functions($client); + +$result = $functions->update('[FUNCTION_ID]', '[NAME]', 'node-14.5'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/graphql/mutation.md b/docs/examples/1.4.x/server-php/examples/graphql/mutation.md new file mode 100644 index 0000000000..5622f7f269 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/graphql/mutation.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$graphql = new Graphql($client); + +$result = $graphql->mutation([]); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/graphql/query.md b/docs/examples/1.4.x/server-php/examples/graphql/query.md new file mode 100644 index 0000000000..3ca1d940c4 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/graphql/query.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$graphql = new Graphql($client); + +$result = $graphql->query([]); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-php/examples/health/get-antivirus.md new file mode 100644 index 0000000000..4f1483514b --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-antivirus.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getAntivirus(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-cache.md b/docs/examples/1.4.x/server-php/examples/health/get-cache.md new file mode 100644 index 0000000000..3d1b19b3ef --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-cache.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getCache(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-d-b.md b/docs/examples/1.4.x/server-php/examples/health/get-d-b.md new file mode 100644 index 0000000000..c03ba23723 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-d-b.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getDB(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-php/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..721b5c2474 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-pub-sub.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getPubSub(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-php/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..76236de7b5 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-queue-certificates.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getQueueCertificates(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-php/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..31f65de1d1 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-queue-functions.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getQueueFunctions(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-php/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..ff1adb2a41 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-queue-logs.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getQueueLogs(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-php/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..99592bcfac --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-queue-webhooks.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getQueueWebhooks(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-queue.md b/docs/examples/1.4.x/server-php/examples/health/get-queue.md new file mode 100644 index 0000000000..9feb1ad8e2 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-queue.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getQueue(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-php/examples/health/get-storage-local.md new file mode 100644 index 0000000000..55212c36ae --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-storage-local.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getStorageLocal(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get-time.md b/docs/examples/1.4.x/server-php/examples/health/get-time.md new file mode 100644 index 0000000000..5410124786 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get-time.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->getTime(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/health/get.md b/docs/examples/1.4.x/server-php/examples/health/get.md new file mode 100644 index 0000000000..62cab8acf2 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/health/get.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$health = new Health($client); + +$result = $health->get(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/locale/get.md b/docs/examples/1.4.x/server-php/examples/locale/get.md new file mode 100644 index 0000000000..c4910463c5 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/locale/get.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$locale = new Locale($client); + +$result = $locale->get(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/locale/list-codes.md b/docs/examples/1.4.x/server-php/examples/locale/list-codes.md new file mode 100644 index 0000000000..55207ce32d --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/locale/list-codes.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$locale = new Locale($client); + +$result = $locale->listCodes(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/locale/list-continents.md b/docs/examples/1.4.x/server-php/examples/locale/list-continents.md new file mode 100644 index 0000000000..9cd8fb1399 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/locale/list-continents.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$locale = new Locale($client); + +$result = $locale->listContinents(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-php/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..1f2ef98c96 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/locale/list-countries-e-u.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$locale = new Locale($client); + +$result = $locale->listCountriesEU(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-php/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..6f8acb7467 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/locale/list-countries-phones.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$locale = new Locale($client); + +$result = $locale->listCountriesPhones(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/locale/list-countries.md b/docs/examples/1.4.x/server-php/examples/locale/list-countries.md new file mode 100644 index 0000000000..28c518e82a --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/locale/list-countries.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$locale = new Locale($client); + +$result = $locale->listCountries(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-php/examples/locale/list-currencies.md new file mode 100644 index 0000000000..37784f3d1e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/locale/list-currencies.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$locale = new Locale($client); + +$result = $locale->listCurrencies(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/locale/list-languages.md b/docs/examples/1.4.x/server-php/examples/locale/list-languages.md new file mode 100644 index 0000000000..8b4f082cb0 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/locale/list-languages.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$locale = new Locale($client); + +$result = $locale->listLanguages(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-php/examples/storage/create-bucket.md new file mode 100644 index 0000000000..bf54c22a47 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/create-bucket.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->createBucket('[BUCKET_ID]', '[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/create-file.md b/docs/examples/1.4.x/server-php/examples/storage/create-file.md new file mode 100644 index 0000000000..e2cfce7ae9 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/create-file.md @@ -0,0 +1,17 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->createFile('[BUCKET_ID]', '[FILE_ID]', InputFile::withPath('file.png')); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-php/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..b3659b6276 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/delete-bucket.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->deleteBucket('[BUCKET_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/delete-file.md b/docs/examples/1.4.x/server-php/examples/storage/delete-file.md new file mode 100644 index 0000000000..00db8551b3 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/delete-file.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->deleteFile('[BUCKET_ID]', '[FILE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-php/examples/storage/get-bucket.md new file mode 100644 index 0000000000..d4d152aff4 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/get-bucket.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->getBucket('[BUCKET_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-php/examples/storage/get-file-download.md new file mode 100644 index 0000000000..0c7fefda37 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/get-file-download.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->getFileDownload('[BUCKET_ID]', '[FILE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-php/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..c1b91e5c29 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/get-file-preview.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->getFilePreview('[BUCKET_ID]', '[FILE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-php/examples/storage/get-file-view.md new file mode 100644 index 0000000000..f527c1b744 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/get-file-view.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->getFileView('[BUCKET_ID]', '[FILE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/get-file.md b/docs/examples/1.4.x/server-php/examples/storage/get-file.md new file mode 100644 index 0000000000..cb56c96a42 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/get-file.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->getFile('[BUCKET_ID]', '[FILE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-php/examples/storage/list-buckets.md new file mode 100644 index 0000000000..b92dc82bcb --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/list-buckets.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->listBuckets(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/list-files.md b/docs/examples/1.4.x/server-php/examples/storage/list-files.md new file mode 100644 index 0000000000..e0b79186e4 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/list-files.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->listFiles('[BUCKET_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-php/examples/storage/update-bucket.md new file mode 100644 index 0000000000..5e46dfc83b --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/update-bucket.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->updateBucket('[BUCKET_ID]', '[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/storage/update-file.md b/docs/examples/1.4.x/server-php/examples/storage/update-file.md new file mode 100644 index 0000000000..1d3e01e99a --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/storage/update-file.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$storage = new Storage($client); + +$result = $storage->updateFile('[BUCKET_ID]', '[FILE_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/create-membership.md b/docs/examples/1.4.x/server-php/examples/teams/create-membership.md new file mode 100644 index 0000000000..34f642ea11 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/create-membership.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->createMembership('[TEAM_ID]', [], 'https://example.com'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/create.md b/docs/examples/1.4.x/server-php/examples/teams/create.md new file mode 100644 index 0000000000..e5efe49b30 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/create.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->create('[TEAM_ID]', '[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-php/examples/teams/delete-membership.md new file mode 100644 index 0000000000..2b40c1742e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/delete-membership.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->deleteMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/delete.md b/docs/examples/1.4.x/server-php/examples/teams/delete.md new file mode 100644 index 0000000000..5ec2ed995c --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/delete.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->delete('[TEAM_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/get-membership.md b/docs/examples/1.4.x/server-php/examples/teams/get-membership.md new file mode 100644 index 0000000000..fdd3024783 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/get-membership.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->getMembership('[TEAM_ID]', '[MEMBERSHIP_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-php/examples/teams/get-prefs.md new file mode 100644 index 0000000000..0436f96962 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/get-prefs.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$teams = new Teams($client); + +$result = $teams->getPrefs('[TEAM_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/get.md b/docs/examples/1.4.x/server-php/examples/teams/get.md new file mode 100644 index 0000000000..94b8a2695a --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/get.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->get('[TEAM_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-php/examples/teams/list-memberships.md new file mode 100644 index 0000000000..f23b78eca1 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/list-memberships.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->listMemberships('[TEAM_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/list.md b/docs/examples/1.4.x/server-php/examples/teams/list.md new file mode 100644 index 0000000000..66f54b6e1c --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/list.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->list(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-php/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..15504ad421 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/update-membership-status.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$teams = new Teams($client); + +$result = $teams->updateMembershipStatus('[TEAM_ID]', '[MEMBERSHIP_ID]', '[USER_ID]', '[SECRET]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/update-membership.md b/docs/examples/1.4.x/server-php/examples/teams/update-membership.md new file mode 100644 index 0000000000..37b8fa7388 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/update-membership.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->updateMembership('[TEAM_ID]', '[MEMBERSHIP_ID]', []); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/update-name.md b/docs/examples/1.4.x/server-php/examples/teams/update-name.md new file mode 100644 index 0000000000..e88a31862d --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/update-name.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$teams = new Teams($client); + +$result = $teams->updateName('[TEAM_ID]', '[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-php/examples/teams/update-prefs.md new file mode 100644 index 0000000000..4d044cce23 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/teams/update-prefs.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token +; + +$teams = new Teams($client); + +$result = $teams->updatePrefs('[TEAM_ID]', []); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-php/examples/users/create-argon2user.md new file mode 100644 index 0000000000..1036ca109e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/create-argon2user.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->createArgon2User('[USER_ID]', 'email@example.com', 'password'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-php/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..de15110a4e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/create-bcrypt-user.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->createBcryptUser('[USER_ID]', 'email@example.com', 'password'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-php/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..15f4ebe0aa --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/create-m-d5user.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->createMD5User('[USER_ID]', 'email@example.com', 'password'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-php/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..2eb682fc42 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/create-p-h-pass-user.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->createPHPassUser('[USER_ID]', 'email@example.com', 'password'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-php/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..3e63bd9928 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/create-s-h-a-user.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->createSHAUser('[USER_ID]', 'email@example.com', 'password'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-php/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..bcf7c52cd5 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->createScryptModifiedUser('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', '[PASSWORD_SALT_SEPARATOR]', '[PASSWORD_SIGNER_KEY]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-php/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..43a4bcc2e2 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/create-scrypt-user.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->createScryptUser('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', null, null, null, null); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/create.md b/docs/examples/1.4.x/server-php/examples/users/create.md new file mode 100644 index 0000000000..dab8a5ed70 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/create.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->create('[USER_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/delete-identity.md b/docs/examples/1.4.x/server-php/examples/users/delete-identity.md new file mode 100644 index 0000000000..a25222751c --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/delete-identity.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->deleteIdentity('[IDENTITY_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/delete-session.md b/docs/examples/1.4.x/server-php/examples/users/delete-session.md new file mode 100644 index 0000000000..c6a507c7b2 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/delete-session.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->deleteSession('[USER_ID]', '[SESSION_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-php/examples/users/delete-sessions.md new file mode 100644 index 0000000000..570d258683 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/delete-sessions.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->deleteSessions('[USER_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/delete.md b/docs/examples/1.4.x/server-php/examples/users/delete.md new file mode 100644 index 0000000000..1d5a822fde --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/delete.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->delete('[USER_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/get-prefs.md b/docs/examples/1.4.x/server-php/examples/users/get-prefs.md new file mode 100644 index 0000000000..e9c8c58bf3 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/get-prefs.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->getPrefs('[USER_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/get.md b/docs/examples/1.4.x/server-php/examples/users/get.md new file mode 100644 index 0000000000..51482d37eb --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/get.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->get('[USER_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/list-identities.md b/docs/examples/1.4.x/server-php/examples/users/list-identities.md new file mode 100644 index 0000000000..2d229e4119 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/list-identities.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->listIdentities(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/list-logs.md b/docs/examples/1.4.x/server-php/examples/users/list-logs.md new file mode 100644 index 0000000000..e6287563c2 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/list-logs.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->listLogs('[USER_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/list-memberships.md b/docs/examples/1.4.x/server-php/examples/users/list-memberships.md new file mode 100644 index 0000000000..039216bc1e --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/list-memberships.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->listMemberships('[USER_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/list-sessions.md b/docs/examples/1.4.x/server-php/examples/users/list-sessions.md new file mode 100644 index 0000000000..e09b65d475 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/list-sessions.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->listSessions('[USER_ID]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/list.md b/docs/examples/1.4.x/server-php/examples/users/list.md new file mode 100644 index 0000000000..8d86e86372 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/list.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->list(); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-php/examples/users/update-email-verification.md new file mode 100644 index 0000000000..67c3e12ee0 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/update-email-verification.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->updateEmailVerification('[USER_ID]', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/update-email.md b/docs/examples/1.4.x/server-php/examples/users/update-email.md new file mode 100644 index 0000000000..c6a7412b89 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/update-email.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->updateEmail('[USER_ID]', 'email@example.com'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/update-labels.md b/docs/examples/1.4.x/server-php/examples/users/update-labels.md new file mode 100644 index 0000000000..b9f4dc30dc --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/update-labels.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->updateLabels('[USER_ID]', []); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/update-name.md b/docs/examples/1.4.x/server-php/examples/users/update-name.md new file mode 100644 index 0000000000..598ef2a3a2 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/update-name.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->updateName('[USER_ID]', '[NAME]'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/update-password.md b/docs/examples/1.4.x/server-php/examples/users/update-password.md new file mode 100644 index 0000000000..de5ec7d132 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/update-password.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->updatePassword('[USER_ID]', ''); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-php/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..e9929a547b --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/update-phone-verification.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->updatePhoneVerification('[USER_ID]', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/update-phone.md b/docs/examples/1.4.x/server-php/examples/users/update-phone.md new file mode 100644 index 0000000000..0df380a23a --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/update-phone.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->updatePhone('[USER_ID]', '+12065550100'); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/update-prefs.md b/docs/examples/1.4.x/server-php/examples/users/update-prefs.md new file mode 100644 index 0000000000..9c4ebaae2b --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/update-prefs.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->updatePrefs('[USER_ID]', []); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-php/examples/users/update-status.md b/docs/examples/1.4.x/server-php/examples/users/update-status.md new file mode 100644 index 0000000000..ad3f6bde79 --- /dev/null +++ b/docs/examples/1.4.x/server-php/examples/users/update-status.md @@ -0,0 +1,16 @@ +setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('5df5acd0d48c2') // Your project ID + ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +$users = new Users($client); + +$result = $users->updateStatus('[USER_ID]', false); \ No newline at end of file diff --git a/docs/examples/1.4.x/server-python/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-python/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..2203cdbd0c --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/create-phone-verification.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.create_phone_verification() diff --git a/docs/examples/1.4.x/server-python/examples/account/create-recovery.md b/docs/examples/1.4.x/server-python/examples/account/create-recovery.md new file mode 100644 index 0000000000..21130fef6d --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/create-recovery.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.create_recovery('email@example.com', 'https://example.com') diff --git a/docs/examples/1.4.x/server-python/examples/account/create-verification.md b/docs/examples/1.4.x/server-python/examples/account/create-verification.md new file mode 100644 index 0000000000..c45d0d462e --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/create-verification.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.create_verification('https://example.com') diff --git a/docs/examples/1.4.x/server-python/examples/account/delete-identity.md b/docs/examples/1.4.x/server-python/examples/account/delete-identity.md new file mode 100644 index 0000000000..bac4334585 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/delete-identity.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.delete_identity('[IDENTITY_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/account/delete-session.md b/docs/examples/1.4.x/server-python/examples/account/delete-session.md new file mode 100644 index 0000000000..8095cdc07f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/delete-session.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.delete_session('[SESSION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-python/examples/account/delete-sessions.md new file mode 100644 index 0000000000..1728d61e67 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/delete-sessions.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.delete_sessions() diff --git a/docs/examples/1.4.x/server-python/examples/account/get-prefs.md b/docs/examples/1.4.x/server-python/examples/account/get-prefs.md new file mode 100644 index 0000000000..da2fd7628e --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/get-prefs.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.get_prefs() diff --git a/docs/examples/1.4.x/server-python/examples/account/get-session.md b/docs/examples/1.4.x/server-python/examples/account/get-session.md new file mode 100644 index 0000000000..25b8f03837 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/get-session.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.get_session('[SESSION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/account/get.md b/docs/examples/1.4.x/server-python/examples/account/get.md new file mode 100644 index 0000000000..f75bad7769 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/get.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.get() diff --git a/docs/examples/1.4.x/server-python/examples/account/list-identities.md b/docs/examples/1.4.x/server-python/examples/account/list-identities.md new file mode 100644 index 0000000000..3c166d1df1 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/list-identities.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.list_identities() diff --git a/docs/examples/1.4.x/server-python/examples/account/list-logs.md b/docs/examples/1.4.x/server-python/examples/account/list-logs.md new file mode 100644 index 0000000000..65802d8b0d --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/list-logs.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.list_logs() diff --git a/docs/examples/1.4.x/server-python/examples/account/list-sessions.md b/docs/examples/1.4.x/server-python/examples/account/list-sessions.md new file mode 100644 index 0000000000..12d5c81d92 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/list-sessions.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.list_sessions() diff --git a/docs/examples/1.4.x/server-python/examples/account/update-email.md b/docs/examples/1.4.x/server-python/examples/account/update-email.md new file mode 100644 index 0000000000..f4a6776f72 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-email.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_email('email@example.com', 'password') diff --git a/docs/examples/1.4.x/server-python/examples/account/update-name.md b/docs/examples/1.4.x/server-python/examples/account/update-name.md new file mode 100644 index 0000000000..eb1eb6279b --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-name.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_name('[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/account/update-password.md b/docs/examples/1.4.x/server-python/examples/account/update-password.md new file mode 100644 index 0000000000..955ada651d --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-password.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_password('') diff --git a/docs/examples/1.4.x/server-python/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-python/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..f2a75b4de9 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-phone-verification.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_phone_verification('[USER_ID]', '[SECRET]') diff --git a/docs/examples/1.4.x/server-python/examples/account/update-phone.md b/docs/examples/1.4.x/server-python/examples/account/update-phone.md new file mode 100644 index 0000000000..aaee1f7eec --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-phone.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_phone('+12065550100', 'password') diff --git a/docs/examples/1.4.x/server-python/examples/account/update-prefs.md b/docs/examples/1.4.x/server-python/examples/account/update-prefs.md new file mode 100644 index 0000000000..e96546b05a --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-prefs.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_prefs({}) diff --git a/docs/examples/1.4.x/server-python/examples/account/update-recovery.md b/docs/examples/1.4.x/server-python/examples/account/update-recovery.md new file mode 100644 index 0000000000..b4ea8aa89c --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-recovery.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_recovery('[USER_ID]', '[SECRET]', 'password', 'password') diff --git a/docs/examples/1.4.x/server-python/examples/account/update-session.md b/docs/examples/1.4.x/server-python/examples/account/update-session.md new file mode 100644 index 0000000000..e7234f7801 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-session.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_session('[SESSION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/account/update-status.md b/docs/examples/1.4.x/server-python/examples/account/update-status.md new file mode 100644 index 0000000000..5924d4d54f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-status.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_status() diff --git a/docs/examples/1.4.x/server-python/examples/account/update-verification.md b/docs/examples/1.4.x/server-python/examples/account/update-verification.md new file mode 100644 index 0000000000..9a410a54a8 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/account/update-verification.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +account = Account(client) + +result = account.update_verification('[USER_ID]', '[SECRET]') diff --git a/docs/examples/1.4.x/server-python/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-python/examples/avatars/get-browser.md new file mode 100644 index 0000000000..9ed56d1d4b --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/avatars/get-browser.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.avatars import Avatars + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +avatars = Avatars(client) + +result = avatars.get_browser('aa') diff --git a/docs/examples/1.4.x/server-python/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-python/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..9fa6b0fd1f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/avatars/get-credit-card.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.avatars import Avatars + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +avatars = Avatars(client) + +result = avatars.get_credit_card('amex') diff --git a/docs/examples/1.4.x/server-python/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-python/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..75b0315eae --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/avatars/get-favicon.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.avatars import Avatars + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +avatars = Avatars(client) + +result = avatars.get_favicon('https://example.com') diff --git a/docs/examples/1.4.x/server-python/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-python/examples/avatars/get-flag.md new file mode 100644 index 0000000000..70d2e5f242 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/avatars/get-flag.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.avatars import Avatars + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +avatars = Avatars(client) + +result = avatars.get_flag('af') diff --git a/docs/examples/1.4.x/server-python/examples/avatars/get-image.md b/docs/examples/1.4.x/server-python/examples/avatars/get-image.md new file mode 100644 index 0000000000..35015d9620 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/avatars/get-image.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.avatars import Avatars + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +avatars = Avatars(client) + +result = avatars.get_image('https://example.com') diff --git a/docs/examples/1.4.x/server-python/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-python/examples/avatars/get-initials.md new file mode 100644 index 0000000000..639fa03bc9 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/avatars/get-initials.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.avatars import Avatars + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +avatars = Avatars(client) + +result = avatars.get_initials() diff --git a/docs/examples/1.4.x/server-python/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-python/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..27fc8e2924 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/avatars/get-q-r.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.avatars import Avatars + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +avatars = Avatars(client) + +result = avatars.get_qr('[TEXT]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..f073d3d3b3 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-boolean-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_boolean_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-collection.md b/docs/examples/1.4.x/server-python/examples/databases/create-collection.md new file mode 100644 index 0000000000..183c55c448 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-collection.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_collection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..5c77689c99 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-datetime-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_datetime_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-document.md b/docs/examples/1.4.x/server-python/examples/databases/create-document.md new file mode 100644 index 0000000000..aa95de9ebd --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-document.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_document('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]', {}) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..92cdcb2a8f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-email-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_email_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..df66f12896 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-enum-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_enum_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..0bfe4248eb --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-float-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_float_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-index.md b/docs/examples/1.4.x/server-python/examples/databases/create-index.md new file mode 100644 index 0000000000..78a7d3327e --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-index.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_index('[DATABASE_ID]', '[COLLECTION_ID]', '', 'key', []) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..b3cce2bde4 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-integer-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_integer_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..967d284b9a --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-ip-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_ip_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..4f69ecae00 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-relationship-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_relationship_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '[RELATED_COLLECTION_ID]', 'oneToOne') diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..00bbbe9ce7 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-string-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_string_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', 1, False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..fd5b7f44e3 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create-url-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create_url_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/create.md b/docs/examples/1.4.x/server-python/examples/databases/create.md new file mode 100644 index 0000000000..e4a832066b --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/create.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.create('[DATABASE_ID]', '[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..41871b2662 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/delete-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.delete_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '') diff --git a/docs/examples/1.4.x/server-python/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-python/examples/databases/delete-collection.md new file mode 100644 index 0000000000..998bb61fb9 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/delete-collection.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.delete_collection('[DATABASE_ID]', '[COLLECTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/delete-document.md b/docs/examples/1.4.x/server-python/examples/databases/delete-document.md new file mode 100644 index 0000000000..605b087b7c --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/delete-document.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.delete_document('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/delete-index.md b/docs/examples/1.4.x/server-python/examples/databases/delete-index.md new file mode 100644 index 0000000000..a53e06c024 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/delete-index.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.delete_index('[DATABASE_ID]', '[COLLECTION_ID]', '') diff --git a/docs/examples/1.4.x/server-python/examples/databases/delete.md b/docs/examples/1.4.x/server-python/examples/databases/delete.md new file mode 100644 index 0000000000..780e1451ef --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/delete.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.delete('[DATABASE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/get-attribute.md new file mode 100644 index 0000000000..0a6105272a --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/get-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.get_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '') diff --git a/docs/examples/1.4.x/server-python/examples/databases/get-collection.md b/docs/examples/1.4.x/server-python/examples/databases/get-collection.md new file mode 100644 index 0000000000..90f57a366c --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/get-collection.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.get_collection('[DATABASE_ID]', '[COLLECTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/get-document.md b/docs/examples/1.4.x/server-python/examples/databases/get-document.md new file mode 100644 index 0000000000..708538418e --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/get-document.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.get_document('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/get-index.md b/docs/examples/1.4.x/server-python/examples/databases/get-index.md new file mode 100644 index 0000000000..3213c66660 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/get-index.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.get_index('[DATABASE_ID]', '[COLLECTION_ID]', '') diff --git a/docs/examples/1.4.x/server-python/examples/databases/get.md b/docs/examples/1.4.x/server-python/examples/databases/get.md new file mode 100644 index 0000000000..93a46b3fa4 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/get.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.get('[DATABASE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-python/examples/databases/list-attributes.md new file mode 100644 index 0000000000..632202c894 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/list-attributes.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.list_attributes('[DATABASE_ID]', '[COLLECTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/list-collections.md b/docs/examples/1.4.x/server-python/examples/databases/list-collections.md new file mode 100644 index 0000000000..d0c98dad97 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/list-collections.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.list_collections('[DATABASE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/list-documents.md b/docs/examples/1.4.x/server-python/examples/databases/list-documents.md new file mode 100644 index 0000000000..5eb03b2658 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/list-documents.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.list_documents('[DATABASE_ID]', '[COLLECTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-python/examples/databases/list-indexes.md new file mode 100644 index 0000000000..b4224be62c --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/list-indexes.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.list_indexes('[DATABASE_ID]', '[COLLECTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/list.md b/docs/examples/1.4.x/server-python/examples/databases/list.md new file mode 100644 index 0000000000..3aa6839d20 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/list.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.list() diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..e6a7d55fb6 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-boolean-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_boolean_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False, False) diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-collection.md b/docs/examples/1.4.x/server-python/examples/databases/update-collection.md new file mode 100644 index 0000000000..4a38aab4d4 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-collection.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_collection('[DATABASE_ID]', '[COLLECTION_ID]', '[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..5c792573ae --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-datetime-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_datetime_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False, '') diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-document.md b/docs/examples/1.4.x/server-python/examples/databases/update-document.md new file mode 100644 index 0000000000..c768c5403c --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-document.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_document('[DATABASE_ID]', '[COLLECTION_ID]', '[DOCUMENT_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..8148b012fd --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-email-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_email_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False, 'email@example.com') diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..65ef26f274 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-enum-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_enum_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', [], False, '[DEFAULT]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..efbf1ad04f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-float-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_float_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False, None, None, None) diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..61c74b8675 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-integer-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_integer_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False, None, None, None) diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..7d5a35d749 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-ip-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_ip_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False, '') diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..7c426a61e3 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-relationship-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_relationship_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '') diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..2ee236e624 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-string-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_string_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False, '[DEFAULT]') diff --git a/docs/examples/1.4.x/server-python/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-python/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..119c787d2d --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update-url-attribute.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update_url_attribute('[DATABASE_ID]', '[COLLECTION_ID]', '', False, 'https://example.com') diff --git a/docs/examples/1.4.x/server-python/examples/databases/update.md b/docs/examples/1.4.x/server-python/examples/databases/update.md new file mode 100644 index 0000000000..d46692ece4 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/databases/update.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +databases = Databases(client) + +result = databases.update('[DATABASE_ID]', '[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/create-build.md b/docs/examples/1.4.x/server-python/examples/functions/create-build.md new file mode 100644 index 0000000000..76888f8b16 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/create-build.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.create_build('[FUNCTION_ID]', '[DEPLOYMENT_ID]', '[BUILD_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-python/examples/functions/create-deployment.md new file mode 100644 index 0000000000..1ee1be05ed --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/create-deployment.md @@ -0,0 +1,15 @@ +from appwrite.client import Client +from appwrite.input_file import InputFile +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.create_deployment('[FUNCTION_ID]', InputFile.from_path('file.png'), False) diff --git a/docs/examples/1.4.x/server-python/examples/functions/create-execution.md b/docs/examples/1.4.x/server-python/examples/functions/create-execution.md new file mode 100644 index 0000000000..7c045225b3 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/create-execution.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.create_execution('[FUNCTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/create-variable.md b/docs/examples/1.4.x/server-python/examples/functions/create-variable.md new file mode 100644 index 0000000000..f33ed08a71 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/create-variable.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.create_variable('[FUNCTION_ID]', '[KEY]', '[VALUE]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/create.md b/docs/examples/1.4.x/server-python/examples/functions/create.md new file mode 100644 index 0000000000..fa6f46ddc1 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/create.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.create('[FUNCTION_ID]', '[NAME]', 'node-14.5') diff --git a/docs/examples/1.4.x/server-python/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-python/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..42d526eca9 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/delete-deployment.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.delete_deployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-python/examples/functions/delete-variable.md new file mode 100644 index 0000000000..cae0f2df9f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/delete-variable.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.delete_variable('[FUNCTION_ID]', '[VARIABLE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/delete.md b/docs/examples/1.4.x/server-python/examples/functions/delete.md new file mode 100644 index 0000000000..e89213ec7a --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/delete.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.delete('[FUNCTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-python/examples/functions/download-deployment.md new file mode 100644 index 0000000000..ee51f67936 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/download-deployment.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.download_deployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-python/examples/functions/get-deployment.md new file mode 100644 index 0000000000..6257b59d2e --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/get-deployment.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.get_deployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/get-execution.md b/docs/examples/1.4.x/server-python/examples/functions/get-execution.md new file mode 100644 index 0000000000..f0e4f0dc67 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/get-execution.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.get_execution('[FUNCTION_ID]', '[EXECUTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/get-variable.md b/docs/examples/1.4.x/server-python/examples/functions/get-variable.md new file mode 100644 index 0000000000..4e71bff24f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/get-variable.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.get_variable('[FUNCTION_ID]', '[VARIABLE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/get.md b/docs/examples/1.4.x/server-python/examples/functions/get.md new file mode 100644 index 0000000000..30e1d5959a --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/get.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.get('[FUNCTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-python/examples/functions/list-deployments.md new file mode 100644 index 0000000000..d1797a18b3 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/list-deployments.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.list_deployments('[FUNCTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/list-executions.md b/docs/examples/1.4.x/server-python/examples/functions/list-executions.md new file mode 100644 index 0000000000..d70f004478 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/list-executions.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.list_executions('[FUNCTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-python/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..19b85e2369 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/list-runtimes.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.list_runtimes() diff --git a/docs/examples/1.4.x/server-python/examples/functions/list-variables.md b/docs/examples/1.4.x/server-python/examples/functions/list-variables.md new file mode 100644 index 0000000000..9a72bba9f8 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/list-variables.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.list_variables('[FUNCTION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/list.md b/docs/examples/1.4.x/server-python/examples/functions/list.md new file mode 100644 index 0000000000..b8442e5ade --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/list.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.list() diff --git a/docs/examples/1.4.x/server-python/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-python/examples/functions/update-deployment.md new file mode 100644 index 0000000000..87dd09710f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/update-deployment.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.update_deployment('[FUNCTION_ID]', '[DEPLOYMENT_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/update-variable.md b/docs/examples/1.4.x/server-python/examples/functions/update-variable.md new file mode 100644 index 0000000000..ab5b43abce --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/update-variable.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.update_variable('[FUNCTION_ID]', '[VARIABLE_ID]', '[KEY]') diff --git a/docs/examples/1.4.x/server-python/examples/functions/update.md b/docs/examples/1.4.x/server-python/examples/functions/update.md new file mode 100644 index 0000000000..1da900890a --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/functions/update.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.functions import Functions + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +functions = Functions(client) + +result = functions.update('[FUNCTION_ID]', '[NAME]', 'node-14.5') diff --git a/docs/examples/1.4.x/server-python/examples/graphql/mutation.md b/docs/examples/1.4.x/server-python/examples/graphql/mutation.md new file mode 100644 index 0000000000..24226a5a01 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/graphql/mutation.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.graphql import Graphql + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +graphql = Graphql(client) + +result = graphql.mutation({}) diff --git a/docs/examples/1.4.x/server-python/examples/graphql/query.md b/docs/examples/1.4.x/server-python/examples/graphql/query.md new file mode 100644 index 0000000000..8e1597c759 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/graphql/query.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.graphql import Graphql + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +graphql = Graphql(client) + +result = graphql.query({}) diff --git a/docs/examples/1.4.x/server-python/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-python/examples/health/get-antivirus.md new file mode 100644 index 0000000000..fbfaf0e52e --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-antivirus.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_antivirus() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-cache.md b/docs/examples/1.4.x/server-python/examples/health/get-cache.md new file mode 100644 index 0000000000..40bc01000b --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-cache.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_cache() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-d-b.md b/docs/examples/1.4.x/server-python/examples/health/get-d-b.md new file mode 100644 index 0000000000..803dd73bd3 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-d-b.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_db() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-python/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..43ada69a0f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-pub-sub.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_pub_sub() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-python/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..4fb0266d11 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-queue-certificates.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_queue_certificates() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-python/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..92e4e2021d --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-queue-functions.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_queue_functions() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-python/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..b798ad7332 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-queue-logs.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_queue_logs() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-python/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..8406de1ff8 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-queue-webhooks.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_queue_webhooks() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-queue.md b/docs/examples/1.4.x/server-python/examples/health/get-queue.md new file mode 100644 index 0000000000..5a35588163 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-queue.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_queue() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-python/examples/health/get-storage-local.md new file mode 100644 index 0000000000..bb2533e27f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-storage-local.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_storage_local() diff --git a/docs/examples/1.4.x/server-python/examples/health/get-time.md b/docs/examples/1.4.x/server-python/examples/health/get-time.md new file mode 100644 index 0000000000..9fe313dd5f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get-time.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get_time() diff --git a/docs/examples/1.4.x/server-python/examples/health/get.md b/docs/examples/1.4.x/server-python/examples/health/get.md new file mode 100644 index 0000000000..d3ff594387 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/health/get.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.health import Health + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +health = Health(client) + +result = health.get() diff --git a/docs/examples/1.4.x/server-python/examples/locale/get.md b/docs/examples/1.4.x/server-python/examples/locale/get.md new file mode 100644 index 0000000000..06b04f2f63 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/locale/get.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.locale import Locale + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +locale = Locale(client) + +result = locale.get() diff --git a/docs/examples/1.4.x/server-python/examples/locale/list-codes.md b/docs/examples/1.4.x/server-python/examples/locale/list-codes.md new file mode 100644 index 0000000000..3dc6cf8327 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/locale/list-codes.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.locale import Locale + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +locale = Locale(client) + +result = locale.list_codes() diff --git a/docs/examples/1.4.x/server-python/examples/locale/list-continents.md b/docs/examples/1.4.x/server-python/examples/locale/list-continents.md new file mode 100644 index 0000000000..ba9c94f8a9 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/locale/list-continents.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.locale import Locale + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +locale = Locale(client) + +result = locale.list_continents() diff --git a/docs/examples/1.4.x/server-python/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-python/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..ea4c43cab6 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/locale/list-countries-e-u.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.locale import Locale + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +locale = Locale(client) + +result = locale.list_countries_eu() diff --git a/docs/examples/1.4.x/server-python/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-python/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..5a4cafe520 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/locale/list-countries-phones.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.locale import Locale + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +locale = Locale(client) + +result = locale.list_countries_phones() diff --git a/docs/examples/1.4.x/server-python/examples/locale/list-countries.md b/docs/examples/1.4.x/server-python/examples/locale/list-countries.md new file mode 100644 index 0000000000..f8ec83c83e --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/locale/list-countries.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.locale import Locale + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +locale = Locale(client) + +result = locale.list_countries() diff --git a/docs/examples/1.4.x/server-python/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-python/examples/locale/list-currencies.md new file mode 100644 index 0000000000..347e81c54c --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/locale/list-currencies.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.locale import Locale + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +locale = Locale(client) + +result = locale.list_currencies() diff --git a/docs/examples/1.4.x/server-python/examples/locale/list-languages.md b/docs/examples/1.4.x/server-python/examples/locale/list-languages.md new file mode 100644 index 0000000000..ce50a6efe7 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/locale/list-languages.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.locale import Locale + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +locale = Locale(client) + +result = locale.list_languages() diff --git a/docs/examples/1.4.x/server-python/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-python/examples/storage/create-bucket.md new file mode 100644 index 0000000000..72ffdccbd8 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/create-bucket.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.create_bucket('[BUCKET_ID]', '[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/create-file.md b/docs/examples/1.4.x/server-python/examples/storage/create-file.md new file mode 100644 index 0000000000..b469b5bdd5 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/create-file.md @@ -0,0 +1,15 @@ +from appwrite.client import Client +from appwrite.input_file import InputFile +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.create_file('[BUCKET_ID]', '[FILE_ID]', InputFile.from_path('file.png')) diff --git a/docs/examples/1.4.x/server-python/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-python/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..60dc1074fd --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/delete-bucket.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.delete_bucket('[BUCKET_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/delete-file.md b/docs/examples/1.4.x/server-python/examples/storage/delete-file.md new file mode 100644 index 0000000000..9bed0af784 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/delete-file.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.delete_file('[BUCKET_ID]', '[FILE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-python/examples/storage/get-bucket.md new file mode 100644 index 0000000000..7ea64f22aa --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/get-bucket.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.get_bucket('[BUCKET_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-python/examples/storage/get-file-download.md new file mode 100644 index 0000000000..e9f5cce824 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/get-file-download.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.get_file_download('[BUCKET_ID]', '[FILE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-python/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..4e12291f13 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/get-file-preview.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.get_file_preview('[BUCKET_ID]', '[FILE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-python/examples/storage/get-file-view.md new file mode 100644 index 0000000000..01cbfafd26 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/get-file-view.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.get_file_view('[BUCKET_ID]', '[FILE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/get-file.md b/docs/examples/1.4.x/server-python/examples/storage/get-file.md new file mode 100644 index 0000000000..f83ed8aa61 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/get-file.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.get_file('[BUCKET_ID]', '[FILE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-python/examples/storage/list-buckets.md new file mode 100644 index 0000000000..204fd9598c --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/list-buckets.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.list_buckets() diff --git a/docs/examples/1.4.x/server-python/examples/storage/list-files.md b/docs/examples/1.4.x/server-python/examples/storage/list-files.md new file mode 100644 index 0000000000..63101e215e --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/list-files.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.list_files('[BUCKET_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-python/examples/storage/update-bucket.md new file mode 100644 index 0000000000..fb1b76b222 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/update-bucket.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.update_bucket('[BUCKET_ID]', '[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/storage/update-file.md b/docs/examples/1.4.x/server-python/examples/storage/update-file.md new file mode 100644 index 0000000000..24a92e36c6 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/storage/update-file.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.storage import Storage + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +storage = Storage(client) + +result = storage.update_file('[BUCKET_ID]', '[FILE_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/create-membership.md b/docs/examples/1.4.x/server-python/examples/teams/create-membership.md new file mode 100644 index 0000000000..57682383f7 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/create-membership.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.create_membership('[TEAM_ID]', [], 'https://example.com') diff --git a/docs/examples/1.4.x/server-python/examples/teams/create.md b/docs/examples/1.4.x/server-python/examples/teams/create.md new file mode 100644 index 0000000000..c69012359f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/create.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.create('[TEAM_ID]', '[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-python/examples/teams/delete-membership.md new file mode 100644 index 0000000000..f8d875986f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/delete-membership.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.delete_membership('[TEAM_ID]', '[MEMBERSHIP_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/delete.md b/docs/examples/1.4.x/server-python/examples/teams/delete.md new file mode 100644 index 0000000000..4fc0fa44cc --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/delete.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.delete('[TEAM_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/get-membership.md b/docs/examples/1.4.x/server-python/examples/teams/get-membership.md new file mode 100644 index 0000000000..e9c62ae3e3 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/get-membership.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.get_membership('[TEAM_ID]', '[MEMBERSHIP_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-python/examples/teams/get-prefs.md new file mode 100644 index 0000000000..40909fa7d8 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/get-prefs.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +teams = Teams(client) + +result = teams.get_prefs('[TEAM_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/get.md b/docs/examples/1.4.x/server-python/examples/teams/get.md new file mode 100644 index 0000000000..fdca2fc28f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/get.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.get('[TEAM_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-python/examples/teams/list-memberships.md new file mode 100644 index 0000000000..63e662a7a6 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/list-memberships.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.list_memberships('[TEAM_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/list.md b/docs/examples/1.4.x/server-python/examples/teams/list.md new file mode 100644 index 0000000000..e60cb60dab --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/list.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.list() diff --git a/docs/examples/1.4.x/server-python/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-python/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..a6cd4cd45f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/update-membership-status.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +teams = Teams(client) + +result = teams.update_membership_status('[TEAM_ID]', '[MEMBERSHIP_ID]', '[USER_ID]', '[SECRET]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/update-membership.md b/docs/examples/1.4.x/server-python/examples/teams/update-membership.md new file mode 100644 index 0000000000..816c6ad894 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/update-membership.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.update_membership('[TEAM_ID]', '[MEMBERSHIP_ID]', []) diff --git a/docs/examples/1.4.x/server-python/examples/teams/update-name.md b/docs/examples/1.4.x/server-python/examples/teams/update-name.md new file mode 100644 index 0000000000..929f4ecb48 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/update-name.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +teams = Teams(client) + +result = teams.update_name('[TEAM_ID]', '[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-python/examples/teams/update-prefs.md new file mode 100644 index 0000000000..4176c622a0 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/teams/update-prefs.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.teams import Teams + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token +) + +teams = Teams(client) + +result = teams.update_prefs('[TEAM_ID]', {}) diff --git a/docs/examples/1.4.x/server-python/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-python/examples/users/create-argon2user.md new file mode 100644 index 0000000000..be1e8cef36 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/create-argon2user.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.create_argon2_user('[USER_ID]', 'email@example.com', 'password') diff --git a/docs/examples/1.4.x/server-python/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-python/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..77c9918879 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/create-bcrypt-user.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.create_bcrypt_user('[USER_ID]', 'email@example.com', 'password') diff --git a/docs/examples/1.4.x/server-python/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-python/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..f3ab3f8418 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/create-m-d5user.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.create_md5_user('[USER_ID]', 'email@example.com', 'password') diff --git a/docs/examples/1.4.x/server-python/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-python/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..e715f47c14 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/create-p-h-pass-user.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.create_ph_pass_user('[USER_ID]', 'email@example.com', 'password') diff --git a/docs/examples/1.4.x/server-python/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-python/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..2a2db5a673 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/create-s-h-a-user.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.create_sha_user('[USER_ID]', 'email@example.com', 'password') diff --git a/docs/examples/1.4.x/server-python/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-python/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..0b42e98dc7 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.create_scrypt_modified_user('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', '[PASSWORD_SALT_SEPARATOR]', '[PASSWORD_SIGNER_KEY]') diff --git a/docs/examples/1.4.x/server-python/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-python/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..b445623018 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/create-scrypt-user.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.create_scrypt_user('[USER_ID]', 'email@example.com', 'password', '[PASSWORD_SALT]', None, None, None, None) diff --git a/docs/examples/1.4.x/server-python/examples/users/create.md b/docs/examples/1.4.x/server-python/examples/users/create.md new file mode 100644 index 0000000000..05249c08ea --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/create.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.create('[USER_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/delete-identity.md b/docs/examples/1.4.x/server-python/examples/users/delete-identity.md new file mode 100644 index 0000000000..d1038248ab --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/delete-identity.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.delete_identity('[IDENTITY_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/delete-session.md b/docs/examples/1.4.x/server-python/examples/users/delete-session.md new file mode 100644 index 0000000000..26b041db1d --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/delete-session.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.delete_session('[USER_ID]', '[SESSION_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-python/examples/users/delete-sessions.md new file mode 100644 index 0000000000..dabe4f627d --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/delete-sessions.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.delete_sessions('[USER_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/delete.md b/docs/examples/1.4.x/server-python/examples/users/delete.md new file mode 100644 index 0000000000..7fdc77576b --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/delete.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.delete('[USER_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/get-prefs.md b/docs/examples/1.4.x/server-python/examples/users/get-prefs.md new file mode 100644 index 0000000000..2bbaa88c59 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/get-prefs.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.get_prefs('[USER_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/get.md b/docs/examples/1.4.x/server-python/examples/users/get.md new file mode 100644 index 0000000000..463957d394 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/get.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.get('[USER_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/list-identities.md b/docs/examples/1.4.x/server-python/examples/users/list-identities.md new file mode 100644 index 0000000000..0addd3ec8a --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/list-identities.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.list_identities() diff --git a/docs/examples/1.4.x/server-python/examples/users/list-logs.md b/docs/examples/1.4.x/server-python/examples/users/list-logs.md new file mode 100644 index 0000000000..ca3a5eb815 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/list-logs.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.list_logs('[USER_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/list-memberships.md b/docs/examples/1.4.x/server-python/examples/users/list-memberships.md new file mode 100644 index 0000000000..0dfb97afce --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/list-memberships.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.list_memberships('[USER_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/list-sessions.md b/docs/examples/1.4.x/server-python/examples/users/list-sessions.md new file mode 100644 index 0000000000..5f8fbd68ea --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/list-sessions.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.list_sessions('[USER_ID]') diff --git a/docs/examples/1.4.x/server-python/examples/users/list.md b/docs/examples/1.4.x/server-python/examples/users/list.md new file mode 100644 index 0000000000..baaf42c574 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/list.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.list() diff --git a/docs/examples/1.4.x/server-python/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-python/examples/users/update-email-verification.md new file mode 100644 index 0000000000..8be33ad97f --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/update-email-verification.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_email_verification('[USER_ID]', False) diff --git a/docs/examples/1.4.x/server-python/examples/users/update-email.md b/docs/examples/1.4.x/server-python/examples/users/update-email.md new file mode 100644 index 0000000000..4899bd3936 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/update-email.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_email('[USER_ID]', 'email@example.com') diff --git a/docs/examples/1.4.x/server-python/examples/users/update-labels.md b/docs/examples/1.4.x/server-python/examples/users/update-labels.md new file mode 100644 index 0000000000..b2d4c2dd01 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/update-labels.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_labels('[USER_ID]', []) diff --git a/docs/examples/1.4.x/server-python/examples/users/update-name.md b/docs/examples/1.4.x/server-python/examples/users/update-name.md new file mode 100644 index 0000000000..66bb6b2920 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/update-name.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_name('[USER_ID]', '[NAME]') diff --git a/docs/examples/1.4.x/server-python/examples/users/update-password.md b/docs/examples/1.4.x/server-python/examples/users/update-password.md new file mode 100644 index 0000000000..e79f1255b8 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/update-password.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_password('[USER_ID]', '') diff --git a/docs/examples/1.4.x/server-python/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-python/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..e42317ca30 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/update-phone-verification.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_phone_verification('[USER_ID]', False) diff --git a/docs/examples/1.4.x/server-python/examples/users/update-phone.md b/docs/examples/1.4.x/server-python/examples/users/update-phone.md new file mode 100644 index 0000000000..6df39fc994 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/update-phone.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_phone('[USER_ID]', '+12065550100') diff --git a/docs/examples/1.4.x/server-python/examples/users/update-prefs.md b/docs/examples/1.4.x/server-python/examples/users/update-prefs.md new file mode 100644 index 0000000000..53d1e524e2 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/update-prefs.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_prefs('[USER_ID]', {}) diff --git a/docs/examples/1.4.x/server-python/examples/users/update-status.md b/docs/examples/1.4.x/server-python/examples/users/update-status.md new file mode 100644 index 0000000000..6d1577d401 --- /dev/null +++ b/docs/examples/1.4.x/server-python/examples/users/update-status.md @@ -0,0 +1,14 @@ +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() + +(client + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key +) + +users = Users(client) + +result = users.update_status('[USER_ID]', False) diff --git a/docs/examples/1.4.x/server-rest/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-rest/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..43512be67f --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/create-phone-verification.md @@ -0,0 +1,7 @@ +POST /v1/account/verification/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/create-recovery.md b/docs/examples/1.4.x/server-rest/examples/account/create-recovery.md new file mode 100644 index 0000000000..2ef165d2d4 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/create-recovery.md @@ -0,0 +1,11 @@ +POST /v1/account/recovery HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "email": "email@example.com", + "url": "https://example.com" +} diff --git a/docs/examples/1.4.x/server-rest/examples/account/create-verification.md b/docs/examples/1.4.x/server-rest/examples/account/create-verification.md new file mode 100644 index 0000000000..81e74312d9 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/create-verification.md @@ -0,0 +1,10 @@ +POST /v1/account/verification HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "url": "https://example.com" +} diff --git a/docs/examples/1.4.x/server-rest/examples/account/delete-identity.md b/docs/examples/1.4.x/server-rest/examples/account/delete-identity.md new file mode 100644 index 0000000000..25db38436b --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/delete-identity.md @@ -0,0 +1,7 @@ +DELETE /v1/account/identities/{identityId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/delete-session.md b/docs/examples/1.4.x/server-rest/examples/account/delete-session.md new file mode 100644 index 0000000000..4783c1983c --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/delete-session.md @@ -0,0 +1,7 @@ +DELETE /v1/account/sessions/{sessionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-rest/examples/account/delete-sessions.md new file mode 100644 index 0000000000..8632a92a29 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/delete-sessions.md @@ -0,0 +1,7 @@ +DELETE /v1/account/sessions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/get-prefs.md b/docs/examples/1.4.x/server-rest/examples/account/get-prefs.md new file mode 100644 index 0000000000..1de7705065 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/get-prefs.md @@ -0,0 +1,7 @@ +GET /v1/account/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/get-session.md b/docs/examples/1.4.x/server-rest/examples/account/get-session.md new file mode 100644 index 0000000000..2953bc7d5b --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/get-session.md @@ -0,0 +1,7 @@ +GET /v1/account/sessions/{sessionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/get.md b/docs/examples/1.4.x/server-rest/examples/account/get.md new file mode 100644 index 0000000000..2cf6ee6937 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/get.md @@ -0,0 +1,7 @@ +GET /v1/account HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/list-identities.md b/docs/examples/1.4.x/server-rest/examples/account/list-identities.md new file mode 100644 index 0000000000..f1fc54d32d --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/list-identities.md @@ -0,0 +1,7 @@ +GET /v1/account/identities HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/list-logs.md b/docs/examples/1.4.x/server-rest/examples/account/list-logs.md new file mode 100644 index 0000000000..811310b9a6 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/list-logs.md @@ -0,0 +1,7 @@ +GET /v1/account/logs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/list-sessions.md b/docs/examples/1.4.x/server-rest/examples/account/list-sessions.md new file mode 100644 index 0000000000..25d7a6247b --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/list-sessions.md @@ -0,0 +1,7 @@ +GET /v1/account/sessions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-email.md b/docs/examples/1.4.x/server-rest/examples/account/update-email.md new file mode 100644 index 0000000000..a9bec63172 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-email.md @@ -0,0 +1,11 @@ +PATCH /v1/account/email HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "email": "email@example.com", + "password": "password" +} diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-name.md b/docs/examples/1.4.x/server-rest/examples/account/update-name.md new file mode 100644 index 0000000000..374f2c8642 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-name.md @@ -0,0 +1,10 @@ +PATCH /v1/account/name HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-password.md b/docs/examples/1.4.x/server-rest/examples/account/update-password.md new file mode 100644 index 0000000000..a15a7d3cde --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-password.md @@ -0,0 +1,11 @@ +PATCH /v1/account/password HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "password": , + "oldPassword": "password" +} diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-rest/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..a87f9cc404 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-phone-verification.md @@ -0,0 +1,11 @@ +PUT /v1/account/verification/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-phone.md b/docs/examples/1.4.x/server-rest/examples/account/update-phone.md new file mode 100644 index 0000000000..90faa9b9f5 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-phone.md @@ -0,0 +1,11 @@ +PATCH /v1/account/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "phone": "+12065550100", + "password": "password" +} diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-prefs.md b/docs/examples/1.4.x/server-rest/examples/account/update-prefs.md new file mode 100644 index 0000000000..83f544e705 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-prefs.md @@ -0,0 +1,10 @@ +PATCH /v1/account/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "prefs": {} +} diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-recovery.md b/docs/examples/1.4.x/server-rest/examples/account/update-recovery.md new file mode 100644 index 0000000000..24cb547aa3 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-recovery.md @@ -0,0 +1,13 @@ +PUT /v1/account/recovery HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]", + "password": "password", + "passwordAgain": "password" +} diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-session.md b/docs/examples/1.4.x/server-rest/examples/account/update-session.md new file mode 100644 index 0000000000..880e5ba7e4 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-session.md @@ -0,0 +1,7 @@ +PATCH /v1/account/sessions/{sessionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-status.md b/docs/examples/1.4.x/server-rest/examples/account/update-status.md new file mode 100644 index 0000000000..5677d65736 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-status.md @@ -0,0 +1,7 @@ +PATCH /v1/account/status HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/account/update-verification.md b/docs/examples/1.4.x/server-rest/examples/account/update-verification.md new file mode 100644 index 0000000000..ed689bf02e --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/account/update-verification.md @@ -0,0 +1,11 @@ +PUT /v1/account/verification HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-rest/examples/avatars/get-browser.md new file mode 100644 index 0000000000..37b093ffeb --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/avatars/get-browser.md @@ -0,0 +1,8 @@ +GET /v1/avatars/browsers/{code} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-rest/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..da3dea1154 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/avatars/get-credit-card.md @@ -0,0 +1,8 @@ +GET /v1/avatars/credit-cards/{code} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-rest/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..6c4005223a --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/avatars/get-favicon.md @@ -0,0 +1,8 @@ +GET /v1/avatars/favicon HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-rest/examples/avatars/get-flag.md new file mode 100644 index 0000000000..6dc45c4a5b --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/avatars/get-flag.md @@ -0,0 +1,8 @@ +GET /v1/avatars/flags/{code} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/avatars/get-image.md b/docs/examples/1.4.x/server-rest/examples/avatars/get-image.md new file mode 100644 index 0000000000..8f7c874750 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/avatars/get-image.md @@ -0,0 +1,8 @@ +GET /v1/avatars/image HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-rest/examples/avatars/get-initials.md new file mode 100644 index 0000000000..80e8ad1753 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/avatars/get-initials.md @@ -0,0 +1,8 @@ +GET /v1/avatars/initials HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-rest/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..7a6da45f10 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/avatars/get-q-r.md @@ -0,0 +1,8 @@ +GET /v1/avatars/qr HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..5c45fdb7c6 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-boolean-attribute.md @@ -0,0 +1,13 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/boolean HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "required": false, + "default": false, + "array": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-collection.md b/docs/examples/1.4.x/server-rest/examples/databases/create-collection.md new file mode 100644 index 0000000000..da4b5c1a39 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-collection.md @@ -0,0 +1,14 @@ +POST /v1/databases/{databaseId}/collections HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "collectionId": "[COLLECTION_ID]", + "name": "[NAME]", + "permissions": ["read(\"any\")"], + "documentSecurity": false, + "enabled": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..0e6f68a1cc --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-datetime-attribute.md @@ -0,0 +1,13 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/datetime HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "required": false, + "default": , + "array": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-document.md b/docs/examples/1.4.x/server-rest/examples/databases/create-document.md new file mode 100644 index 0000000000..6e660cf675 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-document.md @@ -0,0 +1,13 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/documents HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "documentId": "[DOCUMENT_ID]", + "data": {}, + "permissions": ["read(\"any\")"] +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..10c58b3243 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-email-attribute.md @@ -0,0 +1,13 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/email HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "required": false, + "default": "email@example.com", + "array": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..b35d71900d --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-enum-attribute.md @@ -0,0 +1,14 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/enum HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "elements": [], + "required": false, + "default": "[DEFAULT]", + "array": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..0df52a4151 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-float-attribute.md @@ -0,0 +1,15 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/float HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "required": false, + "min": 0, + "max": 0, + "default": 0, + "array": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-index.md b/docs/examples/1.4.x/server-rest/examples/databases/create-index.md new file mode 100644 index 0000000000..1b838dee36 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-index.md @@ -0,0 +1,13 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/indexes HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "type": "key", + "attributes": [], + "orders": [] +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..7f3112b6ba --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-integer-attribute.md @@ -0,0 +1,15 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/integer HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "required": false, + "min": 0, + "max": 0, + "default": 0, + "array": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..533e905a34 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-ip-attribute.md @@ -0,0 +1,13 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/ip HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "required": false, + "default": , + "array": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..988b038e45 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-relationship-attribute.md @@ -0,0 +1,15 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/relationship HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "relatedCollectionId": "[RELATED_COLLECTION_ID]", + "type": "oneToOne", + "twoWay": false, + "key": , + "twoWayKey": , + "onDelete": "cascade" +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..33f8a43044 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-string-attribute.md @@ -0,0 +1,15 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/string HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "size": 1, + "required": false, + "default": "[DEFAULT]", + "array": false, + "encrypt": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..d623119126 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create-url-attribute.md @@ -0,0 +1,13 @@ +POST /v1/databases/{databaseId}/collections/{collectionId}/attributes/url HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": , + "required": false, + "default": "https://example.com", + "array": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/create.md b/docs/examples/1.4.x/server-rest/examples/databases/create.md new file mode 100644 index 0000000000..e38bfe22a3 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/create.md @@ -0,0 +1,12 @@ +POST /v1/databases HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "databaseId": "[DATABASE_ID]", + "name": "[NAME]", + "enabled": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..d0e8fc06cb --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/delete-attribute.md @@ -0,0 +1,7 @@ +DELETE /v1/databases/{databaseId}/collections/{collectionId}/attributes/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-rest/examples/databases/delete-collection.md new file mode 100644 index 0000000000..c91cdd3d6e --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/delete-collection.md @@ -0,0 +1,7 @@ +DELETE /v1/databases/{databaseId}/collections/{collectionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/delete-document.md b/docs/examples/1.4.x/server-rest/examples/databases/delete-document.md new file mode 100644 index 0000000000..7e3ff8ec43 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/delete-document.md @@ -0,0 +1,8 @@ +DELETE /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/delete-index.md b/docs/examples/1.4.x/server-rest/examples/databases/delete-index.md new file mode 100644 index 0000000000..38b2043384 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/delete-index.md @@ -0,0 +1,7 @@ +DELETE /v1/databases/{databaseId}/collections/{collectionId}/indexes/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/delete.md b/docs/examples/1.4.x/server-rest/examples/databases/delete.md new file mode 100644 index 0000000000..4dbcf04fa3 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/delete.md @@ -0,0 +1,7 @@ +DELETE /v1/databases/{databaseId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/get-attribute.md new file mode 100644 index 0000000000..1477108226 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/get-attribute.md @@ -0,0 +1,7 @@ +GET /v1/databases/{databaseId}/collections/{collectionId}/attributes/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/get-collection.md b/docs/examples/1.4.x/server-rest/examples/databases/get-collection.md new file mode 100644 index 0000000000..9735990ca9 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/get-collection.md @@ -0,0 +1,7 @@ +GET /v1/databases/{databaseId}/collections/{collectionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/get-document.md b/docs/examples/1.4.x/server-rest/examples/databases/get-document.md new file mode 100644 index 0000000000..dc31756d75 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/get-document.md @@ -0,0 +1,8 @@ +GET /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/get-index.md b/docs/examples/1.4.x/server-rest/examples/databases/get-index.md new file mode 100644 index 0000000000..4f4c4af634 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/get-index.md @@ -0,0 +1,7 @@ +GET /v1/databases/{databaseId}/collections/{collectionId}/indexes/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/get.md b/docs/examples/1.4.x/server-rest/examples/databases/get.md new file mode 100644 index 0000000000..3006b5008d --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/get.md @@ -0,0 +1,7 @@ +GET /v1/databases/{databaseId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-rest/examples/databases/list-attributes.md new file mode 100644 index 0000000000..d0dc305bb5 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/list-attributes.md @@ -0,0 +1,7 @@ +GET /v1/databases/{databaseId}/collections/{collectionId}/attributes HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/list-collections.md b/docs/examples/1.4.x/server-rest/examples/databases/list-collections.md new file mode 100644 index 0000000000..a250616ea7 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/list-collections.md @@ -0,0 +1,7 @@ +GET /v1/databases/{databaseId}/collections HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/list-documents.md b/docs/examples/1.4.x/server-rest/examples/databases/list-documents.md new file mode 100644 index 0000000000..f3a0b46638 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/list-documents.md @@ -0,0 +1,8 @@ +GET /v1/databases/{databaseId}/collections/{collectionId}/documents HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-rest/examples/databases/list-indexes.md new file mode 100644 index 0000000000..253da29e32 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/list-indexes.md @@ -0,0 +1,7 @@ +GET /v1/databases/{databaseId}/collections/{collectionId}/indexes HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/list.md b/docs/examples/1.4.x/server-rest/examples/databases/list.md new file mode 100644 index 0000000000..559f6ffcba --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/list.md @@ -0,0 +1,7 @@ +GET /v1/databases HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..864c9c0cf2 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-boolean-attribute.md @@ -0,0 +1,11 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/boolean/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "required": false, + "default": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-collection.md b/docs/examples/1.4.x/server-rest/examples/databases/update-collection.md new file mode 100644 index 0000000000..05e7288326 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-collection.md @@ -0,0 +1,13 @@ +PUT /v1/databases/{databaseId}/collections/{collectionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "name": "[NAME]", + "permissions": ["read(\"any\")"], + "documentSecurity": false, + "enabled": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..bfb1d2411b --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-datetime-attribute.md @@ -0,0 +1,11 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/datetime/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "required": false, + "default": +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-document.md b/docs/examples/1.4.x/server-rest/examples/databases/update-document.md new file mode 100644 index 0000000000..573e4fdd33 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-document.md @@ -0,0 +1,12 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "data": {}, + "permissions": ["read(\"any\")"] +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..3c5acefed5 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-email-attribute.md @@ -0,0 +1,11 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/email/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "required": false, + "default": "email@example.com" +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..78d356c2aa --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-enum-attribute.md @@ -0,0 +1,12 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/enum/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "elements": [], + "required": false, + "default": "[DEFAULT]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..536480e339 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-float-attribute.md @@ -0,0 +1,13 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/float/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "required": false, + "min": 0, + "max": 0, + "default": 0 +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..724efd6376 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-integer-attribute.md @@ -0,0 +1,13 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/integer/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "required": false, + "min": 0, + "max": 0, + "default": 0 +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..ec98503cd6 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-ip-attribute.md @@ -0,0 +1,11 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/ip/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "required": false, + "default": +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..de084671cf --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-relationship-attribute.md @@ -0,0 +1,10 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/{key}/relationship HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "onDelete": "cascade" +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..b282ae3e12 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-string-attribute.md @@ -0,0 +1,11 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/string/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "required": false, + "default": "[DEFAULT]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-rest/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..687dc78c75 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update-url-attribute.md @@ -0,0 +1,11 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/attributes/url/{key} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "required": false, + "default": "https://example.com" +} diff --git a/docs/examples/1.4.x/server-rest/examples/databases/update.md b/docs/examples/1.4.x/server-rest/examples/databases/update.md new file mode 100644 index 0000000000..0b485fece6 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/databases/update.md @@ -0,0 +1,11 @@ +PUT /v1/databases/{databaseId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "name": "[NAME]", + "enabled": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/functions/create-build.md b/docs/examples/1.4.x/server-rest/examples/functions/create-build.md new file mode 100644 index 0000000000..356ec4ef7d --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/create-build.md @@ -0,0 +1,7 @@ +POST /v1/functions/{functionId}/deployments/{deploymentId}/builds/{buildId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-rest/examples/functions/create-deployment.md new file mode 100644 index 0000000000..7be546e98e --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/create-deployment.md @@ -0,0 +1,30 @@ +POST /v1/functions/{functionId}/deployments HTTP/1.1 +Host: HOSTNAME +Content-Type: multipart/form-data; boundary="cec8e8123c05ba25" +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +Content-Length: *Length of your entity body in bytes* + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="entrypoint" + +"[ENTRYPOINT]" + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="commands" + +"[COMMANDS]" + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="code" + +cf 94 84 24 8d c4 91 10 0f dc 54 26 6c 8e 4b bc +e8 ee 55 94 29 e7 94 89 19 26 28 01 26 29 3f 16... + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="activate" + +false + +--cec8e8123c05ba25-- diff --git a/docs/examples/1.4.x/server-rest/examples/functions/create-execution.md b/docs/examples/1.4.x/server-rest/examples/functions/create-execution.md new file mode 100644 index 0000000000..307386d7cb --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/create-execution.md @@ -0,0 +1,15 @@ +POST /v1/functions/{functionId}/executions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "body": "[BODY]", + "async": false, + "path": "[PATH]", + "method": "GET", + "headers": {} +} diff --git a/docs/examples/1.4.x/server-rest/examples/functions/create-variable.md b/docs/examples/1.4.x/server-rest/examples/functions/create-variable.md new file mode 100644 index 0000000000..0b4d41db14 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/create-variable.md @@ -0,0 +1,11 @@ +POST /v1/functions/{functionId}/variables HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": "[KEY]", + "value": "[VALUE]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/functions/create.md b/docs/examples/1.4.x/server-rest/examples/functions/create.md new file mode 100644 index 0000000000..0f55041b9e --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/create.md @@ -0,0 +1,29 @@ +POST /v1/functions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "functionId": "[FUNCTION_ID]", + "name": "[NAME]", + "runtime": "node-14.5", + "execute": ["any"], + "events": [], + "schedule": , + "timeout": 1, + "enabled": false, + "logging": false, + "entrypoint": "[ENTRYPOINT]", + "commands": "[COMMANDS]", + "installationId": "[INSTALLATION_ID]", + "providerRepositoryId": "[PROVIDER_REPOSITORY_ID]", + "providerBranch": "[PROVIDER_BRANCH]", + "providerSilentMode": false, + "providerRootDirectory": "[PROVIDER_ROOT_DIRECTORY]", + "templateRepository": "[TEMPLATE_REPOSITORY]", + "templateOwner": "[TEMPLATE_OWNER]", + "templateRootDirectory": "[TEMPLATE_ROOT_DIRECTORY]", + "templateBranch": "[TEMPLATE_BRANCH]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-rest/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..f9a178b3ab --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/delete-deployment.md @@ -0,0 +1,7 @@ +DELETE /v1/functions/{functionId}/deployments/{deploymentId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-rest/examples/functions/delete-variable.md new file mode 100644 index 0000000000..5bb6d50fd2 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/delete-variable.md @@ -0,0 +1,7 @@ +DELETE /v1/functions/{functionId}/variables/{variableId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/delete.md b/docs/examples/1.4.x/server-rest/examples/functions/delete.md new file mode 100644 index 0000000000..fcd6c1d25b --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/delete.md @@ -0,0 +1,7 @@ +DELETE /v1/functions/{functionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-rest/examples/functions/download-deployment.md new file mode 100644 index 0000000000..49e76dd438 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/download-deployment.md @@ -0,0 +1,7 @@ +GET /v1/functions/{functionId}/deployments/{deploymentId}/download HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-rest/examples/functions/get-deployment.md new file mode 100644 index 0000000000..d5d7194a24 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/get-deployment.md @@ -0,0 +1,7 @@ +GET /v1/functions/{functionId}/deployments/{deploymentId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/get-execution.md b/docs/examples/1.4.x/server-rest/examples/functions/get-execution.md new file mode 100644 index 0000000000..59e2f075a5 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/get-execution.md @@ -0,0 +1,8 @@ +GET /v1/functions/{functionId}/executions/{executionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/get-variable.md b/docs/examples/1.4.x/server-rest/examples/functions/get-variable.md new file mode 100644 index 0000000000..8a44fd4fff --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/get-variable.md @@ -0,0 +1,7 @@ +GET /v1/functions/{functionId}/variables/{variableId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/get.md b/docs/examples/1.4.x/server-rest/examples/functions/get.md new file mode 100644 index 0000000000..6afb6c7651 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/get.md @@ -0,0 +1,7 @@ +GET /v1/functions/{functionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-rest/examples/functions/list-deployments.md new file mode 100644 index 0000000000..aed4499c6f --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/list-deployments.md @@ -0,0 +1,7 @@ +GET /v1/functions/{functionId}/deployments HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/list-executions.md b/docs/examples/1.4.x/server-rest/examples/functions/list-executions.md new file mode 100644 index 0000000000..c6777807fc --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/list-executions.md @@ -0,0 +1,8 @@ +GET /v1/functions/{functionId}/executions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-rest/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..1f0b0d917c --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/list-runtimes.md @@ -0,0 +1,7 @@ +GET /v1/functions/runtimes HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/list-variables.md b/docs/examples/1.4.x/server-rest/examples/functions/list-variables.md new file mode 100644 index 0000000000..2757123359 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/list-variables.md @@ -0,0 +1,7 @@ +GET /v1/functions/{functionId}/variables HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/list.md b/docs/examples/1.4.x/server-rest/examples/functions/list.md new file mode 100644 index 0000000000..7a5b470c3a --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/list.md @@ -0,0 +1,7 @@ +GET /v1/functions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-rest/examples/functions/update-deployment.md new file mode 100644 index 0000000000..74b3a5c40b --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/update-deployment.md @@ -0,0 +1,7 @@ +PATCH /v1/functions/{functionId}/deployments/{deploymentId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/functions/update-variable.md b/docs/examples/1.4.x/server-rest/examples/functions/update-variable.md new file mode 100644 index 0000000000..8117ac2a77 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/update-variable.md @@ -0,0 +1,11 @@ +PUT /v1/functions/{functionId}/variables/{variableId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "key": "[KEY]", + "value": "[VALUE]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/functions/update.md b/docs/examples/1.4.x/server-rest/examples/functions/update.md new file mode 100644 index 0000000000..d2cdca21b9 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/functions/update.md @@ -0,0 +1,24 @@ +PUT /v1/functions/{functionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "name": "[NAME]", + "runtime": "node-14.5", + "execute": ["any"], + "events": [], + "schedule": , + "timeout": 1, + "enabled": false, + "logging": false, + "entrypoint": "[ENTRYPOINT]", + "commands": "[COMMANDS]", + "installationId": "[INSTALLATION_ID]", + "providerRepositoryId": "[PROVIDER_REPOSITORY_ID]", + "providerBranch": "[PROVIDER_BRANCH]", + "providerSilentMode": false, + "providerRootDirectory": "[PROVIDER_ROOT_DIRECTORY]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/graphql/mutation.md b/docs/examples/1.4.x/server-rest/examples/graphql/mutation.md new file mode 100644 index 0000000000..8ba1b8cfd1 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/graphql/mutation.md @@ -0,0 +1,12 @@ +POST /v1/graphql/mutation HTTP/1.1 +Host: HOSTNAME +X-Sdk-Graphql: true +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "query": {} +} diff --git a/docs/examples/1.4.x/server-rest/examples/graphql/query.md b/docs/examples/1.4.x/server-rest/examples/graphql/query.md new file mode 100644 index 0000000000..d5bd655080 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/graphql/query.md @@ -0,0 +1,12 @@ +POST /v1/graphql HTTP/1.1 +Host: HOSTNAME +X-Sdk-Graphql: true +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "query": {} +} diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-rest/examples/health/get-antivirus.md new file mode 100644 index 0000000000..7278141759 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-antivirus.md @@ -0,0 +1,7 @@ +GET /v1/health/anti-virus HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-cache.md b/docs/examples/1.4.x/server-rest/examples/health/get-cache.md new file mode 100644 index 0000000000..5c300537d8 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-cache.md @@ -0,0 +1,7 @@ +GET /v1/health/cache HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-d-b.md b/docs/examples/1.4.x/server-rest/examples/health/get-d-b.md new file mode 100644 index 0000000000..69956c8f49 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-d-b.md @@ -0,0 +1,7 @@ +GET /v1/health/db HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-rest/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..4987370d77 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-pub-sub.md @@ -0,0 +1,7 @@ +GET /v1/health/pubsub HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-rest/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..d0ca17fe03 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-queue-certificates.md @@ -0,0 +1,7 @@ +GET /v1/health/queue/certificates HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-rest/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..79c240b5d2 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-queue-functions.md @@ -0,0 +1,7 @@ +GET /v1/health/queue/functions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-rest/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..7597164130 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-queue-logs.md @@ -0,0 +1,7 @@ +GET /v1/health/queue/logs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-rest/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..3257552c52 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-queue-webhooks.md @@ -0,0 +1,7 @@ +GET /v1/health/queue/webhooks HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-queue.md b/docs/examples/1.4.x/server-rest/examples/health/get-queue.md new file mode 100644 index 0000000000..1b76d7ab4c --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-queue.md @@ -0,0 +1,7 @@ +GET /v1/health/queue HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-rest/examples/health/get-storage-local.md new file mode 100644 index 0000000000..e3b89d9d36 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-storage-local.md @@ -0,0 +1,7 @@ +GET /v1/health/storage/local HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get-time.md b/docs/examples/1.4.x/server-rest/examples/health/get-time.md new file mode 100644 index 0000000000..e51d57d2ca --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get-time.md @@ -0,0 +1,7 @@ +GET /v1/health/time HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/health/get.md b/docs/examples/1.4.x/server-rest/examples/health/get.md new file mode 100644 index 0000000000..d7ccd1707f --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/health/get.md @@ -0,0 +1,7 @@ +GET /v1/health HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/locale/get.md b/docs/examples/1.4.x/server-rest/examples/locale/get.md new file mode 100644 index 0000000000..ef2108360c --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/locale/get.md @@ -0,0 +1,8 @@ +GET /v1/locale HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/locale/list-codes.md b/docs/examples/1.4.x/server-rest/examples/locale/list-codes.md new file mode 100644 index 0000000000..15cb593682 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/locale/list-codes.md @@ -0,0 +1,8 @@ +GET /v1/locale/codes HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/locale/list-continents.md b/docs/examples/1.4.x/server-rest/examples/locale/list-continents.md new file mode 100644 index 0000000000..8397d98d15 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/locale/list-continents.md @@ -0,0 +1,8 @@ +GET /v1/locale/continents HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-rest/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..00c7ad223b --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/locale/list-countries-e-u.md @@ -0,0 +1,8 @@ +GET /v1/locale/countries/eu HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-rest/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..34cfc0bce0 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/locale/list-countries-phones.md @@ -0,0 +1,8 @@ +GET /v1/locale/countries/phones HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/locale/list-countries.md b/docs/examples/1.4.x/server-rest/examples/locale/list-countries.md new file mode 100644 index 0000000000..e2821d5350 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/locale/list-countries.md @@ -0,0 +1,8 @@ +GET /v1/locale/countries HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-rest/examples/locale/list-currencies.md new file mode 100644 index 0000000000..df0af85f05 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/locale/list-currencies.md @@ -0,0 +1,8 @@ +GET /v1/locale/currencies HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/locale/list-languages.md b/docs/examples/1.4.x/server-rest/examples/locale/list-languages.md new file mode 100644 index 0000000000..10300b446a --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/locale/list-languages.md @@ -0,0 +1,8 @@ +GET /v1/locale/languages HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-rest/examples/storage/create-bucket.md new file mode 100644 index 0000000000..6bf78a321d --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/create-bucket.md @@ -0,0 +1,19 @@ +POST /v1/storage/buckets HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "bucketId": "[BUCKET_ID]", + "name": "[NAME]", + "permissions": ["read(\"any\")"], + "fileSecurity": false, + "enabled": false, + "maximumFileSize": 1, + "allowedFileExtensions": [], + "compression": "none", + "encryption": false, + "antivirus": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/storage/create-file.md b/docs/examples/1.4.x/server-rest/examples/storage/create-file.md new file mode 100644 index 0000000000..aea83ddfd7 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/create-file.md @@ -0,0 +1,26 @@ +POST /v1/storage/buckets/{bucketId}/files HTTP/1.1 +Host: HOSTNAME +Content-Type: multipart/form-data; boundary="cec8e8123c05ba25" +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... +Content-Length: *Length of your entity body in bytes* + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="fileId" + +"[FILE_ID]" + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="file" + +cf 94 84 24 8d c4 91 10 0f dc 54 26 6c 8e 4b bc +e8 ee 55 94 29 e7 94 89 19 26 28 01 26 29 3f 16... + +--cec8e8123c05ba25 +Content-Disposition: form-data; name="permissions[]" + +["read(\"any\")"] + +--cec8e8123c05ba25-- diff --git a/docs/examples/1.4.x/server-rest/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-rest/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..d8bd329c2f --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/delete-bucket.md @@ -0,0 +1,7 @@ +DELETE /v1/storage/buckets/{bucketId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/delete-file.md b/docs/examples/1.4.x/server-rest/examples/storage/delete-file.md new file mode 100644 index 0000000000..a200a5e4a1 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/delete-file.md @@ -0,0 +1,8 @@ +DELETE /v1/storage/buckets/{bucketId}/files/{fileId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-rest/examples/storage/get-bucket.md new file mode 100644 index 0000000000..3c5b94a0d2 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/get-bucket.md @@ -0,0 +1,7 @@ +GET /v1/storage/buckets/{bucketId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-rest/examples/storage/get-file-download.md new file mode 100644 index 0000000000..d4900613ae --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/get-file-download.md @@ -0,0 +1,8 @@ +GET /v1/storage/buckets/{bucketId}/files/{fileId}/download HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-rest/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..1c5e5aeb65 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/get-file-preview.md @@ -0,0 +1,8 @@ +GET /v1/storage/buckets/{bucketId}/files/{fileId}/preview HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-rest/examples/storage/get-file-view.md new file mode 100644 index 0000000000..fc1da7af32 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/get-file-view.md @@ -0,0 +1,8 @@ +GET /v1/storage/buckets/{bucketId}/files/{fileId}/view HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/get-file.md b/docs/examples/1.4.x/server-rest/examples/storage/get-file.md new file mode 100644 index 0000000000..3002d950e1 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/get-file.md @@ -0,0 +1,8 @@ +GET /v1/storage/buckets/{bucketId}/files/{fileId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-rest/examples/storage/list-buckets.md new file mode 100644 index 0000000000..e094eccc55 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/list-buckets.md @@ -0,0 +1,7 @@ +GET /v1/storage/buckets HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/list-files.md b/docs/examples/1.4.x/server-rest/examples/storage/list-files.md new file mode 100644 index 0000000000..86d50f8802 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/list-files.md @@ -0,0 +1,8 @@ +GET /v1/storage/buckets/{bucketId}/files HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-rest/examples/storage/update-bucket.md new file mode 100644 index 0000000000..e6c69069a3 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/update-bucket.md @@ -0,0 +1,18 @@ +PUT /v1/storage/buckets/{bucketId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "name": "[NAME]", + "permissions": ["read(\"any\")"], + "fileSecurity": false, + "enabled": false, + "maximumFileSize": 1, + "allowedFileExtensions": [], + "compression": "none", + "encryption": false, + "antivirus": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/storage/update-file.md b/docs/examples/1.4.x/server-rest/examples/storage/update-file.md new file mode 100644 index 0000000000..3acf6eb5b2 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/storage/update-file.md @@ -0,0 +1,12 @@ +PUT /v1/storage/buckets/{bucketId}/files/{fileId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "name": "[NAME]", + "permissions": ["read(\"any\")"] +} diff --git a/docs/examples/1.4.x/server-rest/examples/teams/create-membership.md b/docs/examples/1.4.x/server-rest/examples/teams/create-membership.md new file mode 100644 index 0000000000..b52437e464 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/create-membership.md @@ -0,0 +1,16 @@ +POST /v1/teams/{teamId}/memberships HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "email": "email@example.com", + "userId": "[USER_ID]", + "phone": "+12065550100", + "roles": [], + "url": "https://example.com", + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/teams/create.md b/docs/examples/1.4.x/server-rest/examples/teams/create.md new file mode 100644 index 0000000000..2826173726 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/create.md @@ -0,0 +1,13 @@ +POST /v1/teams HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "teamId": "[TEAM_ID]", + "name": "[NAME]", + "roles": [] +} diff --git a/docs/examples/1.4.x/server-rest/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-rest/examples/teams/delete-membership.md new file mode 100644 index 0000000000..9ac5cff637 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/delete-membership.md @@ -0,0 +1,8 @@ +DELETE /v1/teams/{teamId}/memberships/{membershipId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/teams/delete.md b/docs/examples/1.4.x/server-rest/examples/teams/delete.md new file mode 100644 index 0000000000..9995342dfc --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/delete.md @@ -0,0 +1,8 @@ +DELETE /v1/teams/{teamId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/teams/get-membership.md b/docs/examples/1.4.x/server-rest/examples/teams/get-membership.md new file mode 100644 index 0000000000..7317395a54 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/get-membership.md @@ -0,0 +1,8 @@ +GET /v1/teams/{teamId}/memberships/{membershipId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-rest/examples/teams/get-prefs.md new file mode 100644 index 0000000000..bfa1c9c871 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/get-prefs.md @@ -0,0 +1,7 @@ +GET /v1/teams/{teamId}/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/teams/get.md b/docs/examples/1.4.x/server-rest/examples/teams/get.md new file mode 100644 index 0000000000..57605ffbf5 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/get.md @@ -0,0 +1,8 @@ +GET /v1/teams/{teamId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-rest/examples/teams/list-memberships.md new file mode 100644 index 0000000000..bacebc9eac --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/list-memberships.md @@ -0,0 +1,8 @@ +GET /v1/teams/{teamId}/memberships HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/teams/list.md b/docs/examples/1.4.x/server-rest/examples/teams/list.md new file mode 100644 index 0000000000..216ccebcfa --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/list.md @@ -0,0 +1,8 @@ +GET /v1/teams HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + diff --git a/docs/examples/1.4.x/server-rest/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-rest/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..5b3a0e7414 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/update-membership-status.md @@ -0,0 +1,11 @@ +PATCH /v1/teams/{teamId}/memberships/{membershipId}/status HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "userId": "[USER_ID]", + "secret": "[SECRET]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/teams/update-membership.md b/docs/examples/1.4.x/server-rest/examples/teams/update-membership.md new file mode 100644 index 0000000000..7a584b81a1 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/update-membership.md @@ -0,0 +1,11 @@ +PATCH /v1/teams/{teamId}/memberships/{membershipId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "roles": [] +} diff --git a/docs/examples/1.4.x/server-rest/examples/teams/update-name.md b/docs/examples/1.4.x/server-rest/examples/teams/update-name.md new file mode 100644 index 0000000000..15b2c5db49 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/update-name.md @@ -0,0 +1,11 @@ +PUT /v1/teams/{teamId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-rest/examples/teams/update-prefs.md new file mode 100644 index 0000000000..d04ee5aa7b --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/teams/update-prefs.md @@ -0,0 +1,10 @@ +PUT /v1/teams/{teamId}/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + +{ + "prefs": {} +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-rest/examples/users/create-argon2user.md new file mode 100644 index 0000000000..8427c293c4 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/create-argon2user.md @@ -0,0 +1,13 @@ +POST /v1/users/argon2 HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "password": "password", + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-rest/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..84b55586d2 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/create-bcrypt-user.md @@ -0,0 +1,13 @@ +POST /v1/users/bcrypt HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "password": "password", + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-rest/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..cc9ba30bc4 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/create-m-d5user.md @@ -0,0 +1,13 @@ +POST /v1/users/md5 HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "password": "password", + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-rest/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..b3c8465daa --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/create-p-h-pass-user.md @@ -0,0 +1,13 @@ +POST /v1/users/phpass HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "password": "password", + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-rest/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..1593d0c565 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/create-s-h-a-user.md @@ -0,0 +1,14 @@ +POST /v1/users/sha HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "password": "password", + "passwordVersion": "sha1", + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-rest/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..85c779e99d --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,16 @@ +POST /v1/users/scrypt-modified HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "password": "password", + "passwordSalt": "[PASSWORD_SALT]", + "passwordSaltSeparator": "[PASSWORD_SALT_SEPARATOR]", + "passwordSignerKey": "[PASSWORD_SIGNER_KEY]", + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-rest/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..e3c89c1604 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/create-scrypt-user.md @@ -0,0 +1,18 @@ +POST /v1/users/scrypt HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "password": "password", + "passwordSalt": "[PASSWORD_SALT]", + "passwordCpu": 0, + "passwordMemory": 0, + "passwordParallel": 0, + "passwordLength": 0, + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/create.md b/docs/examples/1.4.x/server-rest/examples/users/create.md new file mode 100644 index 0000000000..f213113ac9 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/create.md @@ -0,0 +1,14 @@ +POST /v1/users HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "userId": "[USER_ID]", + "email": "email@example.com", + "phone": "+12065550100", + "password": , + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/delete-identity.md b/docs/examples/1.4.x/server-rest/examples/users/delete-identity.md new file mode 100644 index 0000000000..564d93c729 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/delete-identity.md @@ -0,0 +1,7 @@ +DELETE /v1/users/identities/{identityId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/delete-session.md b/docs/examples/1.4.x/server-rest/examples/users/delete-session.md new file mode 100644 index 0000000000..b44500dd20 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/delete-session.md @@ -0,0 +1,7 @@ +DELETE /v1/users/{userId}/sessions/{sessionId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-rest/examples/users/delete-sessions.md new file mode 100644 index 0000000000..9efbbe2924 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/delete-sessions.md @@ -0,0 +1,7 @@ +DELETE /v1/users/{userId}/sessions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/delete.md b/docs/examples/1.4.x/server-rest/examples/users/delete.md new file mode 100644 index 0000000000..3b6a1854a4 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/delete.md @@ -0,0 +1,7 @@ +DELETE /v1/users/{userId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/get-prefs.md b/docs/examples/1.4.x/server-rest/examples/users/get-prefs.md new file mode 100644 index 0000000000..ecba746af9 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/get-prefs.md @@ -0,0 +1,7 @@ +GET /v1/users/{userId}/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/get.md b/docs/examples/1.4.x/server-rest/examples/users/get.md new file mode 100644 index 0000000000..117d56425f --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/get.md @@ -0,0 +1,7 @@ +GET /v1/users/{userId} HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/list-identities.md b/docs/examples/1.4.x/server-rest/examples/users/list-identities.md new file mode 100644 index 0000000000..369d72b713 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/list-identities.md @@ -0,0 +1,7 @@ +GET /v1/users/identities HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/list-logs.md b/docs/examples/1.4.x/server-rest/examples/users/list-logs.md new file mode 100644 index 0000000000..8feebf59ed --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/list-logs.md @@ -0,0 +1,7 @@ +GET /v1/users/{userId}/logs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/list-memberships.md b/docs/examples/1.4.x/server-rest/examples/users/list-memberships.md new file mode 100644 index 0000000000..27aad07c52 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/list-memberships.md @@ -0,0 +1,7 @@ +GET /v1/users/{userId}/memberships HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/list-sessions.md b/docs/examples/1.4.x/server-rest/examples/users/list-sessions.md new file mode 100644 index 0000000000..6b19eb10b8 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/list-sessions.md @@ -0,0 +1,7 @@ +GET /v1/users/{userId}/sessions HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/list.md b/docs/examples/1.4.x/server-rest/examples/users/list.md new file mode 100644 index 0000000000..6b12d12ca1 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/list.md @@ -0,0 +1,7 @@ +GET /v1/users HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + diff --git a/docs/examples/1.4.x/server-rest/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-rest/examples/users/update-email-verification.md new file mode 100644 index 0000000000..3b5461757e --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/update-email-verification.md @@ -0,0 +1,10 @@ +PATCH /v1/users/{userId}/verification HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "emailVerification": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/update-email.md b/docs/examples/1.4.x/server-rest/examples/users/update-email.md new file mode 100644 index 0000000000..a68c31fc01 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/update-email.md @@ -0,0 +1,10 @@ +PATCH /v1/users/{userId}/email HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "email": "email@example.com" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/update-labels.md b/docs/examples/1.4.x/server-rest/examples/users/update-labels.md new file mode 100644 index 0000000000..3a19def940 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/update-labels.md @@ -0,0 +1,10 @@ +PUT /v1/users/{userId}/labels HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "labels": [] +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/update-name.md b/docs/examples/1.4.x/server-rest/examples/users/update-name.md new file mode 100644 index 0000000000..b138435c31 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/update-name.md @@ -0,0 +1,10 @@ +PATCH /v1/users/{userId}/name HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "name": "[NAME]" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/update-password.md b/docs/examples/1.4.x/server-rest/examples/users/update-password.md new file mode 100644 index 0000000000..f8b0184ce9 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/update-password.md @@ -0,0 +1,10 @@ +PATCH /v1/users/{userId}/password HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "password": +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-rest/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..0a2173db32 --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/update-phone-verification.md @@ -0,0 +1,10 @@ +PATCH /v1/users/{userId}/verification/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "phoneVerification": false +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/update-phone.md b/docs/examples/1.4.x/server-rest/examples/users/update-phone.md new file mode 100644 index 0000000000..1e7b7be8fd --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/update-phone.md @@ -0,0 +1,10 @@ +PATCH /v1/users/{userId}/phone HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "number": "+12065550100" +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/update-prefs.md b/docs/examples/1.4.x/server-rest/examples/users/update-prefs.md new file mode 100644 index 0000000000..fd1a0c6bfa --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/update-prefs.md @@ -0,0 +1,10 @@ +PATCH /v1/users/{userId}/prefs HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "prefs": {} +} diff --git a/docs/examples/1.4.x/server-rest/examples/users/update-status.md b/docs/examples/1.4.x/server-rest/examples/users/update-status.md new file mode 100644 index 0000000000..6ae20142be --- /dev/null +++ b/docs/examples/1.4.x/server-rest/examples/users/update-status.md @@ -0,0 +1,10 @@ +PATCH /v1/users/{userId}/status HTTP/1.1 +Host: HOSTNAME +Content-Type: application/json +X-Appwrite-Response-Format: 1.4.0 +X-Appwrite-Project: 5df5acd0d48c2 +X-Appwrite-Key: 919c2d18fb5d4...a2ae413da83346ad2 + +{ + "status": false +} diff --git a/docs/examples/1.4.x/server-ruby/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-ruby/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..7ec0a1c0c9 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/create-phone-verification.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.create_phone_verification() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/create-recovery.md b/docs/examples/1.4.x/server-ruby/examples/account/create-recovery.md new file mode 100644 index 0000000000..5c6d13c724 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/create-recovery.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.create_recovery(email: 'email@example.com', url: 'https://example.com') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/create-verification.md b/docs/examples/1.4.x/server-ruby/examples/account/create-verification.md new file mode 100644 index 0000000000..dcd9722e47 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/create-verification.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.create_verification(url: 'https://example.com') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/delete-identity.md b/docs/examples/1.4.x/server-ruby/examples/account/delete-identity.md new file mode 100644 index 0000000000..1dcb89a030 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/delete-identity.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.delete_identity(identity_id: '[IDENTITY_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/delete-session.md b/docs/examples/1.4.x/server-ruby/examples/account/delete-session.md new file mode 100644 index 0000000000..3357b2ba20 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/delete-session.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.delete_session(session_id: '[SESSION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-ruby/examples/account/delete-sessions.md new file mode 100644 index 0000000000..b218a536db --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/delete-sessions.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.delete_sessions() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/get-prefs.md b/docs/examples/1.4.x/server-ruby/examples/account/get-prefs.md new file mode 100644 index 0000000000..24092b922b --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/get-prefs.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.get_prefs() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/get-session.md b/docs/examples/1.4.x/server-ruby/examples/account/get-session.md new file mode 100644 index 0000000000..2a8209031d --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/get-session.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.get_session(session_id: '[SESSION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/get.md b/docs/examples/1.4.x/server-ruby/examples/account/get.md new file mode 100644 index 0000000000..61237b2215 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/get.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.get() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/list-identities.md b/docs/examples/1.4.x/server-ruby/examples/account/list-identities.md new file mode 100644 index 0000000000..a7173abf11 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/list-identities.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.list_identities() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/list-logs.md b/docs/examples/1.4.x/server-ruby/examples/account/list-logs.md new file mode 100644 index 0000000000..8a08eb96be --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/list-logs.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.list_logs() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/list-sessions.md b/docs/examples/1.4.x/server-ruby/examples/account/list-sessions.md new file mode 100644 index 0000000000..a6bcb6816d --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/list-sessions.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.list_sessions() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-email.md b/docs/examples/1.4.x/server-ruby/examples/account/update-email.md new file mode 100644 index 0000000000..cd2e10cbbe --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-email.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_email(email: 'email@example.com', password: 'password') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-name.md b/docs/examples/1.4.x/server-ruby/examples/account/update-name.md new file mode 100644 index 0000000000..2685e88cf6 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-name.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_name(name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-password.md b/docs/examples/1.4.x/server-ruby/examples/account/update-password.md new file mode 100644 index 0000000000..6ec26f407a --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-password.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_password(password: '') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-ruby/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..103b32c00d --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-phone-verification.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_phone_verification(user_id: '[USER_ID]', secret: '[SECRET]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-phone.md b/docs/examples/1.4.x/server-ruby/examples/account/update-phone.md new file mode 100644 index 0000000000..377c578dea --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-phone.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_phone(phone: '+12065550100', password: 'password') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-prefs.md b/docs/examples/1.4.x/server-ruby/examples/account/update-prefs.md new file mode 100644 index 0000000000..338a9704f1 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-prefs.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_prefs(prefs: {}) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-recovery.md b/docs/examples/1.4.x/server-ruby/examples/account/update-recovery.md new file mode 100644 index 0000000000..fa901de857 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-recovery.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_recovery(user_id: '[USER_ID]', secret: '[SECRET]', password: 'password', password_again: 'password') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-session.md b/docs/examples/1.4.x/server-ruby/examples/account/update-session.md new file mode 100644 index 0000000000..31dde2e94f --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-session.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_session(session_id: '[SESSION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-status.md b/docs/examples/1.4.x/server-ruby/examples/account/update-status.md new file mode 100644 index 0000000000..ea7a3857b5 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-status.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_status() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/account/update-verification.md b/docs/examples/1.4.x/server-ruby/examples/account/update-verification.md new file mode 100644 index 0000000000..b8f674ec77 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/account/update-verification.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +account = Account.new(client) + +response = account.update_verification(user_id: '[USER_ID]', secret: '[SECRET]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-ruby/examples/avatars/get-browser.md new file mode 100644 index 0000000000..2a66b46b92 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/avatars/get-browser.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +avatars = Avatars.new(client) + +response = avatars.get_browser(code: 'aa') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-ruby/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..d5bcaa824f --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/avatars/get-credit-card.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +avatars = Avatars.new(client) + +response = avatars.get_credit_card(code: 'amex') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-ruby/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..c995fb2036 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/avatars/get-favicon.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +avatars = Avatars.new(client) + +response = avatars.get_favicon(url: 'https://example.com') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-ruby/examples/avatars/get-flag.md new file mode 100644 index 0000000000..7633756425 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/avatars/get-flag.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +avatars = Avatars.new(client) + +response = avatars.get_flag(code: 'af') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/avatars/get-image.md b/docs/examples/1.4.x/server-ruby/examples/avatars/get-image.md new file mode 100644 index 0000000000..4ea52a60e4 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/avatars/get-image.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +avatars = Avatars.new(client) + +response = avatars.get_image(url: 'https://example.com') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-ruby/examples/avatars/get-initials.md new file mode 100644 index 0000000000..62a8ff855d --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/avatars/get-initials.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +avatars = Avatars.new(client) + +response = avatars.get_initials() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-ruby/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..03a1f14aa9 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/avatars/get-q-r.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +avatars = Avatars.new(client) + +response = avatars.get_qr(text: '[TEXT]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..d617d8e322 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-boolean-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_boolean_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-collection.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-collection.md new file mode 100644 index 0000000000..d27e43ad66 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-collection.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..127d2ac2d7 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-datetime-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_datetime_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-document.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-document.md new file mode 100644 index 0000000000..8177fc4b3b --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-document.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]', data: {}) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..c7e1aac86b --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-email-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_email_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..36f8ee06d4 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-enum-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_enum_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', elements: [], required: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..771d281ccf --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-float-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_float_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-index.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-index.md new file mode 100644 index 0000000000..5488e36f74 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-index.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_index(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', type: 'key', attributes: []) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..40649c25f8 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-integer-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_integer_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..ef9e0feba5 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-ip-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_ip_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..573ab10ddc --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-relationship-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_relationship_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', related_collection_id: '[RELATED_COLLECTION_ID]', type: 'oneToOne') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..9901c84b02 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-string-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_string_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', size: 1, required: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..475421fe53 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create-url-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create_url_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/create.md b/docs/examples/1.4.x/server-ruby/examples/databases/create.md new file mode 100644 index 0000000000..1ce19d3125 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/create.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.create(database_id: '[DATABASE_ID]', name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..ae2e32d8bd --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/delete-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.delete_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-ruby/examples/databases/delete-collection.md new file mode 100644 index 0000000000..f118667b6e --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/delete-collection.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.delete_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/delete-document.md b/docs/examples/1.4.x/server-ruby/examples/databases/delete-document.md new file mode 100644 index 0000000000..0b7baa89ed --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/delete-document.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.delete_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/delete-index.md b/docs/examples/1.4.x/server-ruby/examples/databases/delete-index.md new file mode 100644 index 0000000000..829e606135 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/delete-index.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.delete_index(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/delete.md b/docs/examples/1.4.x/server-ruby/examples/databases/delete.md new file mode 100644 index 0000000000..7e0c4211f1 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/delete.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.delete(database_id: '[DATABASE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/get-attribute.md new file mode 100644 index 0000000000..525c8f14cd --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/get-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.get_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/get-collection.md b/docs/examples/1.4.x/server-ruby/examples/databases/get-collection.md new file mode 100644 index 0000000000..897e40d109 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/get-collection.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.get_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/get-document.md b/docs/examples/1.4.x/server-ruby/examples/databases/get-document.md new file mode 100644 index 0000000000..d5853aba56 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/get-document.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.get_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/get-index.md b/docs/examples/1.4.x/server-ruby/examples/databases/get-index.md new file mode 100644 index 0000000000..3217507541 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/get-index.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.get_index(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/get.md b/docs/examples/1.4.x/server-ruby/examples/databases/get.md new file mode 100644 index 0000000000..ced51d6ad1 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/get.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.get(database_id: '[DATABASE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-ruby/examples/databases/list-attributes.md new file mode 100644 index 0000000000..1b57bda217 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/list-attributes.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.list_attributes(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/list-collections.md b/docs/examples/1.4.x/server-ruby/examples/databases/list-collections.md new file mode 100644 index 0000000000..3d646c47e7 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/list-collections.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.list_collections(database_id: '[DATABASE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/list-documents.md b/docs/examples/1.4.x/server-ruby/examples/databases/list-documents.md new file mode 100644 index 0000000000..6f57bb150c --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/list-documents.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.list_documents(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-ruby/examples/databases/list-indexes.md new file mode 100644 index 0000000000..d64b3bfc68 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/list-indexes.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.list_indexes(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/list.md b/docs/examples/1.4.x/server-ruby/examples/databases/list.md new file mode 100644 index 0000000000..84baa108a3 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/list.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.list() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..7a7f01a854 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-boolean-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_boolean_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-collection.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-collection.md new file mode 100644 index 0000000000..eee4058531 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-collection.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..c9f9aa759b --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-datetime-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_datetime_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: '') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-document.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-document.md new file mode 100644 index 0000000000..dbe1b0d71a --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-document.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..de2d4c0749 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-email-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_email_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: 'email@example.com') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..e248a5bcf7 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-enum-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_enum_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', elements: [], required: false, default: '[DEFAULT]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..555355d6cb --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-float-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_float_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, min: null, max: null, default: null) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..154daf330e --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-integer-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_integer_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, min: null, max: null, default: null) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..a6fe4d95bc --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-ip-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_ip_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: '') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..9c51daa3a5 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-relationship-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_relationship_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..e5f2f8f09d --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-string-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_string_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: '[DEFAULT]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-ruby/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..da21dcbfb0 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update-url-attribute.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update_url_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: 'https://example.com') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/databases/update.md b/docs/examples/1.4.x/server-ruby/examples/databases/update.md new file mode 100644 index 0000000000..0900ab3428 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/databases/update.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +databases = Databases.new(client) + +response = databases.update(database_id: '[DATABASE_ID]', name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/create-build.md b/docs/examples/1.4.x/server-ruby/examples/functions/create-build.md new file mode 100644 index 0000000000..9c7397bf26 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/create-build.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.create_build(function_id: '[FUNCTION_ID]', deployment_id: '[DEPLOYMENT_ID]', build_id: '[BUILD_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-ruby/examples/functions/create-deployment.md new file mode 100644 index 0000000000..33a74f8ee6 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/create-deployment.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.create_deployment(function_id: '[FUNCTION_ID]', code: InputFile.from_path('dir/file.png'), activate: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/create-execution.md b/docs/examples/1.4.x/server-ruby/examples/functions/create-execution.md new file mode 100644 index 0000000000..97f4d74ba1 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/create-execution.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.create_execution(function_id: '[FUNCTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/create-variable.md b/docs/examples/1.4.x/server-ruby/examples/functions/create-variable.md new file mode 100644 index 0000000000..003fb4743a --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/create-variable.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.create_variable(function_id: '[FUNCTION_ID]', key: '[KEY]', value: '[VALUE]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/create.md b/docs/examples/1.4.x/server-ruby/examples/functions/create.md new file mode 100644 index 0000000000..3f9b84d60e --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/create.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.create(function_id: '[FUNCTION_ID]', name: '[NAME]', runtime: 'node-14.5') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-ruby/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..64feea1370 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/delete-deployment.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.delete_deployment(function_id: '[FUNCTION_ID]', deployment_id: '[DEPLOYMENT_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-ruby/examples/functions/delete-variable.md new file mode 100644 index 0000000000..598e694141 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/delete-variable.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.delete_variable(function_id: '[FUNCTION_ID]', variable_id: '[VARIABLE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/delete.md b/docs/examples/1.4.x/server-ruby/examples/functions/delete.md new file mode 100644 index 0000000000..48ea5c7a73 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/delete.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.delete(function_id: '[FUNCTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-ruby/examples/functions/download-deployment.md new file mode 100644 index 0000000000..7bcb4dda58 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/download-deployment.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.download_deployment(function_id: '[FUNCTION_ID]', deployment_id: '[DEPLOYMENT_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-ruby/examples/functions/get-deployment.md new file mode 100644 index 0000000000..c19163e7f5 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/get-deployment.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.get_deployment(function_id: '[FUNCTION_ID]', deployment_id: '[DEPLOYMENT_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/get-execution.md b/docs/examples/1.4.x/server-ruby/examples/functions/get-execution.md new file mode 100644 index 0000000000..3deee91574 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/get-execution.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.get_execution(function_id: '[FUNCTION_ID]', execution_id: '[EXECUTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/get-variable.md b/docs/examples/1.4.x/server-ruby/examples/functions/get-variable.md new file mode 100644 index 0000000000..835fc30d81 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/get-variable.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.get_variable(function_id: '[FUNCTION_ID]', variable_id: '[VARIABLE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/get.md b/docs/examples/1.4.x/server-ruby/examples/functions/get.md new file mode 100644 index 0000000000..cfcf8411e5 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/get.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.get(function_id: '[FUNCTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-ruby/examples/functions/list-deployments.md new file mode 100644 index 0000000000..539301c4bb --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/list-deployments.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.list_deployments(function_id: '[FUNCTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/list-executions.md b/docs/examples/1.4.x/server-ruby/examples/functions/list-executions.md new file mode 100644 index 0000000000..c0c1f46cf1 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/list-executions.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.list_executions(function_id: '[FUNCTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-ruby/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..b679da2d8b --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/list-runtimes.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.list_runtimes() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/list-variables.md b/docs/examples/1.4.x/server-ruby/examples/functions/list-variables.md new file mode 100644 index 0000000000..4e5bfab891 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/list-variables.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.list_variables(function_id: '[FUNCTION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/list.md b/docs/examples/1.4.x/server-ruby/examples/functions/list.md new file mode 100644 index 0000000000..2cc71a5c04 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/list.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.list() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-ruby/examples/functions/update-deployment.md new file mode 100644 index 0000000000..c9d9f49d63 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/update-deployment.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.update_deployment(function_id: '[FUNCTION_ID]', deployment_id: '[DEPLOYMENT_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/update-variable.md b/docs/examples/1.4.x/server-ruby/examples/functions/update-variable.md new file mode 100644 index 0000000000..28d7651a46 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/update-variable.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.update_variable(function_id: '[FUNCTION_ID]', variable_id: '[VARIABLE_ID]', key: '[KEY]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/functions/update.md b/docs/examples/1.4.x/server-ruby/examples/functions/update.md new file mode 100644 index 0000000000..30929d484d --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/functions/update.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +functions = Functions.new(client) + +response = functions.update(function_id: '[FUNCTION_ID]', name: '[NAME]', runtime: 'node-14.5') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/graphql/mutation.md b/docs/examples/1.4.x/server-ruby/examples/graphql/mutation.md new file mode 100644 index 0000000000..234dfe6202 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/graphql/mutation.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +graphql = Graphql.new(client) + +response = graphql.mutation(query: {}) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/graphql/query.md b/docs/examples/1.4.x/server-ruby/examples/graphql/query.md new file mode 100644 index 0000000000..1304213caf --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/graphql/query.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +graphql = Graphql.new(client) + +response = graphql.query(query: {}) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-ruby/examples/health/get-antivirus.md new file mode 100644 index 0000000000..b1f16bb0b9 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-antivirus.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_antivirus() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-cache.md b/docs/examples/1.4.x/server-ruby/examples/health/get-cache.md new file mode 100644 index 0000000000..4fb77ec68d --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-cache.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_cache() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-d-b.md b/docs/examples/1.4.x/server-ruby/examples/health/get-d-b.md new file mode 100644 index 0000000000..3317acd6fa --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-d-b.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_db() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-ruby/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..98e834be9e --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-pub-sub.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_pub_sub() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-ruby/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..a4c5c7016b --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-queue-certificates.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_queue_certificates() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-ruby/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..8edb310a5e --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-queue-functions.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_queue_functions() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-ruby/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..74823fcd6c --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-queue-logs.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_queue_logs() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-ruby/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..53b7f33cfe --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-queue-webhooks.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_queue_webhooks() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-queue.md b/docs/examples/1.4.x/server-ruby/examples/health/get-queue.md new file mode 100644 index 0000000000..dfa3c966a4 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-queue.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_queue() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-ruby/examples/health/get-storage-local.md new file mode 100644 index 0000000000..3a85bd3e12 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-storage-local.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_storage_local() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get-time.md b/docs/examples/1.4.x/server-ruby/examples/health/get-time.md new file mode 100644 index 0000000000..9956a33d1f --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get-time.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get_time() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/health/get.md b/docs/examples/1.4.x/server-ruby/examples/health/get.md new file mode 100644 index 0000000000..d23a9ad675 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/health/get.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +health = Health.new(client) + +response = health.get() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/locale/get.md b/docs/examples/1.4.x/server-ruby/examples/locale/get.md new file mode 100644 index 0000000000..e5922f4e7f --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/locale/get.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +locale = Locale.new(client) + +response = locale.get() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/locale/list-codes.md b/docs/examples/1.4.x/server-ruby/examples/locale/list-codes.md new file mode 100644 index 0000000000..3463252405 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/locale/list-codes.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +locale = Locale.new(client) + +response = locale.list_codes() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/locale/list-continents.md b/docs/examples/1.4.x/server-ruby/examples/locale/list-continents.md new file mode 100644 index 0000000000..0416baf77a --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/locale/list-continents.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +locale = Locale.new(client) + +response = locale.list_continents() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-ruby/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..7faa85143c --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/locale/list-countries-e-u.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +locale = Locale.new(client) + +response = locale.list_countries_eu() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-ruby/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..1194f27e0c --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/locale/list-countries-phones.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +locale = Locale.new(client) + +response = locale.list_countries_phones() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/locale/list-countries.md b/docs/examples/1.4.x/server-ruby/examples/locale/list-countries.md new file mode 100644 index 0000000000..b78fba47fd --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/locale/list-countries.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +locale = Locale.new(client) + +response = locale.list_countries() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-ruby/examples/locale/list-currencies.md new file mode 100644 index 0000000000..14b2722ae8 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/locale/list-currencies.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +locale = Locale.new(client) + +response = locale.list_currencies() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/locale/list-languages.md b/docs/examples/1.4.x/server-ruby/examples/locale/list-languages.md new file mode 100644 index 0000000000..4d88bc4723 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/locale/list-languages.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +locale = Locale.new(client) + +response = locale.list_languages() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-ruby/examples/storage/create-bucket.md new file mode 100644 index 0000000000..d6299db79f --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/create-bucket.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.create_bucket(bucket_id: '[BUCKET_ID]', name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/create-file.md b/docs/examples/1.4.x/server-ruby/examples/storage/create-file.md new file mode 100644 index 0000000000..851ed57a48 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/create-file.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.create_file(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]', file: InputFile.from_path('dir/file.png')) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-ruby/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..3fd51bef5e --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/delete-bucket.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.delete_bucket(bucket_id: '[BUCKET_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/delete-file.md b/docs/examples/1.4.x/server-ruby/examples/storage/delete-file.md new file mode 100644 index 0000000000..4d0e3fcbff --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/delete-file.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.delete_file(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-ruby/examples/storage/get-bucket.md new file mode 100644 index 0000000000..ba88debc61 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/get-bucket.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.get_bucket(bucket_id: '[BUCKET_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-ruby/examples/storage/get-file-download.md new file mode 100644 index 0000000000..a22f4cb68f --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/get-file-download.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.get_file_download(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-ruby/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..c5b7c06db1 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/get-file-preview.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.get_file_preview(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-ruby/examples/storage/get-file-view.md new file mode 100644 index 0000000000..c05770b999 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/get-file-view.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.get_file_view(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/get-file.md b/docs/examples/1.4.x/server-ruby/examples/storage/get-file.md new file mode 100644 index 0000000000..a33835c9e2 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/get-file.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.get_file(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-ruby/examples/storage/list-buckets.md new file mode 100644 index 0000000000..7009d0a105 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/list-buckets.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.list_buckets() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/list-files.md b/docs/examples/1.4.x/server-ruby/examples/storage/list-files.md new file mode 100644 index 0000000000..196831a1b3 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/list-files.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.list_files(bucket_id: '[BUCKET_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-ruby/examples/storage/update-bucket.md new file mode 100644 index 0000000000..f990ab3566 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/update-bucket.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.update_bucket(bucket_id: '[BUCKET_ID]', name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/storage/update-file.md b/docs/examples/1.4.x/server-ruby/examples/storage/update-file.md new file mode 100644 index 0000000000..8108d3cc28 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/storage/update-file.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +storage = Storage.new(client) + +response = storage.update_file(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/create-membership.md b/docs/examples/1.4.x/server-ruby/examples/teams/create-membership.md new file mode 100644 index 0000000000..30f343c5d8 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/create-membership.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.create_membership(team_id: '[TEAM_ID]', roles: [], url: 'https://example.com') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/create.md b/docs/examples/1.4.x/server-ruby/examples/teams/create.md new file mode 100644 index 0000000000..d2dff77f41 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/create.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.create(team_id: '[TEAM_ID]', name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-ruby/examples/teams/delete-membership.md new file mode 100644 index 0000000000..d41175d4a8 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/delete-membership.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.delete_membership(team_id: '[TEAM_ID]', membership_id: '[MEMBERSHIP_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/delete.md b/docs/examples/1.4.x/server-ruby/examples/teams/delete.md new file mode 100644 index 0000000000..c1b9b8d8bb --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/delete.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.delete(team_id: '[TEAM_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/get-membership.md b/docs/examples/1.4.x/server-ruby/examples/teams/get-membership.md new file mode 100644 index 0000000000..b06101dd84 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/get-membership.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.get_membership(team_id: '[TEAM_ID]', membership_id: '[MEMBERSHIP_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-ruby/examples/teams/get-prefs.md new file mode 100644 index 0000000000..d4317e8dba --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/get-prefs.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +teams = Teams.new(client) + +response = teams.get_prefs(team_id: '[TEAM_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/get.md b/docs/examples/1.4.x/server-ruby/examples/teams/get.md new file mode 100644 index 0000000000..7cee601b56 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/get.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.get(team_id: '[TEAM_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-ruby/examples/teams/list-memberships.md new file mode 100644 index 0000000000..885a857d72 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/list-memberships.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.list_memberships(team_id: '[TEAM_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/list.md b/docs/examples/1.4.x/server-ruby/examples/teams/list.md new file mode 100644 index 0000000000..e8b581fd91 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/list.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.list() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-ruby/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..aaf52cbb9c --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/update-membership-status.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +teams = Teams.new(client) + +response = teams.update_membership_status(team_id: '[TEAM_ID]', membership_id: '[MEMBERSHIP_ID]', user_id: '[USER_ID]', secret: '[SECRET]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/update-membership.md b/docs/examples/1.4.x/server-ruby/examples/teams/update-membership.md new file mode 100644 index 0000000000..4117aa0aed --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/update-membership.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.update_membership(team_id: '[TEAM_ID]', membership_id: '[MEMBERSHIP_ID]', roles: []) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/update-name.md b/docs/examples/1.4.x/server-ruby/examples/teams/update-name.md new file mode 100644 index 0000000000..41766d6872 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/update-name.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +teams = Teams.new(client) + +response = teams.update_name(team_id: '[TEAM_ID]', name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-ruby/examples/teams/update-prefs.md new file mode 100644 index 0000000000..7656edcd8b --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/teams/update-prefs.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') # Your secret JSON Web Token + +teams = Teams.new(client) + +response = teams.update_prefs(team_id: '[TEAM_ID]', prefs: {}) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-ruby/examples/users/create-argon2user.md new file mode 100644 index 0000000000..9c4fc9ea97 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/create-argon2user.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.create_argon2_user(user_id: '[USER_ID]', email: 'email@example.com', password: 'password') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-ruby/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..700fe49d12 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/create-bcrypt-user.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.create_bcrypt_user(user_id: '[USER_ID]', email: 'email@example.com', password: 'password') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-ruby/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..a7f9c4f7a2 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/create-m-d5user.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.create_md5_user(user_id: '[USER_ID]', email: 'email@example.com', password: 'password') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-ruby/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..d7d8ba1933 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/create-p-h-pass-user.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.create_ph_pass_user(user_id: '[USER_ID]', email: 'email@example.com', password: 'password') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-ruby/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..2d37fc3bfa --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/create-s-h-a-user.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.create_sha_user(user_id: '[USER_ID]', email: 'email@example.com', password: 'password') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-ruby/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..cec9dbb277 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.create_scrypt_modified_user(user_id: '[USER_ID]', email: 'email@example.com', password: 'password', password_salt: '[PASSWORD_SALT]', password_salt_separator: '[PASSWORD_SALT_SEPARATOR]', password_signer_key: '[PASSWORD_SIGNER_KEY]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-ruby/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..94a7af53d2 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/create-scrypt-user.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.create_scrypt_user(user_id: '[USER_ID]', email: 'email@example.com', password: 'password', password_salt: '[PASSWORD_SALT]', password_cpu: null, password_memory: null, password_parallel: null, password_length: null) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/create.md b/docs/examples/1.4.x/server-ruby/examples/users/create.md new file mode 100644 index 0000000000..b04fd5025f --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/create.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.create(user_id: '[USER_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/delete-identity.md b/docs/examples/1.4.x/server-ruby/examples/users/delete-identity.md new file mode 100644 index 0000000000..b1405ddf2a --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/delete-identity.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.delete_identity(identity_id: '[IDENTITY_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/delete-session.md b/docs/examples/1.4.x/server-ruby/examples/users/delete-session.md new file mode 100644 index 0000000000..3b7918ca1f --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/delete-session.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.delete_session(user_id: '[USER_ID]', session_id: '[SESSION_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-ruby/examples/users/delete-sessions.md new file mode 100644 index 0000000000..6772e3fe10 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/delete-sessions.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.delete_sessions(user_id: '[USER_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/delete.md b/docs/examples/1.4.x/server-ruby/examples/users/delete.md new file mode 100644 index 0000000000..62585db404 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/delete.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.delete(user_id: '[USER_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/get-prefs.md b/docs/examples/1.4.x/server-ruby/examples/users/get-prefs.md new file mode 100644 index 0000000000..a4c4764bef --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/get-prefs.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.get_prefs(user_id: '[USER_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/get.md b/docs/examples/1.4.x/server-ruby/examples/users/get.md new file mode 100644 index 0000000000..a731ada955 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/get.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.get(user_id: '[USER_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/list-identities.md b/docs/examples/1.4.x/server-ruby/examples/users/list-identities.md new file mode 100644 index 0000000000..c087063269 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/list-identities.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.list_identities() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/list-logs.md b/docs/examples/1.4.x/server-ruby/examples/users/list-logs.md new file mode 100644 index 0000000000..fa8586eeff --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/list-logs.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.list_logs(user_id: '[USER_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/list-memberships.md b/docs/examples/1.4.x/server-ruby/examples/users/list-memberships.md new file mode 100644 index 0000000000..693e6b9f2c --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/list-memberships.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.list_memberships(user_id: '[USER_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/list-sessions.md b/docs/examples/1.4.x/server-ruby/examples/users/list-sessions.md new file mode 100644 index 0000000000..765789a0da --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/list-sessions.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.list_sessions(user_id: '[USER_ID]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/list.md b/docs/examples/1.4.x/server-ruby/examples/users/list.md new file mode 100644 index 0000000000..8d5daf21f8 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/list.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.list() + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-ruby/examples/users/update-email-verification.md new file mode 100644 index 0000000000..72ec0195dc --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/update-email-verification.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_email_verification(user_id: '[USER_ID]', email_verification: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/update-email.md b/docs/examples/1.4.x/server-ruby/examples/users/update-email.md new file mode 100644 index 0000000000..a3a7dbde34 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/update-email.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_email(user_id: '[USER_ID]', email: 'email@example.com') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/update-labels.md b/docs/examples/1.4.x/server-ruby/examples/users/update-labels.md new file mode 100644 index 0000000000..f94cd1bcaf --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/update-labels.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_labels(user_id: '[USER_ID]', labels: []) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/update-name.md b/docs/examples/1.4.x/server-ruby/examples/users/update-name.md new file mode 100644 index 0000000000..fbf00bb51b --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/update-name.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_name(user_id: '[USER_ID]', name: '[NAME]') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/update-password.md b/docs/examples/1.4.x/server-ruby/examples/users/update-password.md new file mode 100644 index 0000000000..7310a2a0cc --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/update-password.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_password(user_id: '[USER_ID]', password: '') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-ruby/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..995a32a4bf --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/update-phone-verification.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_phone_verification(user_id: '[USER_ID]', phone_verification: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/update-phone.md b/docs/examples/1.4.x/server-ruby/examples/users/update-phone.md new file mode 100644 index 0000000000..f1e74b4a9e --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/update-phone.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_phone(user_id: '[USER_ID]', number: '+12065550100') + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/update-prefs.md b/docs/examples/1.4.x/server-ruby/examples/users/update-prefs.md new file mode 100644 index 0000000000..9845cdf0d5 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/update-prefs.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_prefs(user_id: '[USER_ID]', prefs: {}) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-ruby/examples/users/update-status.md b/docs/examples/1.4.x/server-ruby/examples/users/update-status.md new file mode 100644 index 0000000000..8a82948c76 --- /dev/null +++ b/docs/examples/1.4.x/server-ruby/examples/users/update-status.md @@ -0,0 +1,14 @@ +require 'Appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint + .set_project('5df5acd0d48c2') # Your project ID + .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key + +users = Users.new(client) + +response = users.update_status(user_id: '[USER_ID]', status: false) + +puts response.inspect \ No newline at end of file diff --git a/docs/examples/1.4.x/server-swift/examples/account/create-phone-verification.md b/docs/examples/1.4.x/server-swift/examples/account/create-phone-verification.md new file mode 100644 index 0000000000..cdeba91700 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/create-phone-verification.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let token = try await account.createPhoneVerification() + diff --git a/docs/examples/1.4.x/server-swift/examples/account/create-recovery.md b/docs/examples/1.4.x/server-swift/examples/account/create-recovery.md new file mode 100644 index 0000000000..fdb0e53765 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/create-recovery.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let token = try await account.createRecovery( + email: "email@example.com", + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/create-verification.md b/docs/examples/1.4.x/server-swift/examples/account/create-verification.md new file mode 100644 index 0000000000..63a6a7ac94 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/create-verification.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let token = try await account.createVerification( + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/delete-identity.md b/docs/examples/1.4.x/server-swift/examples/account/delete-identity.md new file mode 100644 index 0000000000..1ebcc46a7a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/delete-identity.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let result = try await account.deleteIdentity( + identityId: "[IDENTITY_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/delete-session.md b/docs/examples/1.4.x/server-swift/examples/account/delete-session.md new file mode 100644 index 0000000000..de9f736f9c --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/delete-session.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let result = try await account.deleteSession( + sessionId: "[SESSION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/delete-sessions.md b/docs/examples/1.4.x/server-swift/examples/account/delete-sessions.md new file mode 100644 index 0000000000..0f58c600d2 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/delete-sessions.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let result = try await account.deleteSessions() + diff --git a/docs/examples/1.4.x/server-swift/examples/account/get-prefs.md b/docs/examples/1.4.x/server-swift/examples/account/get-prefs.md new file mode 100644 index 0000000000..ce72d7c340 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/get-prefs.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let preferences = try await account.getPrefs() + diff --git a/docs/examples/1.4.x/server-swift/examples/account/get-session.md b/docs/examples/1.4.x/server-swift/examples/account/get-session.md new file mode 100644 index 0000000000..e1b48b5aa5 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/get-session.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let session = try await account.getSession( + sessionId: "[SESSION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/get.md b/docs/examples/1.4.x/server-swift/examples/account/get.md new file mode 100644 index 0000000000..060b6a4a27 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/get.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let user = try await account.get() + diff --git a/docs/examples/1.4.x/server-swift/examples/account/list-identities.md b/docs/examples/1.4.x/server-swift/examples/account/list-identities.md new file mode 100644 index 0000000000..4158e54b08 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/list-identities.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let identityList = try await account.listIdentities() + diff --git a/docs/examples/1.4.x/server-swift/examples/account/list-logs.md b/docs/examples/1.4.x/server-swift/examples/account/list-logs.md new file mode 100644 index 0000000000..ee2e8bb7e6 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/list-logs.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let logList = try await account.listLogs() + diff --git a/docs/examples/1.4.x/server-swift/examples/account/list-sessions.md b/docs/examples/1.4.x/server-swift/examples/account/list-sessions.md new file mode 100644 index 0000000000..2baf5836a2 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/list-sessions.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let sessionList = try await account.listSessions() + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-email.md b/docs/examples/1.4.x/server-swift/examples/account/update-email.md new file mode 100644 index 0000000000..4041da0222 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-email.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let user = try await account.updateEmail( + email: "email@example.com", + password: "password" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-name.md b/docs/examples/1.4.x/server-swift/examples/account/update-name.md new file mode 100644 index 0000000000..440b1b6c24 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-name.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let user = try await account.updateName( + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-password.md b/docs/examples/1.4.x/server-swift/examples/account/update-password.md new file mode 100644 index 0000000000..91d55db20f --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-password.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let user = try await account.updatePassword( + password: "" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-phone-verification.md b/docs/examples/1.4.x/server-swift/examples/account/update-phone-verification.md new file mode 100644 index 0000000000..29052c573a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-phone-verification.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let token = try await account.updatePhoneVerification( + userId: "[USER_ID]", + secret: "[SECRET]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-phone.md b/docs/examples/1.4.x/server-swift/examples/account/update-phone.md new file mode 100644 index 0000000000..645b6fc840 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-phone.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let user = try await account.updatePhone( + phone: "+12065550100", + password: "password" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-prefs.md b/docs/examples/1.4.x/server-swift/examples/account/update-prefs.md new file mode 100644 index 0000000000..520f9d5fd4 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-prefs.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let user = try await account.updatePrefs( + prefs: [:] +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-recovery.md b/docs/examples/1.4.x/server-swift/examples/account/update-recovery.md new file mode 100644 index 0000000000..92825cae55 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-recovery.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let token = try await account.updateRecovery( + userId: "[USER_ID]", + secret: "[SECRET]", + password: "password", + passwordAgain: "password" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-session.md b/docs/examples/1.4.x/server-swift/examples/account/update-session.md new file mode 100644 index 0000000000..84229182aa --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-session.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let session = try await account.updateSession( + sessionId: "[SESSION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-status.md b/docs/examples/1.4.x/server-swift/examples/account/update-status.md new file mode 100644 index 0000000000..96b94d63a1 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-status.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let user = try await account.updateStatus() + diff --git a/docs/examples/1.4.x/server-swift/examples/account/update-verification.md b/docs/examples/1.4.x/server-swift/examples/account/update-verification.md new file mode 100644 index 0000000000..b8e925783e --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/account/update-verification.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let account = Account(client) + +let token = try await account.updateVerification( + userId: "[USER_ID]", + secret: "[SECRET]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/avatars/get-browser.md b/docs/examples/1.4.x/server-swift/examples/avatars/get-browser.md new file mode 100644 index 0000000000..df3a99c67a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/avatars/get-browser.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getBrowser( + code: "aa" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/avatars/get-credit-card.md b/docs/examples/1.4.x/server-swift/examples/avatars/get-credit-card.md new file mode 100644 index 0000000000..ce4382d77b --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/avatars/get-credit-card.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getCreditCard( + code: "amex" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/avatars/get-favicon.md b/docs/examples/1.4.x/server-swift/examples/avatars/get-favicon.md new file mode 100644 index 0000000000..36c77218b7 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/avatars/get-favicon.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getFavicon( + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/avatars/get-flag.md b/docs/examples/1.4.x/server-swift/examples/avatars/get-flag.md new file mode 100644 index 0000000000..849ec48cea --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/avatars/get-flag.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getFlag( + code: "af" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/avatars/get-image.md b/docs/examples/1.4.x/server-swift/examples/avatars/get-image.md new file mode 100644 index 0000000000..d457976f54 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/avatars/get-image.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getImage( + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/avatars/get-initials.md b/docs/examples/1.4.x/server-swift/examples/avatars/get-initials.md new file mode 100644 index 0000000000..74d8d956db --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/avatars/get-initials.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getInitials() + diff --git a/docs/examples/1.4.x/server-swift/examples/avatars/get-q-r.md b/docs/examples/1.4.x/server-swift/examples/avatars/get-q-r.md new file mode 100644 index 0000000000..537bfb5b43 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/avatars/get-q-r.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let avatars = Avatars(client) + +let byteBuffer = try await avatars.getQR( + text: "[TEXT]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-boolean-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-boolean-attribute.md new file mode 100644 index 0000000000..11eae088e7 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-boolean-attribute.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeBoolean = try await databases.createBooleanAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-collection.md b/docs/examples/1.4.x/server-swift/examples/databases/create-collection.md new file mode 100644 index 0000000000..ff9172bb29 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-collection.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let collection = try await databases.createCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-datetime-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-datetime-attribute.md new file mode 100644 index 0000000000..26020fb88f --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-datetime-attribute.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeDatetime = try await databases.createDatetimeAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-document.md b/docs/examples/1.4.x/server-swift/examples/databases/create-document.md new file mode 100644 index 0000000000..b76eab7c70 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-document.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let document = try await databases.createDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]", + data: [:] +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-email-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-email-attribute.md new file mode 100644 index 0000000000..cddebec6b2 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-email-attribute.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeEmail = try await databases.createEmailAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-enum-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-enum-attribute.md new file mode 100644 index 0000000000..dc56bff395 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-enum-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeEnum = try await databases.createEnumAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + elements: [], + required: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-float-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-float-attribute.md new file mode 100644 index 0000000000..ec01499e98 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-float-attribute.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeFloat = try await databases.createFloatAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-index.md b/docs/examples/1.4.x/server-swift/examples/databases/create-index.md new file mode 100644 index 0000000000..03cc91b0b4 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-index.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let index = try await databases.createIndex( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + type: "key", + attributes: [] +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-integer-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-integer-attribute.md new file mode 100644 index 0000000000..eeea1cb01b --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-integer-attribute.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeInteger = try await databases.createIntegerAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-ip-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-ip-attribute.md new file mode 100644 index 0000000000..948aa2ad37 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-ip-attribute.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeIp = try await databases.createIpAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-relationship-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-relationship-attribute.md new file mode 100644 index 0000000000..adb7cbb1fc --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-relationship-attribute.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeRelationship = try await databases.createRelationshipAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + relatedCollectionId: "[RELATED_COLLECTION_ID]", + type: "oneToOne" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-string-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-string-attribute.md new file mode 100644 index 0000000000..0d3e65442b --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-string-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeString = try await databases.createStringAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + size: 1, + required: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create-url-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/create-url-attribute.md new file mode 100644 index 0000000000..747a6c7367 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create-url-attribute.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeUrl = try await databases.createUrlAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/create.md b/docs/examples/1.4.x/server-swift/examples/databases/create.md new file mode 100644 index 0000000000..5e4abf88a0 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/create.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let database = try await databases.create( + databaseId: "[DATABASE_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/delete-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/delete-attribute.md new file mode 100644 index 0000000000..0fc9470570 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/delete-attribute.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let result = try await databases.deleteAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/delete-collection.md b/docs/examples/1.4.x/server-swift/examples/databases/delete-collection.md new file mode 100644 index 0000000000..b00916534e --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/delete-collection.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let result = try await databases.deleteCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/delete-document.md b/docs/examples/1.4.x/server-swift/examples/databases/delete-document.md new file mode 100644 index 0000000000..185c33d410 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/delete-document.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let result = try await databases.deleteDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/delete-index.md b/docs/examples/1.4.x/server-swift/examples/databases/delete-index.md new file mode 100644 index 0000000000..0ad4ac3442 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/delete-index.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let result = try await databases.deleteIndex( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/delete.md b/docs/examples/1.4.x/server-swift/examples/databases/delete.md new file mode 100644 index 0000000000..48b687e237 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/delete.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let result = try await databases.delete( + databaseId: "[DATABASE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/get-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/get-attribute.md new file mode 100644 index 0000000000..e0ea280f56 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/get-attribute.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let result = try await databases.getAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/get-collection.md b/docs/examples/1.4.x/server-swift/examples/databases/get-collection.md new file mode 100644 index 0000000000..39c36b3d61 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/get-collection.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let collection = try await databases.getCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/get-document.md b/docs/examples/1.4.x/server-swift/examples/databases/get-document.md new file mode 100644 index 0000000000..2a12e1140a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/get-document.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let document = try await databases.getDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/get-index.md b/docs/examples/1.4.x/server-swift/examples/databases/get-index.md new file mode 100644 index 0000000000..e69263346a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/get-index.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let index = try await databases.getIndex( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/get.md b/docs/examples/1.4.x/server-swift/examples/databases/get.md new file mode 100644 index 0000000000..805fa3ee23 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/get.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let database = try await databases.get( + databaseId: "[DATABASE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/list-attributes.md b/docs/examples/1.4.x/server-swift/examples/databases/list-attributes.md new file mode 100644 index 0000000000..475da0a712 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/list-attributes.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeList = try await databases.listAttributes( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/list-collections.md b/docs/examples/1.4.x/server-swift/examples/databases/list-collections.md new file mode 100644 index 0000000000..8e451ca8a0 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/list-collections.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let collectionList = try await databases.listCollections( + databaseId: "[DATABASE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/list-documents.md b/docs/examples/1.4.x/server-swift/examples/databases/list-documents.md new file mode 100644 index 0000000000..24bb859761 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/list-documents.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let documentList = try await databases.listDocuments( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/list-indexes.md b/docs/examples/1.4.x/server-swift/examples/databases/list-indexes.md new file mode 100644 index 0000000000..145c02ddcc --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/list-indexes.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let indexList = try await databases.listIndexes( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/list.md b/docs/examples/1.4.x/server-swift/examples/databases/list.md new file mode 100644 index 0000000000..fe7a54df44 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/list.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let databaseList = try await databases.list() + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-boolean-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-boolean-attribute.md new file mode 100644 index 0000000000..73b68190ba --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-boolean-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeBoolean = try await databases.updateBooleanAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse, + default: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-collection.md b/docs/examples/1.4.x/server-swift/examples/databases/update-collection.md new file mode 100644 index 0000000000..807c5659f9 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-collection.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let collection = try await databases.updateCollection( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-datetime-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-datetime-attribute.md new file mode 100644 index 0000000000..4ec71bbcf0 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-datetime-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeDatetime = try await databases.updateDatetimeAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse, + default: "" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-document.md b/docs/examples/1.4.x/server-swift/examples/databases/update-document.md new file mode 100644 index 0000000000..56eed00082 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-document.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let document = try await databases.updateDocument( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + documentId: "[DOCUMENT_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-email-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-email-attribute.md new file mode 100644 index 0000000000..11608e1fca --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-email-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeEmail = try await databases.updateEmailAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse, + default: "email@example.com" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-enum-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-enum-attribute.md new file mode 100644 index 0000000000..fce99d4d03 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-enum-attribute.md @@ -0,0 +1,18 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeEnum = try await databases.updateEnumAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + elements: [], + required: xfalse, + default: "[DEFAULT]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-float-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-float-attribute.md new file mode 100644 index 0000000000..6cc8457d00 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-float-attribute.md @@ -0,0 +1,19 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeFloat = try await databases.updateFloatAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse, + min: 0, + max: 0, + default: 0 +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-integer-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-integer-attribute.md new file mode 100644 index 0000000000..cde600aad9 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-integer-attribute.md @@ -0,0 +1,19 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeInteger = try await databases.updateIntegerAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse, + min: 0, + max: 0, + default: 0 +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-ip-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-ip-attribute.md new file mode 100644 index 0000000000..7d70495c27 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-ip-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeIp = try await databases.updateIpAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse, + default: "" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-relationship-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-relationship-attribute.md new file mode 100644 index 0000000000..e89c3658c2 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-relationship-attribute.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeRelationship = try await databases.updateRelationshipAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-string-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-string-attribute.md new file mode 100644 index 0000000000..40ab7baa48 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-string-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeString = try await databases.updateStringAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse, + default: "[DEFAULT]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update-url-attribute.md b/docs/examples/1.4.x/server-swift/examples/databases/update-url-attribute.md new file mode 100644 index 0000000000..ef9198e3bb --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update-url-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let attributeUrl = try await databases.updateUrlAttribute( + databaseId: "[DATABASE_ID]", + collectionId: "[COLLECTION_ID]", + key: "", + required: xfalse, + default: "https://example.com" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/databases/update.md b/docs/examples/1.4.x/server-swift/examples/databases/update.md new file mode 100644 index 0000000000..8e14f08009 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/databases/update.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let databases = Databases(client) + +let database = try await databases.update( + databaseId: "[DATABASE_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/create-build.md b/docs/examples/1.4.x/server-swift/examples/functions/create-build.md new file mode 100644 index 0000000000..8419bf6950 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/create-build.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let result = try await functions.createBuild( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]", + buildId: "[BUILD_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/create-deployment.md b/docs/examples/1.4.x/server-swift/examples/functions/create-deployment.md new file mode 100644 index 0000000000..c6d32a1ba8 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/create-deployment.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let deployment = try await functions.createDeployment( + functionId: "[FUNCTION_ID]", + code: InputFile.fromPath("file.png"), + activate: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/create-execution.md b/docs/examples/1.4.x/server-swift/examples/functions/create-execution.md new file mode 100644 index 0000000000..0354bf5488 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/create-execution.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let execution = try await functions.createExecution( + functionId: "[FUNCTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/create-variable.md b/docs/examples/1.4.x/server-swift/examples/functions/create-variable.md new file mode 100644 index 0000000000..f261311192 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/create-variable.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let variable = try await functions.createVariable( + functionId: "[FUNCTION_ID]", + key: "[KEY]", + value: "[VALUE]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/create.md b/docs/examples/1.4.x/server-swift/examples/functions/create.md new file mode 100644 index 0000000000..5370c789fa --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/create.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let function = try await functions.create( + functionId: "[FUNCTION_ID]", + name: "[NAME]", + runtime: "node-14.5" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/delete-deployment.md b/docs/examples/1.4.x/server-swift/examples/functions/delete-deployment.md new file mode 100644 index 0000000000..228f9f62e2 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/delete-deployment.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let result = try await functions.deleteDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/delete-variable.md b/docs/examples/1.4.x/server-swift/examples/functions/delete-variable.md new file mode 100644 index 0000000000..410cffe13c --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/delete-variable.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let result = try await functions.deleteVariable( + functionId: "[FUNCTION_ID]", + variableId: "[VARIABLE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/delete.md b/docs/examples/1.4.x/server-swift/examples/functions/delete.md new file mode 100644 index 0000000000..bee774e61b --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/delete.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let result = try await functions.delete( + functionId: "[FUNCTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/download-deployment.md b/docs/examples/1.4.x/server-swift/examples/functions/download-deployment.md new file mode 100644 index 0000000000..e75d1e7dfc --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/download-deployment.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let byteBuffer = try await functions.downloadDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/get-deployment.md b/docs/examples/1.4.x/server-swift/examples/functions/get-deployment.md new file mode 100644 index 0000000000..0a463c4121 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/get-deployment.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let deployment = try await functions.getDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/get-execution.md b/docs/examples/1.4.x/server-swift/examples/functions/get-execution.md new file mode 100644 index 0000000000..7af8bd5906 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/get-execution.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let execution = try await functions.getExecution( + functionId: "[FUNCTION_ID]", + executionId: "[EXECUTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/get-variable.md b/docs/examples/1.4.x/server-swift/examples/functions/get-variable.md new file mode 100644 index 0000000000..f2fa61b903 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/get-variable.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let variable = try await functions.getVariable( + functionId: "[FUNCTION_ID]", + variableId: "[VARIABLE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/get.md b/docs/examples/1.4.x/server-swift/examples/functions/get.md new file mode 100644 index 0000000000..c5ba24ae26 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/get.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let function = try await functions.get( + functionId: "[FUNCTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/list-deployments.md b/docs/examples/1.4.x/server-swift/examples/functions/list-deployments.md new file mode 100644 index 0000000000..652620bf40 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/list-deployments.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let deploymentList = try await functions.listDeployments( + functionId: "[FUNCTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/list-executions.md b/docs/examples/1.4.x/server-swift/examples/functions/list-executions.md new file mode 100644 index 0000000000..fa32172cbd --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/list-executions.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let executionList = try await functions.listExecutions( + functionId: "[FUNCTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/list-runtimes.md b/docs/examples/1.4.x/server-swift/examples/functions/list-runtimes.md new file mode 100644 index 0000000000..6a543754eb --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/list-runtimes.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let runtimeList = try await functions.listRuntimes() + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/list-variables.md b/docs/examples/1.4.x/server-swift/examples/functions/list-variables.md new file mode 100644 index 0000000000..d13c752254 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/list-variables.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let variableList = try await functions.listVariables( + functionId: "[FUNCTION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/list.md b/docs/examples/1.4.x/server-swift/examples/functions/list.md new file mode 100644 index 0000000000..81363f17ff --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/list.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let functionList = try await functions.list() + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/update-deployment.md b/docs/examples/1.4.x/server-swift/examples/functions/update-deployment.md new file mode 100644 index 0000000000..b0f4fc23c4 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/update-deployment.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let function = try await functions.updateDeployment( + functionId: "[FUNCTION_ID]", + deploymentId: "[DEPLOYMENT_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/update-variable.md b/docs/examples/1.4.x/server-swift/examples/functions/update-variable.md new file mode 100644 index 0000000000..0eb5b2e976 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/update-variable.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let variable = try await functions.updateVariable( + functionId: "[FUNCTION_ID]", + variableId: "[VARIABLE_ID]", + key: "[KEY]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/functions/update.md b/docs/examples/1.4.x/server-swift/examples/functions/update.md new file mode 100644 index 0000000000..d12bd5c9fb --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/functions/update.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let functions = Functions(client) + +let function = try await functions.update( + functionId: "[FUNCTION_ID]", + name: "[NAME]", + runtime: "node-14.5" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/graphql/mutation.md b/docs/examples/1.4.x/server-swift/examples/graphql/mutation.md new file mode 100644 index 0000000000..db869d48c9 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/graphql/mutation.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let graphql = Graphql(client) + +let any = try await graphql.mutation( + query: [:] +) + diff --git a/docs/examples/1.4.x/server-swift/examples/graphql/query.md b/docs/examples/1.4.x/server-swift/examples/graphql/query.md new file mode 100644 index 0000000000..5e97508be5 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/graphql/query.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let graphql = Graphql(client) + +let any = try await graphql.query( + query: [:] +) + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-antivirus.md b/docs/examples/1.4.x/server-swift/examples/health/get-antivirus.md new file mode 100644 index 0000000000..cab0d98339 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-antivirus.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthAntivirus = try await health.getAntivirus() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-cache.md b/docs/examples/1.4.x/server-swift/examples/health/get-cache.md new file mode 100644 index 0000000000..a682d63a6f --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-cache.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthStatus = try await health.getCache() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-d-b.md b/docs/examples/1.4.x/server-swift/examples/health/get-d-b.md new file mode 100644 index 0000000000..81645497b5 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-d-b.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthStatus = try await health.getDB() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-pub-sub.md b/docs/examples/1.4.x/server-swift/examples/health/get-pub-sub.md new file mode 100644 index 0000000000..5bf027108a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-pub-sub.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthStatus = try await health.getPubSub() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-queue-certificates.md b/docs/examples/1.4.x/server-swift/examples/health/get-queue-certificates.md new file mode 100644 index 0000000000..71f4dcfc43 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-queue-certificates.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthQueue = try await health.getQueueCertificates() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-queue-functions.md b/docs/examples/1.4.x/server-swift/examples/health/get-queue-functions.md new file mode 100644 index 0000000000..d6bdf76756 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-queue-functions.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthQueue = try await health.getQueueFunctions() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-queue-logs.md b/docs/examples/1.4.x/server-swift/examples/health/get-queue-logs.md new file mode 100644 index 0000000000..7580e46da1 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-queue-logs.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthQueue = try await health.getQueueLogs() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-queue-webhooks.md b/docs/examples/1.4.x/server-swift/examples/health/get-queue-webhooks.md new file mode 100644 index 0000000000..431a5a031c --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-queue-webhooks.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthQueue = try await health.getQueueWebhooks() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-queue.md b/docs/examples/1.4.x/server-swift/examples/health/get-queue.md new file mode 100644 index 0000000000..6f8131d7e8 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-queue.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthStatus = try await health.getQueue() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-storage-local.md b/docs/examples/1.4.x/server-swift/examples/health/get-storage-local.md new file mode 100644 index 0000000000..ee807980bb --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-storage-local.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthStatus = try await health.getStorageLocal() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get-time.md b/docs/examples/1.4.x/server-swift/examples/health/get-time.md new file mode 100644 index 0000000000..f6d66d950a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get-time.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthTime = try await health.getTime() + diff --git a/docs/examples/1.4.x/server-swift/examples/health/get.md b/docs/examples/1.4.x/server-swift/examples/health/get.md new file mode 100644 index 0000000000..828f3453e0 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/health/get.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let health = Health(client) + +let healthStatus = try await health.get() + diff --git a/docs/examples/1.4.x/server-swift/examples/locale/get.md b/docs/examples/1.4.x/server-swift/examples/locale/get.md new file mode 100644 index 0000000000..5c5aee4cb4 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/locale/get.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let locale = Locale(client) + +let locale = try await locale.get() + diff --git a/docs/examples/1.4.x/server-swift/examples/locale/list-codes.md b/docs/examples/1.4.x/server-swift/examples/locale/list-codes.md new file mode 100644 index 0000000000..72966a6371 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/locale/list-codes.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let locale = Locale(client) + +let localeCodeList = try await locale.listCodes() + diff --git a/docs/examples/1.4.x/server-swift/examples/locale/list-continents.md b/docs/examples/1.4.x/server-swift/examples/locale/list-continents.md new file mode 100644 index 0000000000..8cd7964b63 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/locale/list-continents.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let locale = Locale(client) + +let continentList = try await locale.listContinents() + diff --git a/docs/examples/1.4.x/server-swift/examples/locale/list-countries-e-u.md b/docs/examples/1.4.x/server-swift/examples/locale/list-countries-e-u.md new file mode 100644 index 0000000000..a787e7b722 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/locale/list-countries-e-u.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let locale = Locale(client) + +let countryList = try await locale.listCountriesEU() + diff --git a/docs/examples/1.4.x/server-swift/examples/locale/list-countries-phones.md b/docs/examples/1.4.x/server-swift/examples/locale/list-countries-phones.md new file mode 100644 index 0000000000..cf16d2d0b2 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/locale/list-countries-phones.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let locale = Locale(client) + +let phoneList = try await locale.listCountriesPhones() + diff --git a/docs/examples/1.4.x/server-swift/examples/locale/list-countries.md b/docs/examples/1.4.x/server-swift/examples/locale/list-countries.md new file mode 100644 index 0000000000..32d5901e37 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/locale/list-countries.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let locale = Locale(client) + +let countryList = try await locale.listCountries() + diff --git a/docs/examples/1.4.x/server-swift/examples/locale/list-currencies.md b/docs/examples/1.4.x/server-swift/examples/locale/list-currencies.md new file mode 100644 index 0000000000..6b1daa7422 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/locale/list-currencies.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let locale = Locale(client) + +let currencyList = try await locale.listCurrencies() + diff --git a/docs/examples/1.4.x/server-swift/examples/locale/list-languages.md b/docs/examples/1.4.x/server-swift/examples/locale/list-languages.md new file mode 100644 index 0000000000..72c5649aae --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/locale/list-languages.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let locale = Locale(client) + +let languageList = try await locale.listLanguages() + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/create-bucket.md b/docs/examples/1.4.x/server-swift/examples/storage/create-bucket.md new file mode 100644 index 0000000000..d3f91ab7af --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/create-bucket.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let bucket = try await storage.createBucket( + bucketId: "[BUCKET_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/create-file.md b/docs/examples/1.4.x/server-swift/examples/storage/create-file.md new file mode 100644 index 0000000000..45dd245d31 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/create-file.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let file = try await storage.createFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]", + file: InputFile.fromPath("file.png") +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/delete-bucket.md b/docs/examples/1.4.x/server-swift/examples/storage/delete-bucket.md new file mode 100644 index 0000000000..4d41f1c373 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/delete-bucket.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let result = try await storage.deleteBucket( + bucketId: "[BUCKET_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/delete-file.md b/docs/examples/1.4.x/server-swift/examples/storage/delete-file.md new file mode 100644 index 0000000000..b2168f8ca1 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/delete-file.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let result = try await storage.deleteFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/get-bucket.md b/docs/examples/1.4.x/server-swift/examples/storage/get-bucket.md new file mode 100644 index 0000000000..8a27759e0e --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/get-bucket.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let bucket = try await storage.getBucket( + bucketId: "[BUCKET_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/get-file-download.md b/docs/examples/1.4.x/server-swift/examples/storage/get-file-download.md new file mode 100644 index 0000000000..5205e17d43 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/get-file-download.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let byteBuffer = try await storage.getFileDownload( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/get-file-preview.md b/docs/examples/1.4.x/server-swift/examples/storage/get-file-preview.md new file mode 100644 index 0000000000..f6fbec6654 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/get-file-preview.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let byteBuffer = try await storage.getFilePreview( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/get-file-view.md b/docs/examples/1.4.x/server-swift/examples/storage/get-file-view.md new file mode 100644 index 0000000000..5926bdd959 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/get-file-view.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let byteBuffer = try await storage.getFileView( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/get-file.md b/docs/examples/1.4.x/server-swift/examples/storage/get-file.md new file mode 100644 index 0000000000..e516242775 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/get-file.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let file = try await storage.getFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/list-buckets.md b/docs/examples/1.4.x/server-swift/examples/storage/list-buckets.md new file mode 100644 index 0000000000..a3e92b282e --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/list-buckets.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let bucketList = try await storage.listBuckets() + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/list-files.md b/docs/examples/1.4.x/server-swift/examples/storage/list-files.md new file mode 100644 index 0000000000..153a10d27f --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/list-files.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let fileList = try await storage.listFiles( + bucketId: "[BUCKET_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/update-bucket.md b/docs/examples/1.4.x/server-swift/examples/storage/update-bucket.md new file mode 100644 index 0000000000..d2fd96c33d --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/update-bucket.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let bucket = try await storage.updateBucket( + bucketId: "[BUCKET_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/storage/update-file.md b/docs/examples/1.4.x/server-swift/examples/storage/update-file.md new file mode 100644 index 0000000000..f37202aa30 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/storage/update-file.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let storage = Storage(client) + +let file = try await storage.updateFile( + bucketId: "[BUCKET_ID]", + fileId: "[FILE_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/create-membership.md b/docs/examples/1.4.x/server-swift/examples/teams/create-membership.md new file mode 100644 index 0000000000..a43f2a4fbf --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/create-membership.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let membership = try await teams.createMembership( + teamId: "[TEAM_ID]", + roles: [], + url: "https://example.com" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/create.md b/docs/examples/1.4.x/server-swift/examples/teams/create.md new file mode 100644 index 0000000000..e4f8c09e57 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/create.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let team = try await teams.create( + teamId: "[TEAM_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/delete-membership.md b/docs/examples/1.4.x/server-swift/examples/teams/delete-membership.md new file mode 100644 index 0000000000..25326deba0 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/delete-membership.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let result = try await teams.deleteMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/delete.md b/docs/examples/1.4.x/server-swift/examples/teams/delete.md new file mode 100644 index 0000000000..c0e3d5e898 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/delete.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let result = try await teams.delete( + teamId: "[TEAM_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/get-membership.md b/docs/examples/1.4.x/server-swift/examples/teams/get-membership.md new file mode 100644 index 0000000000..c399832ec2 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/get-membership.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let membership = try await teams.getMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/get-prefs.md b/docs/examples/1.4.x/server-swift/examples/teams/get-prefs.md new file mode 100644 index 0000000000..4a79855f65 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/get-prefs.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let teams = Teams(client) + +let preferences = try await teams.getPrefs( + teamId: "[TEAM_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/get.md b/docs/examples/1.4.x/server-swift/examples/teams/get.md new file mode 100644 index 0000000000..07980d4f48 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/get.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let team = try await teams.get( + teamId: "[TEAM_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/list-memberships.md b/docs/examples/1.4.x/server-swift/examples/teams/list-memberships.md new file mode 100644 index 0000000000..57d6ef7d37 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/list-memberships.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let membershipList = try await teams.listMemberships( + teamId: "[TEAM_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/list.md b/docs/examples/1.4.x/server-swift/examples/teams/list.md new file mode 100644 index 0000000000..cdb174c357 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/list.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let teamList = try await teams.list() + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/update-membership-status.md b/docs/examples/1.4.x/server-swift/examples/teams/update-membership-status.md new file mode 100644 index 0000000000..e209ece5ea --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/update-membership-status.md @@ -0,0 +1,16 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let teams = Teams(client) + +let membership = try await teams.updateMembershipStatus( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + userId: "[USER_ID]", + secret: "[SECRET]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/update-membership.md b/docs/examples/1.4.x/server-swift/examples/teams/update-membership.md new file mode 100644 index 0000000000..0bbb83228e --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/update-membership.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let membership = try await teams.updateMembership( + teamId: "[TEAM_ID]", + membershipId: "[MEMBERSHIP_ID]", + roles: [] +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/update-name.md b/docs/examples/1.4.x/server-swift/examples/teams/update-name.md new file mode 100644 index 0000000000..378d6d1ade --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/update-name.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let teams = Teams(client) + +let team = try await teams.updateName( + teamId: "[TEAM_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/teams/update-prefs.md b/docs/examples/1.4.x/server-swift/examples/teams/update-prefs.md new file mode 100644 index 0000000000..142896ad8a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/teams/update-prefs.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token + +let teams = Teams(client) + +let preferences = try await teams.updatePrefs( + teamId: "[TEAM_ID]", + prefs: [:] +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/create-argon2user.md b/docs/examples/1.4.x/server-swift/examples/users/create-argon2user.md new file mode 100644 index 0000000000..5914c87d96 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/create-argon2user.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.createArgon2User( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/create-bcrypt-user.md b/docs/examples/1.4.x/server-swift/examples/users/create-bcrypt-user.md new file mode 100644 index 0000000000..4321365b5c --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/create-bcrypt-user.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.createBcryptUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/create-m-d5user.md b/docs/examples/1.4.x/server-swift/examples/users/create-m-d5user.md new file mode 100644 index 0000000000..2302780c6b --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/create-m-d5user.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.createMD5User( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/create-p-h-pass-user.md b/docs/examples/1.4.x/server-swift/examples/users/create-p-h-pass-user.md new file mode 100644 index 0000000000..b856891a7d --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/create-p-h-pass-user.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.createPHPassUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/create-s-h-a-user.md b/docs/examples/1.4.x/server-swift/examples/users/create-s-h-a-user.md new file mode 100644 index 0000000000..c96661377a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/create-s-h-a-user.md @@ -0,0 +1,15 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.createSHAUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/create-scrypt-modified-user.md b/docs/examples/1.4.x/server-swift/examples/users/create-scrypt-modified-user.md new file mode 100644 index 0000000000..3a9f70386e --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/create-scrypt-modified-user.md @@ -0,0 +1,18 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.createScryptModifiedUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password", + passwordSalt: "[PASSWORD_SALT]", + passwordSaltSeparator: "[PASSWORD_SALT_SEPARATOR]", + passwordSignerKey: "[PASSWORD_SIGNER_KEY]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/create-scrypt-user.md b/docs/examples/1.4.x/server-swift/examples/users/create-scrypt-user.md new file mode 100644 index 0000000000..dbe923de93 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/create-scrypt-user.md @@ -0,0 +1,20 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.createScryptUser( + userId: "[USER_ID]", + email: "email@example.com", + password: "password", + passwordSalt: "[PASSWORD_SALT]", + passwordCpu: 0, + passwordMemory: 0, + passwordParallel: 0, + passwordLength: 0 +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/create.md b/docs/examples/1.4.x/server-swift/examples/users/create.md new file mode 100644 index 0000000000..db49c1f77f --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/create.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.create( + userId: "[USER_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/delete-identity.md b/docs/examples/1.4.x/server-swift/examples/users/delete-identity.md new file mode 100644 index 0000000000..d4b26dbc68 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/delete-identity.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let result = try await users.deleteIdentity( + identityId: "[IDENTITY_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/delete-session.md b/docs/examples/1.4.x/server-swift/examples/users/delete-session.md new file mode 100644 index 0000000000..161e11d274 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/delete-session.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let result = try await users.deleteSession( + userId: "[USER_ID]", + sessionId: "[SESSION_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/delete-sessions.md b/docs/examples/1.4.x/server-swift/examples/users/delete-sessions.md new file mode 100644 index 0000000000..71bc2bf893 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/delete-sessions.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let result = try await users.deleteSessions( + userId: "[USER_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/delete.md b/docs/examples/1.4.x/server-swift/examples/users/delete.md new file mode 100644 index 0000000000..c8762da65a --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/delete.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let result = try await users.delete( + userId: "[USER_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/get-prefs.md b/docs/examples/1.4.x/server-swift/examples/users/get-prefs.md new file mode 100644 index 0000000000..956724d0b3 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/get-prefs.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let preferences = try await users.getPrefs( + userId: "[USER_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/get.md b/docs/examples/1.4.x/server-swift/examples/users/get.md new file mode 100644 index 0000000000..a2b3a126f9 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/get.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.get( + userId: "[USER_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/list-identities.md b/docs/examples/1.4.x/server-swift/examples/users/list-identities.md new file mode 100644 index 0000000000..db55096368 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/list-identities.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let identityList = try await users.listIdentities() + diff --git a/docs/examples/1.4.x/server-swift/examples/users/list-logs.md b/docs/examples/1.4.x/server-swift/examples/users/list-logs.md new file mode 100644 index 0000000000..20a55b7f50 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/list-logs.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let logList = try await users.listLogs( + userId: "[USER_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/list-memberships.md b/docs/examples/1.4.x/server-swift/examples/users/list-memberships.md new file mode 100644 index 0000000000..c07287eb46 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/list-memberships.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let membershipList = try await users.listMemberships( + userId: "[USER_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/list-sessions.md b/docs/examples/1.4.x/server-swift/examples/users/list-sessions.md new file mode 100644 index 0000000000..9f403d8da0 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/list-sessions.md @@ -0,0 +1,13 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let sessionList = try await users.listSessions( + userId: "[USER_ID]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/list.md b/docs/examples/1.4.x/server-swift/examples/users/list.md new file mode 100644 index 0000000000..6b41b20015 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/list.md @@ -0,0 +1,11 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let userList = try await users.list() + diff --git a/docs/examples/1.4.x/server-swift/examples/users/update-email-verification.md b/docs/examples/1.4.x/server-swift/examples/users/update-email-verification.md new file mode 100644 index 0000000000..b0649e63f6 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/update-email-verification.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.updateEmailVerification( + userId: "[USER_ID]", + emailVerification: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/update-email.md b/docs/examples/1.4.x/server-swift/examples/users/update-email.md new file mode 100644 index 0000000000..892ff0033f --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/update-email.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.updateEmail( + userId: "[USER_ID]", + email: "email@example.com" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/update-labels.md b/docs/examples/1.4.x/server-swift/examples/users/update-labels.md new file mode 100644 index 0000000000..47fc143387 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/update-labels.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.updateLabels( + userId: "[USER_ID]", + labels: [] +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/update-name.md b/docs/examples/1.4.x/server-swift/examples/users/update-name.md new file mode 100644 index 0000000000..a5ce6f9cad --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/update-name.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.updateName( + userId: "[USER_ID]", + name: "[NAME]" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/update-password.md b/docs/examples/1.4.x/server-swift/examples/users/update-password.md new file mode 100644 index 0000000000..fa2de8b93c --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/update-password.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.updatePassword( + userId: "[USER_ID]", + password: "" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/update-phone-verification.md b/docs/examples/1.4.x/server-swift/examples/users/update-phone-verification.md new file mode 100644 index 0000000000..f837ffc167 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/update-phone-verification.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.updatePhoneVerification( + userId: "[USER_ID]", + phoneVerification: xfalse +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/update-phone.md b/docs/examples/1.4.x/server-swift/examples/users/update-phone.md new file mode 100644 index 0000000000..f2b8f350de --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/update-phone.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.updatePhone( + userId: "[USER_ID]", + number: "+12065550100" +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/update-prefs.md b/docs/examples/1.4.x/server-swift/examples/users/update-prefs.md new file mode 100644 index 0000000000..fc4131ea2f --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/update-prefs.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let preferences = try await users.updatePrefs( + userId: "[USER_ID]", + prefs: [:] +) + diff --git a/docs/examples/1.4.x/server-swift/examples/users/update-status.md b/docs/examples/1.4.x/server-swift/examples/users/update-status.md new file mode 100644 index 0000000000..f382775b17 --- /dev/null +++ b/docs/examples/1.4.x/server-swift/examples/users/update-status.md @@ -0,0 +1,14 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + +let users = Users(client) + +let user = try await users.updateStatus( + userId: "[USER_ID]", + status: xfalse +) + diff --git a/docs/references/account/delete-identity.md b/docs/references/account/delete-identity.md new file mode 100644 index 0000000000..ef480e06a4 --- /dev/null +++ b/docs/references/account/delete-identity.md @@ -0,0 +1 @@ +Delete an identity by its unique ID. \ No newline at end of file diff --git a/docs/references/account/get-prefs.md b/docs/references/account/get-prefs.md index 8edfbb6883..867684dad7 100644 --- a/docs/references/account/get-prefs.md +++ b/docs/references/account/get-prefs.md @@ -1 +1 @@ -Get currently logged in user preferences as a key-value object. \ No newline at end of file +Get the preferences as a key-value object for the currently logged in user. \ No newline at end of file diff --git a/docs/references/account/get.md b/docs/references/account/get.md index f62b1f52bf..4dcae53117 100644 --- a/docs/references/account/get.md +++ b/docs/references/account/get.md @@ -1 +1 @@ -Get currently logged in user data as JSON object. \ No newline at end of file +Get the currently logged in user. \ No newline at end of file diff --git a/docs/references/account/list-identities.md b/docs/references/account/list-identities.md new file mode 100644 index 0000000000..4378bfb67a --- /dev/null +++ b/docs/references/account/list-identities.md @@ -0,0 +1 @@ +Get the list of identities for the currently logged in user. \ No newline at end of file diff --git a/docs/references/account/list-logs.md b/docs/references/account/list-logs.md index 5cd2a4b87e..1f3a8d67a4 100644 --- a/docs/references/account/list-logs.md +++ b/docs/references/account/list-logs.md @@ -1 +1 @@ -Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log. \ No newline at end of file +Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log. \ No newline at end of file diff --git a/docs/references/account/list-sessions.md b/docs/references/account/list-sessions.md index e944fd3675..f4eadf285c 100644 --- a/docs/references/account/list-sessions.md +++ b/docs/references/account/list-sessions.md @@ -1 +1 @@ -Get currently logged in user list of active sessions across different devices. \ No newline at end of file +Get the list of active sessions across different devices for the currently logged in user. \ No newline at end of file diff --git a/docs/references/functions/create-build.md b/docs/references/functions/create-build.md new file mode 100644 index 0000000000..31a288a35a --- /dev/null +++ b/docs/references/functions/create-build.md @@ -0,0 +1 @@ +Create a new build for an Appwrite Function deployment. This endpoint can be used to retry a failed build. \ No newline at end of file diff --git a/docs/references/functions/create-deployment.md b/docs/references/functions/create-deployment.md index 7cae5989ae..c9dc6e3a7b 100644 --- a/docs/references/functions/create-deployment.md +++ b/docs/references/functions/create-deployment.md @@ -2,4 +2,4 @@ Create a new function code deployment. Use this endpoint to upload a new version This 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](/docs/functions). -Use the "command" param to set the entry point used to execute your code. \ No newline at end of file +Use the "command" param to set the entrypoint used to execute your code. \ No newline at end of file diff --git a/docs/references/functions/create-variable.md b/docs/references/functions/create-variable.md index 35747c42a6..40fabd75a8 100644 --- a/docs/references/functions/create-variable.md +++ b/docs/references/functions/create-variable.md @@ -1 +1 @@ -Create a new function variable. These variables can be accessed within function in the `env` object under the request variable. \ No newline at end of file +Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables. \ No newline at end of file diff --git a/docs/references/project/create-variable.md b/docs/references/project/create-variable.md new file mode 100644 index 0000000000..2bbee5bf99 --- /dev/null +++ b/docs/references/project/create-variable.md @@ -0,0 +1 @@ +Create a new project variable. This variable will be accessible in all Appwrite Functions at runtime. \ No newline at end of file diff --git a/docs/references/project/delete-variable.md b/docs/references/project/delete-variable.md new file mode 100644 index 0000000000..9be15f83ca --- /dev/null +++ b/docs/references/project/delete-variable.md @@ -0,0 +1 @@ +Delete a project variable by its unique ID. \ No newline at end of file diff --git a/docs/references/project/get-variable.md b/docs/references/project/get-variable.md new file mode 100644 index 0000000000..8636768434 --- /dev/null +++ b/docs/references/project/get-variable.md @@ -0,0 +1 @@ +Get a project variable by its unique ID. \ No newline at end of file diff --git a/docs/references/project/list-variables.md b/docs/references/project/list-variables.md new file mode 100644 index 0000000000..fbe191178a --- /dev/null +++ b/docs/references/project/list-variables.md @@ -0,0 +1 @@ +Get a list of all project variables. These variables will be accessible in all Appwrite Functions at runtime. \ No newline at end of file diff --git a/docs/references/project/update-variable.md b/docs/references/project/update-variable.md new file mode 100644 index 0000000000..603622b2c7 --- /dev/null +++ b/docs/references/project/update-variable.md @@ -0,0 +1 @@ +Update project variable by its unique ID. This variable will be accessible in all Appwrite Functions at runtime. \ No newline at end of file diff --git a/docs/references/proxy/create-rule.md b/docs/references/proxy/create-rule.md new file mode 100644 index 0000000000..be567b1cc0 --- /dev/null +++ b/docs/references/proxy/create-rule.md @@ -0,0 +1 @@ +Create a new proxy rule. \ No newline at end of file diff --git a/docs/references/proxy/delete-rule.md b/docs/references/proxy/delete-rule.md new file mode 100644 index 0000000000..7a4823f86d --- /dev/null +++ b/docs/references/proxy/delete-rule.md @@ -0,0 +1 @@ +Delete a proxy rule by its unique ID. \ No newline at end of file diff --git a/docs/references/proxy/get-rule.md b/docs/references/proxy/get-rule.md new file mode 100644 index 0000000000..cfd040141e --- /dev/null +++ b/docs/references/proxy/get-rule.md @@ -0,0 +1 @@ +Get a proxy rule by its unique ID. \ No newline at end of file diff --git a/docs/references/proxy/list-rules.md b/docs/references/proxy/list-rules.md new file mode 100644 index 0000000000..042d780f02 --- /dev/null +++ b/docs/references/proxy/list-rules.md @@ -0,0 +1 @@ +Get a list of all the proxy rules. You can use the query params to filter your results. \ No newline at end of file diff --git a/docs/references/teams/update-team-membership-roles.md b/docs/references/teams/update-team-membership.md similarity index 78% rename from docs/references/teams/update-team-membership-roles.md rename to docs/references/teams/update-team-membership.md index 344d2875df..5f7b46e640 100644 --- a/docs/references/teams/update-team-membership-roles.md +++ b/docs/references/teams/update-team-membership.md @@ -1 +1 @@ -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](/docs/permissions). \ No newline at end of file +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](/docs/permissions). diff --git a/docs/references/users/delete-identity.md b/docs/references/users/delete-identity.md new file mode 100644 index 0000000000..ef480e06a4 --- /dev/null +++ b/docs/references/users/delete-identity.md @@ -0,0 +1 @@ +Delete an identity by its unique ID. \ No newline at end of file diff --git a/docs/references/users/list-identities.md b/docs/references/users/list-identities.md new file mode 100644 index 0000000000..e8a66e5e40 --- /dev/null +++ b/docs/references/users/list-identities.md @@ -0,0 +1 @@ +Get identities for all users. \ No newline at end of file diff --git a/docs/sdks/dart/CHANGELOG.md b/docs/sdks/dart/CHANGELOG.md index 16197b3969..f0cf7868d2 100644 --- a/docs/sdks/dart/CHANGELOG.md +++ b/docs/sdks/dart/CHANGELOG.md @@ -1,3 +1,18 @@ +## 9.0.0 + +* Support for Appwrite 1.4.0 +* New endpoints for fetching user identities +* New endpoints for listing locale codes +* New endpoint for downloading a function deployment +* Updated documentation +* Breaking changes: + * The `createFunction` method has a new signature. + * The `createExecution` method has a new signature. + * The `updateFunction` method has a new signature. + * The `createDeployment` method no longer requires an entrypoint. + * The `updateFile` method now includes the ability to update the file name. + * The `updateMembershipRoles` method has been renamed to `updateMembership`. + ## 8.0.0 * Added relationships support diff --git a/docs/sdks/flutter/CHANGELOG.md b/docs/sdks/flutter/CHANGELOG.md index dbac2c9816..f682d203ce 100644 --- a/docs/sdks/flutter/CHANGELOG.md +++ b/docs/sdks/flutter/CHANGELOG.md @@ -1,3 +1,17 @@ +## 10.0.0 + +* Support for Appwrite 1.4.0 +* New endpoints for fetching user identities +* New endpoints for listing locale codes +* Updated documentation +* Breaking changes: + * The `createFunction` method has a new signature. + * The `createExecution` method has a new signature. + * The `updateFunction` method has a new signature. + * The `createDeployment` method no longer requires an entrypoint. + * The `updateFile` method now includes the ability to update the file name. + * The `updateMembershipRoles` method has been renamed to `updateMembership`. + ## 9.0.0 * Added relationships support diff --git a/docs/services/proxy.md b/docs/services/proxy.md new file mode 100644 index 0000000000..ebf189595a --- /dev/null +++ b/docs/services/proxy.md @@ -0,0 +1,3 @@ +The Proxy service allows you to configure behavior for your attached domains. You can use proxy service to create rules that define what is returned on specific domains and subdomains. + +Proxy Rules can be configured to serve Appwrite API, which allows you to comply with first-party cookies, making your website more secure. It can also be configured to serve Appwrite Function, which lets you accept incoming webhooks, build custom API endpoints, and serve static files. \ No newline at end of file diff --git a/docs/services/vcs.md b/docs/services/vcs.md new file mode 100644 index 0000000000..db8cbfdd99 --- /dev/null +++ b/docs/services/vcs.md @@ -0,0 +1,3 @@ +The VCS (Version Control System) service in Appwrite provides a way to interact with VCS providers like Git, GitHub etc. and manage your code repositories. You can use it to install the VCS app or to create, list, and delete repositories. You can also use the VCS service to clone, push, and pull code from your repositories. + +The VCS service helps you to either link an existing code repository to your Appwrite Function or to create a new repository from scratch using one of the available templates. If you link a repository to an Appwrite Function, it automatically creates a new deployment when you push changes. diff --git a/docs/tutorials/add-oauth2-provider.md b/docs/tutorials/add-oauth2-provider.md index 4aa20649ca..734f199693 100644 --- a/docs/tutorials/add-oauth2-provider.md +++ b/docs/tutorials/add-oauth2-provider.md @@ -42,7 +42,7 @@ app/config/providers.php Make sure to fill in all data needed and that your provider array key name: -- is in [`camelCase`](https://en.wikipedia.org/wiki/Camel_case) format +- is in [`camelCase`](https://en.wikipedia.org/wiki/Camel_case) format for sentence, but lowercase for names. `github` must be all lowercased, but `paypalSandbox` should have uppercase S - has no spaces or special characters > Please make sure to keep the list of providers in `providers.php` in the alphabetical order A-Z. diff --git a/phpcs.xml b/phpcs.xml index ccde5812b3..70e4df36ed 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -7,6 +7,8 @@ ./app/sdks + + ./tests/resources/functions ./app/console diff --git a/src/Appwrite/Auth/OAuth2.php b/src/Appwrite/Auth/OAuth2.php index c737e183f8..f7dc1d50a1 100644 --- a/src/Appwrite/Auth/OAuth2.php +++ b/src/Appwrite/Auth/OAuth2.php @@ -208,7 +208,7 @@ abstract class OAuth2 \curl_close($ch); - if ($code != 200) { + if ($code >= 400) { throw new Exception($response, $code); } diff --git a/src/Appwrite/Auth/OAuth2/Exception.php b/src/Appwrite/Auth/OAuth2/Exception.php index af98fa5e9d..28d8d652f9 100644 --- a/src/Appwrite/Auth/OAuth2/Exception.php +++ b/src/Appwrite/Auth/OAuth2/Exception.php @@ -16,9 +16,15 @@ class Exception extends AppwriteException $this->message = $response; $decoded = json_decode($response, true); if (\is_array($decoded)) { - $this->error = $decoded['error']; - $this->errorDescription = $decoded['error_description']; - $this->message = $this->error . ': ' . $this->errorDescription; + if (\is_array($decoded['error'] ?? '')) { + $this->error = $decoded['error']['status']; + $this->errorDescription = $decoded['error']['message']; + $this->message = $this->error . ': ' . $this->errorDescription; + } else { + $this->error = $decoded['error'] ?? $decoded['message'] ?? 'Unknown error'; + $this->errorDescription = $decoded['error_description'] ?? 'No description'; + $this->message = $this->error . ': ' . $this->errorDescription; + } } $type = match ($code) { 400 => AppwriteException::USER_OAUTH2_BAD_REQUEST, diff --git a/src/Appwrite/Auth/OAuth2/Firebase.php b/src/Appwrite/Auth/OAuth2/Firebase.php new file mode 100644 index 0000000000..9c64038089 --- /dev/null +++ b/src/Appwrite/Auth/OAuth2/Firebase.php @@ -0,0 +1,389 @@ + 'offline', + 'client_id' => $this->appID, + 'redirect_uri' => $this->callback, + 'scope' => \implode(' ', $this->getScopes()), + 'state' => \json_encode($this->state), + 'response_type' => 'code', + 'prompt' => 'consent', + ]); + } + + /** + * @param string $code + * + * @return array + */ + protected function getTokens(string $code): array + { + if (empty($this->tokens)) { + $response = $this->request( + 'POST', + 'https://oauth2.googleapis.com/token', + [], + \http_build_query([ + 'client_id' => $this->appID, + 'redirect_uri' => $this->callback, + 'client_secret' => $this->appSecret, + 'code' => $code, + 'grant_type' => 'authorization_code' + ]) + ); + + $this->tokens = \json_decode($response, true); + } + + return $this->tokens; + } + + /** + * @param string $refreshToken + * + * @return array + */ + public function refreshTokens(string $refreshToken): array + { + $response = $this->request( + 'POST', + 'https://oauth2.googleapis.com/token', + [], + \http_build_query([ + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'grant_type' => 'refresh_token', + 'refresh_token' => $refreshToken + ]) + ); + + $output = []; + \parse_str($response, $output); + $this->tokens = $output; + + if (empty($this->tokens['refresh_token'])) { + $this->tokens['refresh_token'] = $refreshToken; + } + + return $this->tokens; + } + + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserID(string $accessToken): string + { + $user = $this->getUser($accessToken); + + return $user['id'] ?? ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserEmail(string $accessToken): string + { + $user = $this->getUser($accessToken); + + return $user['email'] ?? ''; + } + + + /** + * Check if the OAuth email is verified + * + * @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user + * + * @param string $accessToken + * + * @return bool + */ + public function isEmailVerified(string $accessToken): bool + { + $user = $this->getUser($accessToken); + + if ($user['verified'] ?? false) { + return true; + } + + return false; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserName(string $accessToken): string + { + $user = $this->getUser($accessToken); + + return $user['name'] ?? ''; + } + + /** + * @param string $accessToken + * + * @return array + */ + protected function getUser(string $accessToken) + { + if (empty($this->user)) { + $response = $this->request( + 'GET', + 'https://www.googleapis.com/oauth2/v1/userinfo?access_token=' . \urlencode($accessToken), + [], + ); + + $this->user = \json_decode($response, true); + } + + return $this->user; + } + + public function getProjects(string $accessToken): array + { + $projects = $this->request('GET', 'https://firebase.googleapis.com/v1beta1/projects', ['Authorization: Bearer ' . \urlencode($accessToken)]); + + $projects = \json_decode($projects, true); + + return $projects['results']; + } + + /* + Be careful with the setIAMPolicy method, it will overwrite all existing policies + **/ + public function assignIAMRole(string $accessToken, string $email, string $projectId, array $role) + { + // Get IAM Roles + $iamRoles = $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/' . $projectId . ':getIamPolicy', [ + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' + ]); + + $iamRoles = \json_decode($iamRoles, true); + + $iamRoles['bindings'][] = [ + 'role' => $role['name'], + 'members' => [ + 'serviceAccount:' . $email + ] + ]; + + // Set IAM Roles + $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/' . $projectId . ':setIamPolicy', [ + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' + ], \json_encode([ + 'policy' => $iamRoles + ])); + } + + private function generateRandomString($length = 10): string + { + $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $charactersLength = strlen($characters); + $randomString = ''; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[random_int(0, $charactersLength - 1)]; + } + return $randomString; + } + + private function createCustomRole(string $accessToken, string $projectId): array + { + // Check if role already exists + try { + $role = $this->request('GET', 'https://iam.googleapis.com/v1/projects/' . $projectId . '/roles/appwriteMigrations', [ + 'Content-Type: application/json', + 'Authorization: Bearer ' . \urlencode($accessToken), + ]); + + $role = \json_decode($role, true); + + return $role; + } catch (\Exception $e) { + if ($e->getCode() !== 404) { + throw $e; + } + } + + // Create role if doesn't exist or isn't correct + $role = $this->request( + 'POST', + 'https://iam.googleapis.com/v1/projects/' . $projectId . '/roles/', + [ + 'Content-Type: application/json', + 'Authorization: Bearer ' . \urlencode($accessToken), + ], + \json_encode( + [ + 'roleId' => 'appwriteMigrations', + 'role' => [ + 'title' => 'Appwrite Migrations', + 'description' => 'A helper role for Appwrite Migrations', + 'includedPermissions' => $this->iamPermissions, + 'stage' => 'GA' + ] + ] + ) + ); + + return json_decode($role, true); + } + + public function createServiceAccount(string $accessToken, string $projectId): array + { + // Create Service Account + $uid = $this->generateRandomString(); + + $response = $this->request( + 'POST', + 'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts', + [ + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' + ], + \json_encode([ + 'accountId' => 'appwrite-' . $uid, + 'serviceAccount' => [ + 'displayName' => 'Appwrite Migrations ' . $uid + ] + ]) + ); + + $response = json_decode($response, true); + + // Create and assign IAM Roles + $role = $this->createCustomRole($accessToken, $projectId); + + \sleep(1); // Wait for IAM to propagate changes. + + $this->assignIAMRole($accessToken, $response['email'], $projectId, $role); + + // Create Service Account Key + $responseKey = $this->request( + 'POST', + 'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts/' . $response['email'] . '/keys', + [ + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' + ] + ); + + $responseKey = json_decode($responseKey, true); + + return json_decode(base64_decode($responseKey['privateKeyData']), true); + } + + public function cleanupServiceAccounts(string $accessToken, string $projectId) + { + // List Service Accounts + $response = $this->request( + 'GET', + 'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts', + [ + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' + ] + ); + + $response = json_decode($response, true); + + if (empty($response['accounts'])) { + return false; + } + + foreach ($response['accounts'] as $account) { + if (strpos($account['email'], 'appwrite-') !== false) { + $this->request( + 'DELETE', + 'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts/' . $account['email'], + [ + 'Authorization: Bearer ' . \urlencode($accessToken), + 'Content-Type: application/json' + ] + ); + } + } + + return true; + } +} diff --git a/src/Appwrite/Auth/OAuth2/Github.php b/src/Appwrite/Auth/OAuth2/Github.php index 8b9208fc06..1cefc397c5 100644 --- a/src/Appwrite/Auth/OAuth2/Github.php +++ b/src/Appwrite/Auth/OAuth2/Github.php @@ -208,4 +208,15 @@ class Github extends OAuth2 return $this->user; } + + public function createRepository(string $accessToken, string $repositoryName, bool $private): array + { + $repository = $this->request('POST', 'https://api.github.com/user/repos', ['Authorization: token ' . \urlencode($accessToken)], \json_encode([ + 'name' => $repositoryName, + 'private' => $private + ])); + + $repository = \json_decode($repository, true); + return $repository; + } } diff --git a/src/Appwrite/Detector/Detector.php b/src/Appwrite/Detector/Detector.php index 62f7a0a04b..61286835f5 100644 --- a/src/Appwrite/Detector/Detector.php +++ b/src/Appwrite/Detector/Detector.php @@ -77,10 +77,14 @@ class Detector */ public function getDevice(): array { + $deviceName = $this->getDetector()->getDeviceName(); + $deviceBrand = $this->getDetector()->getBrandName(); + $deviceModel = $this->getDetector()->getModel(); + return [ - 'deviceName' => $this->getDetector()->getDeviceName(), - 'deviceBrand' => $this->getDetector()->getBrandName(), - 'deviceModel' => $this->getDetector()->getModel(), + 'deviceName' => empty($deviceName) ? null : $deviceName, + 'deviceBrand' => empty($deviceBrand) ? null : $deviceBrand, + 'deviceModel' => empty($deviceModel) ? null : $deviceModel, ]; } diff --git a/src/Appwrite/Event/Build.php b/src/Appwrite/Event/Build.php index 4d4b338118..428b6aa832 100644 --- a/src/Appwrite/Event/Build.php +++ b/src/Appwrite/Event/Build.php @@ -10,12 +10,26 @@ class Build extends Event protected string $type = ''; protected ?Document $resource = null; protected ?Document $deployment = null; + protected ?Document $template = null; public function __construct() { parent::__construct(Event::BUILDS_QUEUE_NAME, Event::BUILDS_CLASS_NAME); } + /** + * Sets template for the build event. + * + * @param Document $template + * @return self + */ + public function setTemplate(Document $template): self + { + $this->template = $template; + + return $this; + } + /** * Sets resource document for the build event. * @@ -97,7 +111,8 @@ class Build extends Event 'project' => $this->project, 'resource' => $this->resource, 'deployment' => $this->deployment, - 'type' => $this->type + 'type' => $this->type, + 'template' => $this->template ]); } } diff --git a/src/Appwrite/Event/Delete.php b/src/Appwrite/Event/Delete.php index d1519121a6..8e593b1020 100644 --- a/src/Appwrite/Event/Delete.php +++ b/src/Appwrite/Event/Delete.php @@ -13,7 +13,6 @@ class Delete extends Event protected ?string $datetime = null; protected ?string $hourlyUsageRetentionDatetime = null; - public function __construct() { parent::__construct(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME); @@ -127,7 +126,7 @@ class Delete extends Event 'document' => $this->document, 'resource' => $this->resource, 'datetime' => $this->datetime, - 'hourlyUsageRetentionDatetime' => $this->hourlyUsageRetentionDatetime, + 'hourlyUsageRetentionDatetime' => $this->hourlyUsageRetentionDatetime ]); } } diff --git a/src/Appwrite/Event/Event.php b/src/Appwrite/Event/Event.php index 0cf90eb3d3..23dde49637 100644 --- a/src/Appwrite/Event/Event.php +++ b/src/Appwrite/Event/Event.php @@ -38,6 +38,9 @@ class Event public const MESSAGING_QUEUE_NAME = 'v1-messaging'; public const MESSAGING_CLASS_NAME = 'MessagingV1'; + public const MIGRATIONS_QUEUE_NAME = 'v1-migrations'; + public const MIGRATIONS_CLASS_NAME = 'MigrationsV1'; + protected string $queue = ''; protected string $class = ''; protected string $event = ''; diff --git a/src/Appwrite/Event/Func.php b/src/Appwrite/Event/Func.php index d121b47a4a..b8c81cdc2d 100644 --- a/src/Appwrite/Event/Func.php +++ b/src/Appwrite/Event/Func.php @@ -10,7 +10,10 @@ class Func extends Event { protected string $jwt = ''; protected string $type = ''; - protected string $data = ''; + protected string $body = ''; + protected string $path = ''; + protected string $method = ''; + protected array $headers = []; protected ?Document $function = null; protected ?Document $execution = null; @@ -89,14 +92,53 @@ class Func extends Event } /** - * Sets custom data for the function event. + * Sets custom body for the function event. * - * @param string $data + * @param string $body * @return self */ - public function setData(string $data): self + public function setBody(string $body): self { - $this->data = $data; + $this->body = $body; + + return $this; + } + + /** + * Sets custom method for the function event. + * + * @param string $method + * @return self + */ + public function setMethod(string $method): self + { + $this->method = $method; + + return $this; + } + + /** + * Sets custom path for the function event. + * + * @param string $path + * @return self + */ + public function setPath(string $path): self + { + $this->path = $path; + + return $this; + } + + /** + * Sets custom headers for the function event. + * + * @param string $headers + * @return self + */ + public function setHeaders(array $headers): self + { + $this->headers = $headers; return $this; } @@ -159,7 +201,10 @@ class Func extends Event 'jwt' => $this->jwt, 'payload' => $this->payload, 'events' => $events, - 'data' => $this->data, + 'body' => $this->body, + 'path' => $this->path, + 'headers' => $this->headers, + 'method' => $this->method, ]); } diff --git a/src/Appwrite/Event/Mail.php b/src/Appwrite/Event/Mail.php index 37b42704c5..e1c015fb2b 100644 --- a/src/Appwrite/Event/Mail.php +++ b/src/Appwrite/Event/Mail.php @@ -8,11 +8,11 @@ use Utopia\Database\Document; class Mail extends Event { protected string $recipient = ''; - protected string $from = ''; protected string $name = ''; protected string $subject = ''; protected string $body = ''; protected array $smtp = []; + protected array $variables = []; public function __construct() { @@ -65,29 +65,6 @@ class Mail extends Event return $this->recipient; } - /** - * Sets from for the mail event. - * - * @param string $from - * @return self - */ - public function setFrom(string $from): self - { - $this->from = $from; - - return $this; - } - - /** - * Returns from for mail event. - * - * @return string - */ - public function getFrom(): string - { - return $this->from; - } - /** * Sets body for the mail event. * @@ -166,7 +143,7 @@ class Mail extends Event */ public function setSmtpUsername(string $username): self { - $this->smtp['username']; + $this->smtp['username'] = $username; return $this; } @@ -178,7 +155,19 @@ class Mail extends Event */ public function setSmtpPassword(string $password): self { - $this->smtp['password']; + $this->smtp['password'] = $password; + return $this; + } + + /** + * Set SMTP secure + * + * @param string $password + * @return self + */ + public function setSmtpSecure(string $secure): self + { + $this->smtp['secure'] = $secure; return $this; } @@ -194,6 +183,18 @@ class Mail extends Event return $this; } + /** + * Set SMTP sender name + * + * @param string $senderName + * @return self + */ + public function setSmtpSenderName(string $senderName): self + { + $this->smtp['senderName'] = $senderName; + return $this; + } + /** * Set SMTP reply to * @@ -246,6 +247,16 @@ class Mail extends Event return $this->smtp['password'] ?? ''; } + /** + * Get SMTP secure + * + * @return string + */ + public function getSmtpSecure(): string + { + return $this->smtp['secure'] ?? ''; + } + /** * Get SMTP sender email * @@ -256,6 +267,16 @@ class Mail extends Event return $this->smtp['senderEmail'] ?? ''; } + /** + * Get SMTP sender name + * + * @return string + */ + public function getSmtpSenderName(): string + { + return $this->smtp['senderName'] ?? ''; + } + /** * Get SMTP reply to * @@ -266,6 +287,28 @@ class Mail extends Event return $this->smtp['replyTo'] ?? ''; } + /** + * Get Email Variables + * + * @return array + */ + public function getVariables(): array + { + return $this->variables; + } + + /** + * Set Email Variables + * + * @param array $variables + * @return self + */ + public function setVariables(array $variables): self + { + $this->variables = $variables; + return $this; + } + /** * Executes the event and sends it to the mails worker. * @@ -275,12 +318,12 @@ class Mail extends Event public function trigger(): string|bool { return Resque::enqueue($this->queue, $this->class, [ - 'from' => $this->from, 'recipient' => $this->recipient, 'name' => $this->name, 'subject' => $this->subject, 'body' => $this->body, 'smtp' => $this->smtp, + 'variables' => $this->variables, 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) ]); } diff --git a/src/Appwrite/Event/Migration.php b/src/Appwrite/Event/Migration.php new file mode 100644 index 0000000000..4d53f16796 --- /dev/null +++ b/src/Appwrite/Event/Migration.php @@ -0,0 +1,98 @@ +migration = $migration; + + return $this; + } + + /** + * Returns set migration document for the function event. + * + * @return null|Document + */ + public function getMigration(): ?Document + { + return $this->migration; + } + + /** + * Sets migration type for the migration event. + * + * @param string $type + * + * @return self + */ + public function setType(string $type): self + { + $this->type = $type; + + return $this; + } + + /** + * Returns set migration type for the migration event. + * + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * Executes the migration event and sends it to the migrations worker. + * + * @return string|bool + * @throws \InvalidArgumentException + */ + public function trigger(): string|bool + { + return Resque::enqueue($this->queue, $this->class, [ + 'project' => $this->project, + 'user' => $this->user, + 'migration' => $this->migration + ]); + } + + /** + * Schedules the migration event and schedules it in the migrations worker queue. + * + * @param \DateTime|int $at + * @return void + * @throws \Resque_Exception + * @throws \ResqueScheduler_InvalidTimestampException + */ + public function schedule(DateTime|int $at): void + { + ResqueScheduler::enqueueAt($at, $this->queue, $this->class, [ + 'project' => $this->project, + 'user' => $this->user, + 'migration' => $this->migration + ]); + } +} diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 6b448db8ec..77dc03e310 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -32,6 +32,7 @@ class Exception extends \Exception * - Platform * - Domain * - GraphQL + * - Migrations */ /** General */ @@ -53,6 +54,7 @@ class Exception extends \Exception public const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported'; public const GENERAL_CODES_DISABLED = 'general_codes_disabled'; public const GENERAL_USAGE_DISABLED = 'general_usage_disabled'; + public const GENERAL_NOT_IMPLEMENTED = 'general_not_implemented'; /** Users */ public const USER_COUNT_EXCEEDED = 'user_count_exceeded'; @@ -73,6 +75,7 @@ class Exception extends \Exception public const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; public const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; public const USER_SESSION_NOT_FOUND = 'user_session_not_found'; + public const USER_IDENTITY_NOT_FOUND = 'user_identity_not_found'; public const USER_UNAUTHORIZED = 'user_unauthorized'; public const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; public const USER_PHONE_ALREADY_EXISTS = 'user_phone_already_exists'; @@ -103,6 +106,7 @@ class Exception extends \Exception public const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; /** Storage */ + public const STORAGE_FILE_ALREADY_EXISTS = 'storage_file_already_exists'; public const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; public const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; public const STORAGE_FILE_EMPTY = 'storage_file_empty'; @@ -115,9 +119,17 @@ class Exception extends \Exception public const STORAGE_INVALID_RANGE = 'storage_invalid_range'; public const STORAGE_INVALID_APPWRITE_ID = 'storage_invalid_appwrite_id'; + /** VCS */ + public const INSTALLATION_NOT_FOUND = 'installation_not_found'; + public const PROVIDER_REPOSITORY_NOT_FOUND = 'provider_repository_not_found'; + public const REPOSITORY_NOT_FOUND = 'repository_not_found'; + public const PROVIDER_CONTRIBUTION_CONFLICT = 'provider_contribution_conflict'; + public const GENERAL_PROVIDER_FAILURE = 'general_provider_failure'; + /** Functions */ public const FUNCTION_NOT_FOUND = 'function_not_found'; public const FUNCTION_RUNTIME_UNSUPPORTED = 'function_runtime_unsupported'; + public const FUNCTION_ENTRYPOINT_MISSING = 'function_entrypoint_missing'; /** Deployments */ public const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; @@ -183,6 +195,16 @@ class Exception extends \Exception /** Webhooks */ public const WEBHOOK_NOT_FOUND = 'webhook_not_found'; + /** Router */ + public const ROUTER_HOST_NOT_FOUND = 'router_host_not_found'; + public const ROUTER_DOMAIN_NOT_CONFIGURED = 'router_domain_not_configured'; + + /** Proxy */ + public const RULE_RESOURCE_NOT_FOUND = 'rule_resource_not_found'; + public const RULE_NOT_FOUND = 'rule_not_found'; + public const RULE_ALREADY_EXISTS = 'rule_already_exists'; + public const RULE_VERIFICATION_FAILED = 'rule_verification_failed'; + /** Keys */ public const KEY_NOT_FOUND = 'key_not_found'; @@ -193,17 +215,15 @@ class Exception extends \Exception /** Platform */ public const PLATFORM_NOT_FOUND = 'platform_not_found'; - /** Domain */ - public const DOMAIN_NOT_FOUND = 'domain_not_found'; - public const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; - public const DOMAIN_FORBIDDEN = 'domain_forbidden'; - public const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; - public const DOMAIN_TARGET_INVALID = 'domain_target_invalid'; - /** GraphqQL */ public const GRAPHQL_NO_QUERY = 'graphql_no_query'; public const GRAPHQL_TOO_MANY_QUERIES = 'graphql_too_many_queries'; + /** Migrations */ + public const MIGRATION_NOT_FOUND = 'migration_not_found'; + public const MIGRATION_ALREADY_EXISTS = 'migration_already_exists'; + public const MIGRATION_IN_PROGRESS = 'migration_in_progress'; + protected $type = ''; protected $errors = []; diff --git a/src/Appwrite/GraphQL/Resolvers.php b/src/Appwrite/GraphQL/Resolvers.php index c143a93554..37bc1d922b 100644 --- a/src/Appwrite/GraphQL/Resolvers.php +++ b/src/Appwrite/GraphQL/Resolvers.php @@ -269,7 +269,7 @@ class Resolvers try { $route = $utopia->match($request, fresh: true); - $utopia->execute($route, $request); + $utopia->execute($route, $request, $response); } catch (\Throwable $e) { if ($beforeReject) { $e = $beforeReject($e); diff --git a/src/Appwrite/GraphQL/Types/Mapper.php b/src/Appwrite/GraphQL/Types/Mapper.php index 0be60d93dc..0f9ad661f6 100644 --- a/src/Appwrite/GraphQL/Types/Mapper.php +++ b/src/Appwrite/GraphQL/Types/Mapper.php @@ -256,10 +256,12 @@ class Mapper case 'Appwrite\Utopia\Database\Validator\Queries\Indexes': case 'Appwrite\Utopia\Database\Validator\Queries\Databases': case 'Appwrite\Utopia\Database\Validator\Queries\Deployments': + case 'Appwrite\Utopia\Database\Validator\Queries\Installations': case 'Utopia\Database\Validator\Queries\Documents': 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\Rules': case 'Appwrite\Utopia\Database\Validator\Queries\Memberships': case 'Utopia\Database\Validator\Permissions': case 'Appwrite\Utopia\Database\Validator\Queries\Projects': diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php index 33fe484c13..1925944664 100644 --- a/src/Appwrite/Messaging/Adapter/Realtime.php +++ b/src/Appwrite/Messaging/Adapter/Realtime.php @@ -260,6 +260,11 @@ class Realtime extends Adapter $channels[] = 'account.' . $parts[1]; $roles = [Role::user(ID::custom($parts[1]))->toString()]; break; + case 'rules': + $channels[] = 'console'; + $projectId = 'console'; + $roles = [Role::team($project->getAttribute('teamId'))->toString()]; + break; case 'teams': if ($parts[2] === 'memberships') { $permissionsChanged = $parts[4] ?? false; @@ -325,6 +330,11 @@ class Realtime extends Adapter $roles = [Role::team($project->getAttribute('teamId'))->toString()]; } + break; + case 'migrations': + $channels[] = 'console'; + $projectId = 'console'; + $roles = [Role::team($project->getAttribute('teamId'))->toString()]; break; } diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 9ea3443091..a73fa47ca7 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -65,6 +65,7 @@ abstract class Migration '1.3.7' => 'V18', '1.3.8' => 'V18', '1.4.0' => 'V19', + '1.4.1' => 'V19', ]; /** @@ -77,7 +78,11 @@ abstract class Migration Authorization::disable(); Authorization::setDefaultStatus(false); - $this->collections = array_merge([ + $this->collections = Config::getParam('collections', []); + + $projectCollections = $this->collections['projects']; + + $this->collections['projects'] = array_merge([ '_metadata' => [ '$id' => ID::custom('_metadata'), '$collection' => Database::METADATA @@ -90,7 +95,7 @@ abstract class Migration '$id' => ID::custom('abuse'), '$collection' => Database::METADATA ] - ], Config::getParam('collections', [])); + ], $projectCollections); } /** @@ -131,7 +136,14 @@ abstract class Migration */ public function forEachDocument(callable $callback): void { - foreach ($this->collections as $collection) { + $internalProjectId = $this->project->getInternalId(); + + $collections = match ($internalProjectId) { + 'console' => $this->collections['console'], + default => $this->collections['projects'], + }; + + foreach ($collections as $collection) { if ($collection['$collection'] !== Database::METADATA) { continue; } @@ -148,12 +160,12 @@ abstract class Migration $old = $document->getArrayCopy(); $new = call_user_func($callback, $document); - if (is_null($new) || !self::hasDifference($new->getArrayCopy(), $old)) { + if (is_null($new) || $new->getArrayCopy() == $old) { return; } try { - $new = $this->projectDB->updateDocument($document->getCollection(), $document->getId(), $document); + $this->projectDB->updateDocument($document->getCollection(), $document->getId(), $document); } catch (\Throwable $th) { Console::error('Failed to update document: ' . $th->getMessage()); return; @@ -199,32 +211,6 @@ abstract class Migration } while (!is_null($nextDocument)); } - /** - * Checks 2 arrays for differences. - * - * @param array $array1 - * @param array $array2 - * @return bool - */ - public static function hasDifference(array $array1, array $array2): bool - { - foreach ($array1 as $key => $value) { - if (is_array($value)) { - if (!isset($array2[$key]) || !is_array($array2[$key])) { - return true; - } else { - if (self::hasDifference($value, $array2[$key])) { - return true; - } - } - } elseif (!array_key_exists($key, $array2) || $array2[$key] !== $value) { - return true; - } - } - - return false; - } - /** * Creates colletion from the config collection. * @@ -237,10 +223,15 @@ abstract class Migration { $name ??= $id; + $collectionType = match ($this->project->getInternalId()) { + 'console' => 'console', + default => 'projects', + }; + if (!$this->projectDB->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), $name)) { $attributes = []; $indexes = []; - $collection = $this->collections[$id]; + $collection = $this->collections[$collectionType][$id]; foreach ($collection['attributes'] as $attribute) { $attributes[] = new Document([ @@ -286,10 +277,22 @@ abstract class Migration public function createAttributeFromCollection(Database $database, string $collectionId, string $attributeId, string $from = null): void { $from ??= $collectionId; - $collection = Config::getParam('collections', [])[$from] ?? null; - if (is_null($collection)) { - throw new Exception("Collection {$collectionId} not found"); + + $collectionType = match ($this->project->getInternalId()) { + 'console' => 'console', + default => 'projects', + }; + + if ($from === 'files') { + $collectionType = 'buckets'; } + + $collection = $this->collections[$collectionType][$from] ?? null; + + if (is_null($collection)) { + throw new Exception("Collection {$from} not found"); + } + $attributes = $collection['attributes']; $attributeKey = array_search($attributeId, array_column($attributes, '$id')); @@ -332,17 +335,24 @@ abstract class Migration public function createIndexFromCollection(Database $database, string $collectionId, string $indexId, string $from = null): void { $from ??= $collectionId; - $collection = Config::getParam('collections', [])[$collectionId] ?? null; + + $collectionType = match ($this->project->getInternalId()) { + 'console' => 'console', + default => 'projects', + }; + + $collection = $this->collections[$collectionType][$from] ?? null; if (is_null($collection)) { throw new Exception("Collection {$collectionId} not found"); } + $indexes = $collection['indexes']; $indexKey = array_search($indexId, array_column($indexes, '$id')); if ($indexKey === false) { - throw new Exception("Attribute {$indexId} not found"); + throw new Exception("Index {$indexId} not found"); } $index = $indexes[$indexKey]; diff --git a/src/Appwrite/Migration/Version/V17.php b/src/Appwrite/Migration/Version/V17.php index 3f744d8069..c0e2498e7f 100644 --- a/src/Appwrite/Migration/Version/V17.php +++ b/src/Appwrite/Migration/Version/V17.php @@ -70,6 +70,18 @@ class V17 extends Migration $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); switch ($id) { + case 'builds': + try { + /** + * Create 'size' attribute + */ + $this->createAttributeFromCollection($this->projectDB, $id, 'size'); + $this->projectDB->deleteCachedCollection($id); + } catch (\Throwable $th) { + Console::warning("'size' from {$id}: {$th->getMessage()}"); + } + + break; case 'files': try { /** diff --git a/src/Appwrite/Migration/Version/V19.php b/src/Appwrite/Migration/Version/V19.php index 75cd472ebb..d59aa8302c 100644 --- a/src/Appwrite/Migration/Version/V19.php +++ b/src/Appwrite/Migration/Version/V19.php @@ -2,12 +2,15 @@ namespace Appwrite\Migration\Version; -use Appwrite\Auth\Auth; -use Utopia\Config\Config; use Appwrite\Migration\Migration; +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\Exception; +use Utopia\Database\Query; class V19 extends Migration { @@ -28,117 +31,48 @@ class V19 extends Migration Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); - $this->alterPermissionIndex('_metadata'); - - Console::info('Migrating Databases'); - $this->migrateDatabases(); - Console::info('Migrating Collections'); $this->migrateCollections(); + if ($this->project->getId() == 'console') { + Console::info('Migrating Domains'); + $this->migrateDomains(); + } + Console::info('Migrating Buckets'); $this->migrateBuckets(); Console::info('Migrating Documents'); $this->forEachDocument([$this, 'fixDocument']); + + Console::log('Cleaning Up Collections'); + $this->cleanCollections(); } - /** - * Migrate all Databases. - * - * @return void - * @throws \Exception - */ - private function migrateDatabases(): void + protected function migrateDomains(): void { - foreach ($this->documentsIterator('databases') as $database) { - Console::log("Migrating Collections of {$database->getId()} ({$database->getAttribute('name')})"); - - $databaseTable = "database_{$database->getInternalId()}"; - - $this->alterPermissionIndex($databaseTable); - - foreach ($this->documentsIterator($databaseTable) as $collection) { - $collectionTable = "{$databaseTable}_collection_{$collection->getInternalId()}"; - Console::log("Migrating Collections of {$collectionTable} {$collection->getId()} ({$collection->getAttribute('name')})"); - $this->alterPermissionIndex($collectionTable); - } - } - } - - /** - * Migrate all Collections. - * - * @return void - */ - private function migrateCollections(): void - { - foreach ($this->collections as $collection) { - $id = $collection['$id']; - - Console::log("Migrating Collection \"{$id}\""); - - $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); - - switch ($id) { - case 'projects': - try { - /** - * Create 'passwordHistory' attribute - */ - $this->createAttributeFromCollection($this->projectDB, $id, 'smtp'); - $this->createAttributeFromCollection($this->projectDB, $id, 'templates'); - $this->projectDB->deleteCachedCollection($id); - } catch (\Throwable $th) { - Console::warning("'SMTP and Templates' from {$id}: {$th->getMessage()}"); - } - break; - default: - break; - } - if (!in_array($id, ['files', 'collections'])) { - $this->alterPermissionIndex($id); + foreach ($this->documentsIterator('domains') as $domain) { + $status = 'created'; + if ($domain->getAttribute('verification', false)) { + $status = 'verified'; } - usleep(50000); - } - } + $ruleDocument = new Document([ + 'projectId' => $domain->getAttribute('projectId'), + 'projectInternalId' => $domain->getAttribute('projectInternalId'), + 'domain' => $domain->getAttribute('domain'), + 'resourceType' => 'api', + 'resourceInternalId' => '', + 'resourceId' => '', + 'status' => $status, + 'certificateId' => $domain->getAttribute('certificateId'), + ]); - /** - * Fix run on each document - * - * @param Document $document - * @return Document - */ - protected function fixDocument(Document $document): Document - { - switch ($document->getCollection()) { - case 'projects': - /** - * Bump version number. - */ - $document->setAttribute('version', '1.4.0'); - - $document->setAttribute('smtp', []); - $document->setAttribute('templates', []); - - break; - } - - return $document; - } - - protected function alterPermissionIndex($collectionName): void - { - try { - $table = "`{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_{$collectionName}_perms"; - $this->pdo->prepare(" - ALTER TABLE {$table} - DROP INDEX `_permission`, - ADD INDEX `_permission` (`_permission`, `_type`, `_document`); - ")->execute(); - } catch (\Throwable $th) { - Console::warning($th->getMessage()); + try { + $this->consoleDB->createDocument('rules', $ruleDocument); + } catch (\Throwable $th) { + Console::warning("Error migrating domain {$domain->getAttribute('domain')}: {$th->getMessage()}"); + } } } @@ -154,7 +88,600 @@ class V19 extends Migration foreach ($this->documentsIterator('buckets') as $bucket) { $id = "bucket_{$bucket->getInternalId()}"; Console::log("Migrating Bucket {$id} {$bucket->getId()} ({$bucket->getAttribute('name')})"); - $this->alterPermissionIndex($id); + + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'bucketInternalId', 'files'); + $this->projectDB->deleteCachedCollection($id); + } catch (\Throwable $th) { + Console::warning("'bucketInternalId' from {$id}: {$th->getMessage()}"); + } } } + + /** + * Migrate all Collections. + * + * @return void + * @throws \Throwable + * @throws Exception + */ + private function migrateCollections(): void + { + $internalProjectId = $this->project->getInternalId(); + $collectionType = match ($internalProjectId) { + 'console' => 'console', + default => 'projects', + }; + $collections = $this->collections[$collectionType]; + foreach ($collections as $collection) { + $id = $collection['$id']; + + if ($id === 'schedules' && $internalProjectId === 'console') { + continue; + } + + Console::log("Migrating Collection \"{$id}\""); + + $this->projectDB->setNamespace("_$internalProjectId"); + + switch ($id) { + case '_metadata': + $this->createCollection('identities'); + $this->createCollection('migrations'); + // Holding off on this until a future release + // $this->createCollection('statsLogger'); + break; + case 'attributes': + case 'indexes': + try { + $this->projectDB->updateAttribute($id, 'databaseInternalId', required: true); + } catch (\Throwable $th) { + Console::warning("'databaseInternalId' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->updateAttribute($id, 'collectionInternalId', required: true); + } catch (\Throwable $th) { + Console::warning("'collectionInternalId' from {$id}: {$th->getMessage()}"); + } + + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'error'); + } catch (\Throwable $th) { + Console::warning("'error' from {$id}: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'buckets': + // Recreate indexes so they're the right size + $indexesToDelete = [ + '_key_name', + ]; + foreach ($indexesToDelete as $index) { + try { + $this->projectDB->deleteIndex($id, $index); + } catch (\Throwable $th) { + Console::warning("'$index' from {$id}: {$th->getMessage()}"); + } + } + + $indexesToCreate = [ + ...$indexesToDelete + ]; + + foreach ($indexesToCreate as $index) { + try { + $this->createIndexFromCollection($this->projectDB, $id, $index); + } catch (\Throwable $th) { + Console::warning("'$index' from {$id}: {$th->getMessage()}"); + } + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'builds': + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'deploymentInternalId'); + } catch (\Throwable $th) { + Console::warning("'deploymentInternalId' from {$id}: {$th->getMessage()}"); + } + + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'logs'); + } catch (\Throwable $th) { + Console::warning("'logs' from {$id}: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'certificates': + try { + $this->projectDB->renameAttribute($id, 'log', 'logs'); + } catch (\Throwable $th) { + Console::warning("'errors' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->updateAttribute($id, 'logs', size: 1000000); + } catch (\Throwable $th) { + Console::warning("'errors' from {$id}: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'databases': + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'enabled'); + } catch (\Throwable $th) { + Console::warning("'enabled' from {$id}: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'deployments': + $attributesToCreate = [ + 'resourceInternalId', + 'buildInternalId', + 'type', + ]; + foreach ($attributesToCreate as $attribute) { + try { + $this->createAttributeFromCollection($this->projectDB, $id, $attribute); + } catch (\Throwable $th) { + Console::warning("$attribute from {$id}: {$th->getMessage()}"); + } + } + + // Recreate indexes so they're the right size + $indexesToDelete = [ + '_key_entrypoint', + '_key_resource', + '_key_resource_type', + '_key_buildId', + ]; + foreach ($indexesToDelete as $index) { + try { + $this->projectDB->deleteIndex($id, $index); + } catch (\Throwable $th) { + Console::warning("'$index' from {$id}: {$th->getMessage()}"); + } + } + + $indexesToCreate = [ + '_key_resource', + '_key_resource_type', + '_key_buildId', + ]; + foreach ($indexesToCreate as $index) { + try { + $this->createIndexFromCollection($this->projectDB, $id, $index); + } catch (\Throwable $th) { + Console::warning("'$index' from {$id}: {$th->getMessage()}"); + } + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'executions': + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'functionInternalId'); + } catch (\Throwable $th) { + Console::warning("'functionInternalId' from {$id}: {$th->getMessage()}"); + } + + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'deploymentInternalId'); + } catch (\Throwable $th) { + Console::warning("'deploymentInternalId' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->renameAttribute($id, 'stderr', 'errors'); + } catch (\Throwable $th) { + Console::warning("'errors' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->renameAttribute($id, 'stdout', 'logs'); + } catch (\Throwable $th) { + Console::warning("'logs' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->renameAttribute($id, 'statusCode', 'responseStatusCode'); + } catch (\Throwable $th) { + Console::warning("'responseStatusCode' from {$id}: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'files': + // Recreate indexes so they're the right size + $indexesToDelete = [ + '_key_name', + '_key_signature', + '_key_mimeType', + ]; + foreach ($indexesToDelete as $index) { + try { + $this->projectDB->deleteIndex($id, $index); + } catch (\Throwable $th) { + Console::warning("'$index' from {$id}: {$th->getMessage()}"); + } + } + + $indexesToCreate = $indexesToDelete; + foreach ($indexesToCreate as $index) { + try { + $this->createIndexFromCollection($this->projectDB, $id, $index); + } catch (\Throwable $th) { + Console::warning("'$index' from {$id}: {$th->getMessage()}"); + } + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'functions': + $attributesToCreate = [ + 'live', + 'installationId', + 'installationInternalId', + 'providerRepositoryId', + 'repositoryId', + 'repositoryInternalId', + 'providerBranch', + 'providerRootDirectory', + 'providerSilentMode', + 'logging', + 'deploymentInternalId', + 'scheduleInternalId', + 'scheduleId', + 'version', + 'entrypoint', + 'commands', + ]; + foreach ($attributesToCreate as $attribute) { + try { + $this->createAttributeFromCollection($this->projectDB, $id, $attribute); + } catch (\Throwable $th) { + Console::warning("'$attribute' from {$id}: {$th->getMessage()}"); + } + } + + // Recreate indexes so they're the right size + $indexesToDelete = [ + '_key_name', + '_key_runtime', + '_key_deployment', + ]; + foreach ($indexesToDelete as $index) { + try { + $this->projectDB->deleteIndex($id, $index); + } catch (\Throwable $th) { + Console::warning("'$index' from {$id}: {$th->getMessage()}"); + } + } + + $indexesToCreate = [ + ...$indexesToDelete, + '_key_installationId', + '_key_installationInternalId', + '_key_providerRepositoryId', + '_key_repositoryId', + '_key_repositoryInternalId', + ]; + foreach ($indexesToCreate as $index) { + try { + $this->createIndexFromCollection($this->projectDB, $id, $index); + } catch (\Throwable $th) { + Console::warning("'$index' from {$id}: {$th->getMessage()}"); + } + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'memberships': + try { + $this->projectDB->updateAttribute($id, 'teamInternalId', required: true); + } catch (\Throwable $th) { + Console::warning("'teamInternalId' from {$id}: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection($id); + + // Intentional fall through to update memberships.userInternalId + case 'sessions': + case 'tokens': + try { + $this->projectDB->updateAttribute($id, 'userInternalId', required: true); + } catch (\Throwable $th) { + Console::warning("'userInternalId' from {$id}: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'domains': + case 'keys': + case 'platforms': + case 'webhooks': + try { + $this->projectDB->updateAttribute($id, 'projectInternalId', required: true); + } catch (\Throwable $th) { + Console::warning("'projectInternalId' from {$id}: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'projects': + $attributesToCreate = [ + 'database', + 'smtp', + 'templates', + ]; + foreach ($attributesToCreate as $attribute) { + try { + $this->createAttributeFromCollection($this->projectDB, $id, $attribute); + } catch (\Throwable $th) { + Console::warning("'$attribute' from {$id}: {$th->getMessage()}"); + Console::warning($th->getTraceAsString()); + } + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'stats': + try { + $this->projectDB->updateAttribute($id, 'value', signed: true); + } catch (\Throwable $th) { + Console::warning("'value' from {$id}: {$th->getMessage()}"); + } + + // Holding off on these until a future release + // try { + // $this->projectDB->deleteAttribute($id, 'type'); + // $this->projectDB->deleteCachedCollection($id); + // } catch (\Throwable $th) { + // Console::warning("'type' from {$id}: {$th->getMessage()}"); + // } + + // try { + // $this->projectDB->deleteIndex($id, '_key_metric_period_time'); + // $this->projectDB->deleteCachedCollection($id); + // } catch (\Throwable $th) { + // Console::warning("'_key_metric_period_time' from {$id}: {$th->getMessage()}"); + // } + + // try { + // $this->createIndexFromCollection($this->projectDB, $id, '_key_metric_period_time'); + // $this->projectDB->deleteCachedCollection($id); + // } catch (\Throwable $th) { + // Console::warning("'_key_metric_period_time' from {$id}: {$th->getMessage()}"); + // } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'users': + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'labels'); + } catch (\Throwable $th) { + Console::warning("'labels' from {$id}: {$th->getMessage()}"); + } + + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'accessedAt'); + } catch (\Throwable $th) { + Console::warning("'accessedAt' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->updateAttribute($id, 'search', filters: ['userSearch']); + } catch (\Throwable $th) { + Console::warning("'search' from {$id}: {$th->getMessage()}"); + } + + try { + $this->createIndexFromCollection($this->projectDB, $id, '_key_accessedAt'); + } catch (\Throwable $th) { + Console::warning("'_key_accessedAt' from {$id}: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection($id); + + break; + case 'variables': + try { + $this->projectDB->deleteIndex($id, '_key_function'); + } catch (\Throwable $th) { + Console::warning("'_key_function' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->deleteIndex($id, '_key_uniqueKey'); + } catch (\Throwable $th) { + Console::warning("'_key_uniqueKey' from {$id}: {$th->getMessage()}"); + } + + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'resourceType'); + } catch (\Throwable $th) { + Console::warning("'resourceType' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->renameAttribute($id, 'functionInternalId', 'resourceInternalId'); + } catch (\Throwable $th) { + Console::warning("'resourceInternalId' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->renameAttribute($id, 'functionId', 'resourceId'); + } catch (\Throwable $th) { + Console::warning("'resourceId' from {$id}: {$th->getMessage()}"); + } + + $indexesToCreate = [ + '_key_resourceInternalId', + '_key_resourceId_resourceType', + '_key_resourceType', + '_key_uniqueKey', + ]; + foreach ($indexesToCreate as $index) { + try { + $this->createIndexFromCollection($this->projectDB, $id, $index); + } catch (\Throwable $th) { + Console::warning("'$index' from {$id}: {$th->getMessage()}"); + } + } + + $this->projectDB->deleteCachedCollection($id); + + break; + default: + break; + } + + usleep(50000); + } + } + + /** + * Fix run on each document + * + * @param Document $document + * @return Document + */ + protected function fixDocument(Document $document): Document + { + switch ($document->getCollection()) { + case 'attributes': + case 'indexes': + $status = $document->getAttribute('status', ''); + if ($status === 'failed') { + $document->setAttribute('error', 'Unknown problem'); + } + break; + case 'builds': + $deploymentId = $document->getAttribute('deploymentId'); + $deployment = $this->projectDB->getDocument('deployments', $deploymentId); + $document->setAttribute('deploymentInternalId', $deployment->getInternalId()); + + $stdout = $document->getAttribute('stdout', ''); + $stderr = $document->getAttribute('stderr', ''); + $document->setAttribute('logs', $stdout . PHP_EOL . $stderr); + break; + case 'databases': + $document->setAttribute('enabled', true); + break; + case 'deployments': + $resourceId = $document->getAttribute('resourceId'); + $function = $this->projectDB->getDocument('functions', $resourceId); + $document->setAttribute('resourceInternalId', $function->getInternalId()); + + $buildId = $document->getAttribute('buildId'); + if (!empty($buildId)) { + $build = $this->projectDB->getDocument('builds', $buildId); + $document->setAttribute('buildInternalId', $build->getInternalId()); + } + + $document->setAttribute('type', 'manual'); + break; + case 'executions': + $functionId = $document->getAttribute('functionId'); + $function = $this->projectDB->getDocument('functions', $functionId); + $document->setAttribute('functionInternalId', $function->getInternalId()); + + $deploymentId = $document->getAttribute('deploymentId'); + $deployment = $this->projectDB->getDocument('deployments', $deploymentId); + $document->setAttribute('deploymentInternalId', $deployment->getInternalId()); + break; + case 'functions': + $document->setAttribute('live', true); + $document->setAttribute('logging', true); + $document->setAttribute('version', 'v2'); + $deploymentId = $document->getAttribute('deployment'); + + if (!empty($deploymentId)) { + $deployment = $this->projectDB->getDocument('deployments', $deploymentId); + $document->setAttribute('deploymentInternalId', $deployment->getInternalId()); + $document->setAttribute('entrypoint', $deployment->getAttribute('entrypoint')); + } + + $schedule = $this->consoleDB->createDocument('schedules', new Document([ + 'region' => App::getEnv('_APP_REGION', 'default'), // Todo replace with projects region + 'resourceType' => 'function', + 'resourceId' => $document->getId(), + 'resourceInternalId' => $document->getInternalId(), + 'resourceUpdatedAt' => DateTime::now(), + 'projectId' => $this->project->getId(), + 'schedule' => $document->getAttribute('schedule'), + 'active' => !empty($document->getAttribute('schedule')) && !empty($document->getAttribute('deployment')), + ])); + + $document->setAttribute('scheduleId', $schedule->getId()); + $document->setAttribute('scheduleInternalId', $schedule->getInternalId()); + break; + case 'projects': + $document->setAttribute('version', '1.4.0'); + + $databases = Config::getParam('pools-database', []); + $database = $databases[0]; + + $document->setAttribute('database', $database); + $document->setAttribute('smtp', []); + $document->setAttribute('templates', []); + + break; + default: + break; + } + + return $document; + } + + private function cleanCollections(): void + { + try { + $this->projectDB->deleteAttribute('projects', 'domains'); + } catch (\Throwable $th) { + Console::warning("'domains' from projects: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection('projects'); + + try { + $this->projectDB->deleteAttribute('functions', 'schedule'); + } catch (\Throwable $th) { + Console::warning("'schedule' from functions: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection('functions'); + + try { + $this->projectDB->deleteAttribute('builds', 'stderr'); + } catch (\Throwable $th) { + Console::warning("'stderr' from builds: {$th->getMessage()}"); + } + + try { + $this->projectDB->deleteAttribute('builds', 'stdout'); + } catch (\Throwable $th) { + Console::warning("'stdout' from builds: {$th->getMessage()}"); + } + + $this->projectDB->deleteCachedCollection('builds'); + } } diff --git a/src/Appwrite/Platform/Services/Tasks.php b/src/Appwrite/Platform/Services/Tasks.php index 9e919127bf..bc8d1bbc72 100644 --- a/src/Appwrite/Platform/Services/Tasks.php +++ b/src/Appwrite/Platform/Services/Tasks.php @@ -22,6 +22,7 @@ use Appwrite\Platform\Tasks\VolumeSync; use Appwrite\Platform\Tasks\CalcUsersStats; use Appwrite\Platform\Tasks\CalcTierStats; use Appwrite\Platform\Tasks\PatchDeleteProjectCollections; +use Appwrite\Platform\Tasks\Upgrade; class Tasks extends Service { @@ -30,11 +31,13 @@ class Tasks extends Service $this->type = self::TYPE_CLI; $this ->addAction(Version::getName(), new Version()) + ->addAction(Usage::getName(), new Usage()) ->addAction(Vars::getName(), new Vars()) ->addAction(SSL::getName(), new SSL()) ->addAction(Hamster::getName(), new Hamster()) ->addAction(Doctor::getName(), new Doctor()) ->addAction(Install::getName(), new Install()) + ->addAction(Upgrade::getName(), new Upgrade()) ->addAction(Maintenance::getName(), new Maintenance()) ->addAction(PatchCreateMissingSchedules::getName(), new PatchCreateMissingSchedules()) ->addAction(ClearCardCache::getName(), new ClearCardCache()) diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index be12eadf62..22355d0269 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -6,7 +6,9 @@ use Appwrite\Auth\Auth; use Appwrite\Docker\Compose; use Appwrite\Docker\Env; use Appwrite\Utopia\View; -use Utopia\Analytics\GoogleAnalytics; +use Utopia\Analytics\Adapter; +use Utopia\Analytics\Adapter\GoogleAnalytics; +use Utopia\Analytics\Event; use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Validator\Text; @@ -14,6 +16,8 @@ use Utopia\Platform\Action; class Install extends Action { + protected string $path = '/usr/src/code/appwrite'; + public static function getName(): string { return 'install'; @@ -33,24 +37,7 @@ class Install extends Action public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive): void { - /** - * 1. Start - DONE - * 2. Check for older setup and get older version - DONE - * 2.1 If older version is equal or bigger(?) than current version, **stop setup** - * 2.2. Get ENV vars - DONE - * 2.2.1 Fetch from older docker-compose.yml file - * 2.2.2 Fetch from older .env file (manually parse) - * 2.3 Use old ENV vars as default values - * 2.4 Ask for all required vars not given as CLI args and if in interactive mode - * Otherwise, just use default vars. - DONE - * 3. Ask user to backup important volumes, env vars, and SQL tables - * In th future we can try and automate this for smaller/medium size setups - * 4. Drop new docker-compose.yml setup (located inside the container, no network dependencies with appwrite.io) - DONE - * 5. Run docker compose up -d - DONE - * 6. Run data migration - */ $config = Config::getParam('variables'); - $path = '/usr/src/code/appwrite'; $defaultHTTPPort = '80'; $defaultHTTPSPort = '443'; $vars = []; @@ -70,19 +57,28 @@ class Install extends Action Console::success('Starting Appwrite installation...'); // Create directory with write permissions - if (null !== $path && !\file_exists(\dirname($path))) { - if (!@\mkdir(\dirname($path), 0755, true)) { - Console::error('Can\'t create directory ' . \dirname($path)); + if (!\file_exists(\dirname($this->path))) { + if (!@\mkdir(\dirname($this->path), 0755, true)) { + Console::error('Can\'t create directory ' . \dirname($this->path)); Console::exit(1); } } - $data = @file_get_contents($path . '/docker-compose.yml'); + $data = @file_get_contents($this->path . '/docker-compose.yml'); if ($data !== false) { + if ($interactive == 'Y' && Console::isInteractive()) { + $answer = Console::confirm('Previous installation found, do you want to overwrite it (a backup will be created before overwriting)? (Y/n)'); + + if ($answer !== 'Y') { + Console::info('No action taken.'); + return; + } + } + $time = \time(); Console::info('Compose file found, creating backup: docker-compose.yml.' . $time . '.backup'); - file_put_contents($path . '/docker-compose.yml.' . $time . '.backup', $data); + file_put_contents($this->path . '/docker-compose.yml.' . $time . '.backup', $data); $compose = new Compose($data); $appwrite = $compose->getService('appwrite'); $oldVersion = ($appwrite) ? $appwrite->getImageVersion() : null; @@ -116,11 +112,11 @@ class Install extends Action } } - $data = @file_get_contents($path . '/.env'); + $data = @file_get_contents($this->path . '/.env'); if ($data !== false) { // Fetch all env vars from previous .env file Console::info('Env file found, creating backup: .env.' . $time . '.backup'); - file_put_contents($path . '/.env.' . $time . '.backup', $data); + file_put_contents($this->path . '/.env.' . $time . '.backup', $data); $env = new Env($data); foreach ($env->list() as $key => $value) { @@ -198,31 +194,28 @@ class Install extends Action } } - $templateForCompose = new View(__DIR__ . '/../views/install/compose.phtml'); - $templateForEnv = new View(__DIR__ . '/../views/install/env.phtml'); + $templateForCompose = new View(__DIR__ . '/../../../../app/views/install/compose.phtml'); + $templateForEnv = new View(__DIR__ . '/../../../../app/views/install/env.phtml'); $templateForCompose ->setParam('httpPort', $httpPort) ->setParam('httpsPort', $httpsPort) ->setParam('version', APP_VERSION_STABLE) ->setParam('organization', $organization) - ->setParam('image', $image) - ; + ->setParam('image', $image); - $templateForEnv - ->setParam('vars', $input) - ; + $templateForEnv->setParam('vars', $input); - if (!file_put_contents($path . '/docker-compose.yml', $templateForCompose->render(false))) { + if (!file_put_contents($this->path . '/docker-compose.yml', $templateForCompose->render(false))) { $message = 'Failed to save Docker Compose file'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); + $this->sendEvent($analytics, $message); Console::error($message); Console::exit(1); } - if (!file_put_contents($path . '/.env', $templateForEnv->render(false))) { + if (!file_put_contents($this->path . '/.env', $templateForEnv->render(false))) { $message = 'Failed to save environment variables file'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); + $this->sendEvent($analytics, $message); Console::error($message); Console::exit(1); } @@ -239,18 +232,33 @@ class Install extends Action Console::log("Running \"docker compose up -d --remove-orphans --renew-anon-volumes\""); - $exit = Console::execute("${env} docker compose --project-directory {$path} up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr); + $exit = Console::execute("$env docker compose --project-directory $this->path up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr); if ($exit !== 0) { $message = 'Failed to install Appwrite dockers'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); + $this->sendEvent($analytics, $message); Console::error($message); Console::error($stderr); Console::exit($exit); } else { $message = 'Appwrite installed successfully'; - $analytics->createEvent('install/server', 'install', APP_VERSION_STABLE . ' - ' . $message); + $this->sendEvent($analytics, $message); Console::success($message); } } + + private function sendEvent(Adapter $analytics, string $message): void + { + $event = new Event(); + $event->setName(APP_VERSION_STABLE); + $event->setValue($message); + $event->setUrl('http://localhost/'); + $event->setProps([ + 'category' => 'install/server', + 'action' => 'install', + ]); + $event->setType('install/server'); + + $analytics->createEvent($event); + } } diff --git a/src/Appwrite/Platform/Tasks/Maintenance.php b/src/Appwrite/Platform/Tasks/Maintenance.php index 0739923e34..eb98b1bb3b 100644 --- a/src/Appwrite/Platform/Tasks/Maintenance.php +++ b/src/Appwrite/Platform/Tasks/Maintenance.php @@ -2,7 +2,6 @@ namespace Appwrite\Platform\Tasks; -use Appwrite\Auth\Auth; use Appwrite\Event\Certificate; use Appwrite\Event\Delete; use Utopia\App; @@ -109,7 +108,6 @@ class Maintenance extends Action function notifyDeleteCache($interval) { - (new Delete()) ->setType(DELETE_TYPE_CACHE_BY_TIMESTAMP) ->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * $interval)) @@ -118,7 +116,6 @@ class Maintenance extends Action function notifyDeleteSchedules($interval) { - (new Delete()) ->setType(DELETE_TYPE_SCHEDULES) ->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * $interval)) diff --git a/src/Appwrite/Platform/Tasks/Migrate.php b/src/Appwrite/Platform/Tasks/Migrate.php index 90b4234109..38e5c8aa46 100644 --- a/src/Appwrite/Platform/Tasks/Migrate.php +++ b/src/Appwrite/Platform/Tasks/Migrate.php @@ -7,10 +7,10 @@ use Utopia\CLI\Console; use Appwrite\Migration\Migration; use Utopia\App; use Utopia\Cache\Cache; -use Utopia\Cache\Adapter\Redis as RedisCache; +use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; -use Utopia\Registry\Registry; use Utopia\Validator\Text; class Migrate extends Action @@ -26,20 +26,22 @@ class Migrate extends Action ->desc('Migrate Appwrite to new version') /** @TODO APP_VERSION_STABLE needs to be defined */ ->param('version', APP_VERSION_STABLE, new Text(8), 'Version to migrate to.', true) - ->inject('register') - ->callback(fn ($version, $register) => $this->action($version, $register)); + ->inject('cache') + ->inject('dbForConsole') + ->inject('getProjectDB') + ->callback(fn ($version, $cache, $dbForConsole, $getProjectDB) => $this->action($version, $cache, $dbForConsole, $getProjectDB)); } - private function clearProjectsCache(Redis $redis, Document $project) + private function clearProjectsCache(Cache $cache, Document $project) { try { - $redis->del($redis->keys("cache-_{$project->getInternalId()}:*")); + $cache->purge("cache-_{$project->getInternalId()}:*"); } catch (\Throwable $th) { Console::error('Failed to clear project ("' . $project->getId() . '") cache with error: ' . $th->getMessage()); } } - public function action(string $version, Registry $register) + public function action(string $version, Cache $cache, Database $dbForConsole, callable $getProjectDB) { Authorization::disable(); if (!array_key_exists($version, Migration::$versions)) { @@ -52,14 +54,6 @@ class Migrate extends Action Console::success('Starting Data Migration to version ' . $version); - $dbPool = $register->get('dbPool', true); - $redis = $register->get('cache', true); - - $cache = new Cache(new RedisCache($redis)); - - $dbForConsole = $dbPool->getDB('console', $cache); - $dbForConsole->setNamespace('_project_console'); - $console = $app->getResource('console'); $limit = 30; @@ -79,6 +73,7 @@ class Migrate extends Action } $class = 'Appwrite\\Migration\\Version\\' . Migration::$versions[$version]; + /** @var Migration $migration */ $migration = new $class(); while (!empty($projects)) { @@ -90,11 +85,11 @@ class Migrate extends Action continue; } - $this->clearProjectsCache($redis, $project); + $this->clearProjectsCache($cache, $project); try { // TODO: Iterate through all project DBs - $projectDB = $dbPool->getDB($project->getId(), $cache); + $projectDB = $getProjectDB($project); $migration ->setProject($project, $projectDB, $dbForConsole) ->execute(); @@ -103,11 +98,11 @@ class Migrate extends Action throw $th; } - $this->clearProjectsCache($redis, $project); + $this->clearProjectsCache($cache, $project); } $sum = \count($projects); - $projects = $dbForConsole->find('projects', limit: $limit, offset: $offset); + $projects = $dbForConsole->find('projects', [Query::limit($limit), Query::offset($offset)]); $offset = $offset + $limit; $count = $count + $sum; @@ -115,7 +110,6 @@ class Migrate extends Action Console::log('Migrated ' . $count . '/' . $totalProjects . ' projects...'); } - Swoole\Event::wait(); // Wait for Coroutines to finish Console::success('Data Migration Completed'); } } diff --git a/src/Appwrite/Platform/Tasks/SDKs.php b/src/Appwrite/Platform/Tasks/SDKs.php index f70ae8bd60..a052acf373 100644 --- a/src/Appwrite/Platform/Tasks/SDKs.php +++ b/src/Appwrite/Platform/Tasks/SDKs.php @@ -51,7 +51,7 @@ class SDKs extends Action $production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false; $message = ($git) ? Console::confirm('Please enter your commit message:') : ''; - if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', '1.3.x', 'latest'])) { + if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', '1.3.x', '1.4.x', 'latest'])) { throw new Exception('Unknown version given'); } @@ -232,7 +232,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ->setTwitter(APP_SOCIAL_TWITTER_HANDLE) ->setDiscord(APP_SOCIAL_DISCORD_CHANNEL, APP_SOCIAL_DISCORD) ->setDefaultHeaders([ - 'X-Appwrite-Response-Format' => '1.0.0', + 'X-Appwrite-Response-Format' => '1.4.0', ]); try { diff --git a/src/Appwrite/Platform/Tasks/Specs.php b/src/Appwrite/Platform/Tasks/Specs.php index 82caf8ef72..2a22c59103 100644 --- a/src/Appwrite/Platform/Tasks/Specs.php +++ b/src/Appwrite/Platform/Tasks/Specs.php @@ -40,8 +40,6 @@ class Specs extends Action public function action(string $version, string $mode, Registry $register): void { - //$db = $register->get('db'); - //$redis = $register->get('cache'); $appRoutes = App::getRoutes(); $response = new Response(new HttpResponse()); $mocks = ($mode === 'mocks'); diff --git a/src/Appwrite/Platform/Tasks/Upgrade.php b/src/Appwrite/Platform/Tasks/Upgrade.php new file mode 100644 index 0000000000..e3f0458394 --- /dev/null +++ b/src/Appwrite/Platform/Tasks/Upgrade.php @@ -0,0 +1,42 @@ +desc('Upgrade Appwrite') + ->param('httpPort', '', new Text(4), 'Server HTTP port', true) + ->param('httpsPort', '', new Text(4), 'Server HTTPS port', true) + ->param('organization', 'appwrite', new Text(0), 'Docker Registry organization', true) + ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) + ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) + ->callback(fn ($httpPort, $httpsPort, $organization, $image, $interactive) => $this->action($httpPort, $httpsPort, $organization, $image, $interactive)); + } + + public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive): void + { + // Check for previous installation + $data = @file_get_contents($this->path . '/docker-compose.yml'); + if (empty($data)) { + Console::error('Appwrite installation not found.'); + Console::log('The command was not run in the parent folder of your appwrite installation.'); + Console::log('Please navigate to the parent directory of the Appwrite installation and try again.'); + Console::log(' parent_directory <= you run the command in this directory'); + Console::log(' └── appwrite'); + Console::log(' └── docker-compose.yml'); + Console::exit(1); + } + parent::action($httpPort, $httpsPort, $organization, $image, $interactive); + } +} diff --git a/src/Appwrite/Platform/Tasks/Usage.php b/src/Appwrite/Platform/Tasks/Usage.php new file mode 100644 index 0000000000..fa677ea142 --- /dev/null +++ b/src/Appwrite/Platform/Tasks/Usage.php @@ -0,0 +1,60 @@ +desc('Schedules syncing data from influxdb to Appwrite console db') + ->inject('dbForConsole') + ->inject('influxdb') + ->inject('register') + ->inject('getProjectDB') + ->inject('logError') + ->callback(fn ($dbForConsole, $influxDB, $register, $getProjectDB, $logError) => $this->action($dbForConsole, $influxDB, $register, $getProjectDB, $logError)); + } + + protected function aggregateTimeseries(UtopiaDatabase $database, InfluxDatabase $influxDB, callable $logError): void + { + } + + public function action(UtopiaDatabase $dbForConsole, InfluxDatabase $influxDB, Registry $register, callable $getProjectDB, callable $logError) + { + Console::title('Usage Aggregation V1'); + Console::success(APP_NAME . ' usage aggregation process v1 has started'); + + $errorLogger = fn(Throwable $error, string $action = 'syncUsageStats') => $logError($error, "usage", $action); + + $interval = (int) App::getEnv('_APP_USAGE_AGGREGATION_INTERVAL', '30'); // 30 seconds (by default) + $region = App::getEnv('region', 'default'); + $usage = new TimeSeries($region, $dbForConsole, $influxDB, $getProjectDB, $register, $errorLogger); + + Console::loop(function () use ($interval, $usage) { + $now = date('d-m-Y H:i:s', time()); + Console::info("[{$now}] Aggregating Timeseries Usage data every {$interval} seconds"); + $loopStart = microtime(true); + + $usage->collect(); + + $loopTook = microtime(true) - $loopStart; + $now = date('d-m-Y H:i:s', time()); + Console::info("[{$now}] Aggregation took {$loopTook} seconds"); + }, $interval); + } +} diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index 146500e743..7693f1e6ff 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -223,7 +223,7 @@ abstract class Worker if (isset(self::$databases[$databaseName])) { $database = self::$databases[$databaseName]; - $database->setNamespace('console'); + $database->setNamespace('_console'); return $database; } @@ -237,7 +237,7 @@ abstract class Worker self::$databases[$databaseName] = $database; - $database->setNamespace('console'); + $database->setNamespace('_console'); return $database; } @@ -328,38 +328,82 @@ abstract class Worker public function getDevice(string $root): Device { $connection = App::getEnv('_APP_CONNECTIONS_STORAGE', ''); - $acl = 'private'; - $device = Storage::DEVICE_LOCAL; - $accessKey = ''; - $accessSecret = ''; - $bucket = ''; - $region = ''; - try { - $dsn = new DSN($connection); - $device = $dsn->getScheme(); - $accessKey = $dsn->getUser(); - $accessSecret = $dsn->getPassword(); - $bucket = $dsn->getPath(); - $region = $dsn->getParam('region'); - } catch (\Exception $e) { - Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); - } + if (!empty($connection)) { + $acl = 'private'; + $device = Storage::DEVICE_LOCAL; + $accessKey = ''; + $accessSecret = ''; + $bucket = ''; + $region = ''; - switch ($device) { - case Storage::DEVICE_S3: - return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case STORAGE::DEVICE_DO_SPACES: - return new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case Storage::DEVICE_BACKBLAZE: - return new Backblaze($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case Storage::DEVICE_LINODE: - return new Linode($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case Storage::DEVICE_WASABI: - return new Wasabi($root, $accessKey, $accessSecret, $bucket, $region, $acl); - case Storage::DEVICE_LOCAL: - default: - return new Local($root); + try { + $dsn = new DSN($connection); + $device = $dsn->getScheme(); + $accessKey = $dsn->getUser() ?? ''; + $accessSecret = $dsn->getPassword() ?? ''; + $bucket = $dsn->getPath() ?? ''; + $region = $dsn->getParam('region'); + } catch (\Exception $e) { + Console::warning($e->getMessage() . 'Invalid DSN. Defaulting to Local device.'); + } + + switch ($device) { + case Storage::DEVICE_S3: + return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case STORAGE::DEVICE_DO_SPACES: + return new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case Storage::DEVICE_BACKBLAZE: + return new Backblaze($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case Storage::DEVICE_LINODE: + return new Linode($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case Storage::DEVICE_WASABI: + return new Wasabi($root, $accessKey, $accessSecret, $bucket, $region, $acl); + case Storage::DEVICE_LOCAL: + default: + return new Local($root); + } + } else { + switch (strtolower(App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL) ?? '')) { + case Storage::DEVICE_LOCAL: + default: + return new Local($root); + case Storage::DEVICE_S3: + $s3AccessKey = App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', ''); + $s3SecretKey = App::getEnv('_APP_STORAGE_S3_SECRET', ''); + $s3Region = App::getEnv('_APP_STORAGE_S3_REGION', ''); + $s3Bucket = App::getEnv('_APP_STORAGE_S3_BUCKET', ''); + $s3Acl = 'private'; + return new S3($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl); + case Storage::DEVICE_DO_SPACES: + $doSpacesAccessKey = App::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', ''); + $doSpacesSecretKey = App::getEnv('_APP_STORAGE_DO_SPACES_SECRET', ''); + $doSpacesRegion = App::getEnv('_APP_STORAGE_DO_SPACES_REGION', ''); + $doSpacesBucket = App::getEnv('_APP_STORAGE_DO_SPACES_BUCKET', ''); + $doSpacesAcl = 'private'; + return new DOSpaces($root, $doSpacesAccessKey, $doSpacesSecretKey, $doSpacesBucket, $doSpacesRegion, $doSpacesAcl); + case Storage::DEVICE_BACKBLAZE: + $backblazeAccessKey = App::getEnv('_APP_STORAGE_BACKBLAZE_ACCESS_KEY', ''); + $backblazeSecretKey = App::getEnv('_APP_STORAGE_BACKBLAZE_SECRET', ''); + $backblazeRegion = App::getEnv('_APP_STORAGE_BACKBLAZE_REGION', ''); + $backblazeBucket = App::getEnv('_APP_STORAGE_BACKBLAZE_BUCKET', ''); + $backblazeAcl = 'private'; + return new Backblaze($root, $backblazeAccessKey, $backblazeSecretKey, $backblazeBucket, $backblazeRegion, $backblazeAcl); + case Storage::DEVICE_LINODE: + $linodeAccessKey = App::getEnv('_APP_STORAGE_LINODE_ACCESS_KEY', ''); + $linodeSecretKey = App::getEnv('_APP_STORAGE_LINODE_SECRET', ''); + $linodeRegion = App::getEnv('_APP_STORAGE_LINODE_REGION', ''); + $linodeBucket = App::getEnv('_APP_STORAGE_LINODE_BUCKET', ''); + $linodeAcl = 'private'; + return new Linode($root, $linodeAccessKey, $linodeSecretKey, $linodeBucket, $linodeRegion, $linodeAcl); + case Storage::DEVICE_WASABI: + $wasabiAccessKey = App::getEnv('_APP_STORAGE_WASABI_ACCESS_KEY', ''); + $wasabiSecretKey = App::getEnv('_APP_STORAGE_WASABI_SECRET', ''); + $wasabiRegion = App::getEnv('_APP_STORAGE_WASABI_REGION', ''); + $wasabiBucket = App::getEnv('_APP_STORAGE_WASABI_BUCKET', ''); + $wasabiAcl = 'private'; + return new Wasabi($root, $wasabiAccessKey, $wasabiSecretKey, $wasabiBucket, $wasabiRegion, $wasabiAcl); + } } } } diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 94cb0bb90d..863966eedd 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -347,10 +347,13 @@ class OpenAPI3 extends Format case 'Appwrite\Utopia\Database\Validator\Queries\Attributes': case 'Appwrite\Utopia\Database\Validator\Queries\Databases': case 'Appwrite\Utopia\Database\Validator\Queries\Deployments': + case 'Appwrite\Utopia\Database\Validator\Queries\Installations': + case 'Appwrite\Utopia\Database\Validator\Queries\Documents': case 'Utopia\Database\Validator\Queries\Documents': 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\Rules': case 'Appwrite\Utopia\Database\Validator\Queries\Memberships': case 'Appwrite\Utopia\Database\Validator\Queries\Projects': case 'Appwrite\Utopia\Database\Validator\Queries\Teams': diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 6b3d394aad..c6ae7a7ff1 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -347,10 +347,13 @@ class Swagger2 extends Format case 'Appwrite\Utopia\Database\Validator\Queries\Attributes': case 'Appwrite\Utopia\Database\Validator\Queries\Databases': case 'Appwrite\Utopia\Database\Validator\Queries\Deployments': + case 'Appwrite\Utopia\Database\Validator\Queries\Installations': + case 'Appwrite\Utopia\Database\Validator\Queries\Documents': case 'Utopia\Database\Validator\Queries\Documents': 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\Rules': case 'Appwrite\Utopia\Database\Validator\Queries\Memberships': case 'Appwrite\Utopia\Database\Validator\Queries\Projects': case 'Appwrite\Utopia\Database\Validator\Queries\Teams': diff --git a/src/Appwrite/Usage/Calculator.php b/src/Appwrite/Usage/Calculator.php new file mode 100644 index 0000000000..37c130a34a --- /dev/null +++ b/src/Appwrite/Usage/Calculator.php @@ -0,0 +1,15 @@ +region = $region; + } + + abstract public function collect(): void; +} diff --git a/src/Appwrite/Usage/Calculators/TimeSeries.php b/src/Appwrite/Usage/Calculators/TimeSeries.php new file mode 100644 index 0000000000..e0a12b443f --- /dev/null +++ b/src/Appwrite/Usage/Calculators/TimeSeries.php @@ -0,0 +1,557 @@ + '1h', + 'startTime' => '-24 hours' + ], + [ + 'key' => '1d', + 'startTime' => '-30 days' + ] + ]; + + /** + * All the metrics that we are collecting + * + * @var array + */ + protected array $metrics = [ + 'project.$all.network.requests' => [ + 'table' => 'appwrite_usage_project_{scope}_network_requests', + ], + 'project.$all.network.bandwidth' => [ + 'table' => 'appwrite_usage_project_{scope}_network_bandwidth', + ], + 'project.$all.network.inbound' => [ + 'table' => 'appwrite_usage_project_{scope}_network_inbound', + ], + 'project.$all.network.outbound' => [ + 'table' => 'appwrite_usage_project_{scope}_network_outbound', + ], + /* Users service metrics */ + 'users.$all.requests.create' => [ + 'table' => 'appwrite_usage_users_{scope}_requests_create', + ], + 'users.$all.requests.read' => [ + 'table' => 'appwrite_usage_users_{scope}_requests_read', + ], + 'users.$all.requests.update' => [ + 'table' => 'appwrite_usage_users_{scope}_requests_update', + ], + 'users.$all.requests.delete' => [ + 'table' => 'appwrite_usage_users_{scope}_requests_delete', + ], + + 'databases.$all.requests.create' => [ + 'table' => 'appwrite_usage_databases_{scope}_requests_create', + ], + 'databases.$all.requests.read' => [ + 'table' => 'appwrite_usage_databases_{scope}_requests_read', + ], + 'databases.$all.requests.update' => [ + 'table' => 'appwrite_usage_databases_{scope}_requests_update', + ], + 'databases.$all.requests.delete' => [ + 'table' => 'appwrite_usage_databases_{scope}_requests_delete', + ], + + 'collections.$all.requests.create' => [ + 'table' => 'appwrite_usage_collections_{scope}_requests_create', + ], + 'collections.$all.requests.read' => [ + 'table' => 'appwrite_usage_collections_{scope}_requests_read', + ], + 'collections.$all.requests.update' => [ + 'table' => 'appwrite_usage_collections_{scope}_requests_update', + ], + 'collections.$all.requests.delete' => [ + 'table' => 'appwrite_usage_collections_{scope}_requests_delete', + ], + + 'documents.$all.requests.create' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_create', + ], + 'documents.$all.requests.read' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_read', + ], + 'documents.$all.requests.update' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_update', + ], + 'documents.$all.requests.delete' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_delete', + ], + + 'collections.databaseId.requests.create' => [ + 'table' => 'appwrite_usage_collections_{scope}_requests_create', + 'groupBy' => ['databaseId'], + ], + 'collections.databaseId.requests.read' => [ + 'table' => 'appwrite_usage_collections_{scope}_requests_read', + 'groupBy' => ['databaseId'], + ], + 'collections.databaseId.requests.update' => [ + 'table' => 'appwrite_usage_collections_{scope}_requests_update', + 'groupBy' => ['databaseId'], + ], + 'collections.databaseId.requests.delete' => [ + 'table' => 'appwrite_usage_collections_{scope}_requests_delete', + 'groupBy' => ['databaseId'], + ], + + 'documents.databaseId.requests.create' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_create', + 'groupBy' => ['databaseId'], + ], + 'documents.databaseId.requests.read' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_read', + 'groupBy' => ['databaseId'], + ], + 'documents.databaseId.requests.update' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_update', + 'groupBy' => ['databaseId'], + ], + 'documents.databaseId.requests.delete' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_delete', + 'groupBy' => ['databaseId'], + ], + + 'documents.databaseId/collectionId.requests.create' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_create', + 'groupBy' => ['databaseId', 'collectionId'], + ], + 'documents.databaseId/collectionId.requests.read' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_read', + 'groupBy' => ['databaseId', 'collectionId'], + ], + 'documents.databaseId/collectionId.requests.update' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_update', + 'groupBy' => ['databaseId', 'collectionId'], + ], + 'documents.databaseId/collectionId.requests.delete' => [ + 'table' => 'appwrite_usage_documents_{scope}_requests_delete', + 'groupBy' => ['databaseId', 'collectionId'], + ], + + 'buckets.$all.requests.create' => [ + 'table' => 'appwrite_usage_buckets_{scope}_requests_create', + ], + 'buckets.$all.requests.read' => [ + 'table' => 'appwrite_usage_buckets_{scope}_requests_read', + ], + 'buckets.$all.requests.update' => [ + 'table' => 'appwrite_usage_buckets_{scope}_requests_update', + ], + 'buckets.$all.requests.delete' => [ + 'table' => 'appwrite_usage_buckets_{scope}_requests_delete', + ], + + 'files.$all.requests.create' => [ + 'table' => 'appwrite_usage_files_{scope}_requests_create', + ], + 'files.$all.requests.read' => [ + 'table' => 'appwrite_usage_files_{scope}_requests_read', + ], + 'files.$all.requests.update' => [ + 'table' => 'appwrite_usage_files_{scope}_requests_update', + ], + 'files.$all.requests.delete' => [ + 'table' => 'appwrite_usage_files_{scope}_requests_delete', + ], + + 'files.bucketId.requests.create' => [ + 'table' => 'appwrite_usage_files_{scope}_requests_create', + 'groupBy' => ['bucketId'], + ], + 'files.bucketId.requests.read' => [ + 'table' => 'appwrite_usage_files_{scope}_requests_read', + 'groupBy' => ['bucketId'], + ], + 'files.bucketId.requests.update' => [ + 'table' => 'appwrite_usage_files_{scope}_requests_update', + 'groupBy' => ['bucketId'], + ], + 'files.bucketId.requests.delete' => [ + 'table' => 'appwrite_usage_files_{scope}_requests_delete', + 'groupBy' => ['bucketId'], + ], + + 'sessions.$all.requests.create' => [ + 'table' => 'appwrite_usage_sessions__{scope}_requests_create', + ], + 'sessions.provider.requests.create' => [ + 'table' => 'appwrite_usage_sessions_{scope}_requests_create', + 'groupBy' => ['provider'], + ], + 'sessions.$all.requests.delete' => [ + 'table' => 'appwrite_usage_sessions_{scope}_requests_delete', + ], + 'executions.$all.compute.total' => [ + 'table' => 'appwrite_usage_executions_{scope}_compute', + ], + 'builds.$all.compute.total' => [ + 'table' => 'appwrite_usage_builds_{scope}_compute', + ], + 'executions.$all.compute.failure' => [ + 'table' => 'appwrite_usage_executions_{scope}_compute', + 'filters' => [ + 'functionStatus' => 'failed', + ], + ], + 'builds.$all.compute.failure' => [ + 'table' => 'appwrite_usage_builds_{scope}_compute', + 'filters' => [ + 'functionStatus' => 'failed', + ], + ], + 'executions.$all.compute.success' => [ + 'table' => 'appwrite_usage_executions_{scope}_compute', + 'filters' => [ + 'functionStatus' => 'success', + ], + ], + 'builds.$all.compute.success' => [ + 'table' => 'appwrite_usage_builds_{scope}_compute', + 'filters' => [ + 'functionStatus' => 'success', + ], + ], + 'executions.functionId.compute.total' => [ + 'table' => 'appwrite_usage_executions_{scope}_compute', + 'groupBy' => ['functionId'], + ], + 'builds.functionId.compute.total' => [ + 'table' => 'appwrite_usage_builds_{scope}_compute', + 'groupBy' => ['functionId'], + ], + + 'executions.functionId.compute.failure' => [ + 'table' => 'appwrite_usage_executions_{scope}_compute', + 'groupBy' => ['functionId'], + 'filters' => [ + 'functionStatus' => 'failed', + ], + ], + 'builds.functionId.compute.failure' => [ + 'table' => 'appwrite_usage_builds_{scope}_compute', + 'groupBy' => ['functionId'], + 'filters' => [ + 'functionBuildStatus' => 'failed', + ], + ], + 'executions.functionId.compute.success' => [ + 'table' => 'appwrite_usage_executions_{scope}_compute', + 'groupBy' => ['functionId'], + 'filters' => [ + 'functionStatus' => 'success', + ], + ], + 'builds.functionId.compute.success' => [ + 'table' => 'appwrite_usage_builds_{scope}_compute', + 'groupBy' => ['functionId'], + 'filters' => [ + 'functionBuildStatus' => 'success', + ], + ], + + // counters + 'users.$all.count.total' => [ + 'table' => 'appwrite_usage_users_{scope}_count_total', + ], + 'buckets.$all.count.total' => [ + 'table' => 'appwrite_usage_buckets_{scope}_count_total', + ], + 'files.$all.count.total' => [ + 'table' => 'appwrite_usage_files_{scope}_count_total', + ], + 'files.bucketId.count.total' => [ + 'table' => 'appwrite_usage_files_{scope}_count_total', + 'groupBy' => ['bucketId'] + ], + 'databases.$all.count.total' => [ + 'table' => 'appwrite_usage_databases_{scope}_count_total', + ], + 'collections.$all.count.total' => [ + 'table' => 'appwrite_usage_collections_{scope}_count_total', + ], + 'documents.$all.count.total' => [ + 'table' => 'appwrite_usage_documents_{scope}_count_total', + ], + 'collections.databaseId.count.total' => [ + 'table' => 'appwrite_usage_collections_{scope}_count_total', + 'groupBy' => ['databaseId'] + ], + 'documents.databaseId.count.total' => [ + 'table' => 'appwrite_usage_documents_{scope}_count_total', + 'groupBy' => ['databaseId'] + ], + 'documents.databaseId/collectionId.count.total' => [ + 'table' => 'appwrite_usage_documents_{scope}_count_total', + 'groupBy' => ['databaseId', 'collectionId'] + ], + 'deployments.$all.storage.size' => [ + 'table' => 'appwrite_usage_deployments_{scope}_storage_size', + ], + 'project.$all.storage.size' => [ + 'table' => 'appwrite_usage_project_{scope}_storage_size', + ], + 'files.$all.storage.size' => [ + 'table' => 'appwrite_usage_files_{scope}_storage_size', + ], + 'files.$bucketId.storage.size' => [ + 'table' => 'appwrite_usage_files_{scope}_storage_size', + 'groupBy' => ['bucketId'] + ], + + 'builds.$all.compute.time' => [ + 'table' => 'appwrite_usage_executions_{scope}_compute_time', + ], + 'executions.$all.compute.time' => [ + 'table' => 'appwrite_usage_executions_{scope}_compute_time', + ], + + 'executions.functionId.compute.time' => [ + 'table' => 'appwrite_usage_executions_{scope}_compute_time', + 'groupBy' => ['functionId'], + ], + 'builds.functionId.compute.time' => [ + 'table' => 'appwrite_usage_builds_{scope}_compute_time', + 'groupBy' => ['functionId'], + ], + + 'project.$all.compute.time' => [ // Built time + execution time + 'table' => 'appwrite_usage_project_{scope}_compute_time', + 'groupBy' => ['functionId'], + ], + + 'deployments.$all.storage.size' => [ + 'table' => 'appwrite_usage_deployments_{scope}_storage_size' + ], + 'project.$all.storage.size' => [ + 'table' => 'appwrite_usage_project_{scope}_storage_size' + ], + 'files.$all.storage.size' => [ + 'table' => 'appwrite_usage_files_{scope}_storage_size' + ], + 'files.bucketId.storage.size' => [ + 'table' => 'appwrite_usage_files_{scope}_storage_size', + 'groupBy' => ['bucketId'] + ] + ]; + + public function __construct(string $region, Database $database, InfluxDatabase $influxDB, callable $getProjectDB, Registry $register, callable $errorHandler = null) + { + parent::__construct($region); + $this->database = $database; + $this->influxDB = $influxDB; + $this->getProjectDB = $getProjectDB; + $this->register = $register; + $this->errorHandler = $errorHandler; + } + + /** + * Create or Update Mertic + * Create or update each metric in the stats collection for the given project + * + * @param string $projectId + * @param int $time + * @param string $period + * @param string $metric + * @param int $value + * @param int $type + * + * @return void + */ + private function createOrUpdateMetric(string $projectId, string $time, string $period, string $metric, int $value, int $type): void + { + $id = \md5("{$time}_{$period}_{$metric}"); + $project = $this->database->getDocument('projects', $projectId); + $database = call_user_func($this->getProjectDB, $project); + + try { + $document = $database->getDocument('stats', $id); + if ($document->isEmpty()) { + $database->createDocument('stats', new Document([ + '$id' => $id, + 'period' => $period, + 'time' => $time, + 'metric' => $metric, + 'value' => $value, + 'type' => $type, + 'region' => $this->region, + ])); + } else { + $database->updateDocument( + 'stats', + $document->getId(), + $document->setAttribute('value', $value) + ); + } + } catch (\Exception $e) { // if projects are deleted this might fail + if (is_callable($this->errorHandler)) { + call_user_func($this->errorHandler, $e, "sync_project_{$projectId}_metric_{$metric}"); + } else { + throw $e; + } + } + + $this->register->get('pools')->reclaim(); + } + + /** + * Sync From InfluxDB + * Sync stats from influxDB to stats collection in the Appwrite database + * + * @param string $metric + * @param array $options + * @param array $period + * + * @return void + */ + private function syncFromInfluxDB(string $metric, array $options, array $period): void + { + $start = DateTime::createFromFormat('U', \strtotime($period['startTime']))->format(DateTime::RFC3339); + if (!empty($this->latestTime[$metric][$period['key']])) { + $start = $this->latestTime[$metric][$period['key']]; + } + $end = (new DateTime())->format(DateTime::RFC3339); + + $table = $options['table']; //Which influxdb table to query for this metric + $groupBy = empty($options['groupBy']) ? '' : ', ' . implode(', ', array_map(fn($groupBy) => '"' . $groupBy . '" ', $options['groupBy'])); //Some sub level metrics may be grouped by other tags like collectionId, bucketId, etc + + $filters = $options['filters'] ?? []; // Some metrics might have additional filters, like function's status + if (!empty($filters)) { + $filters = ' AND ' . implode(' AND ', array_map(fn ($filter, $value) => "\"{$filter}\"='{$value}'", array_keys($filters), array_values($filters))); + } else { + $filters = ''; + } + + $query = "SELECT sum(value) AS \"value\" "; + $query .= "FROM \"{$table}\" "; + $query .= "WHERE \"time\" > '{$start}' "; + $query .= "AND \"time\" < '{$end}' "; + $query .= "AND \"metric_type\"='counter' {$filters} "; + $query .= "GROUP BY time({$period['key']}), \"projectId\" {$groupBy} "; + $query .= "FILL(null)"; + + try { + $result = $this->influxDB->query($query); + $points = $result->getPoints(); + foreach ($points as $point) { + $projectId = $point['projectId']; + + if (!empty($projectId) && $projectId !== 'console') { + $metricUpdated = $metric; + if (!empty($groupBy)) { + foreach ($options['groupBy'] as $groupBy) { + $groupedBy = $point[$groupBy] ?? ''; + if (empty($groupedBy)) { + continue; + } + $metricUpdated = str_replace($groupBy, $groupedBy, $metricUpdated); + } + } + + $value = (!empty($point['value'])) ? $point['value'] : 0; + + $this->createOrUpdateMetric( + $point['projectId'], + $point['time'], + $period['key'], + $metricUpdated, + $value, + 0 + ); + $this->latestTime[$metric][$period['key']] = $point['time']; + } + } + } catch (\Exception $e) { // if projects are deleted this might fail + if (is_callable($this->errorHandler)) { + call_user_func($this->errorHandler, $e, "sync_metric_{$metric}_influxdb"); + } else { + throw $e; + } + } + } + + /** + * Collect Stats + * Collect all the stats from Influd DB to Database + * + * @return void + */ + public function collect(): void + { + foreach ($this->periods as $period) { + foreach ($this->metrics as $metric => $options) { //for each metrics + try { + $this->syncFromInfluxDB($metric, $options, $period); + } catch (\Exception $e) { + if (is_callable($this->errorHandler)) { + call_user_func($this->errorHandler, $e); + } else { + throw $e; + } + } + } + } + } +} diff --git a/src/Appwrite/Usage/Stats.php b/src/Appwrite/Usage/Stats.php new file mode 100644 index 0000000000..e6e0056664 --- /dev/null +++ b/src/Appwrite/Usage/Stats.php @@ -0,0 +1,225 @@ +statsd = $statsd; + } + + /** + * @param string $key + * @param mixed $value + * + * @return $this + */ + public function setParam(string $key, $value): self + { + $this->params[$key] = $value; + + return $this; + } + + /** + * @param string $key + * + * @return mixed|null + */ + public function getParam(string $key) + { + return (isset($this->params[$key])) ? $this->params[$key] : null; + } + + /** + * @param string $namespace + * + * @return $this + */ + public function setNamespace(string $namespace): self + { + $this->namespace = $namespace; + + return $this; + } + + /** + * @return string + */ + public function getNamespace() + { + return $this->namespace; + } + + /** + * Submit data to StatsD. + * Send various metrics to StatsD based on the parameters that are set + * @return void + */ + public function submit(): void + { + $projectId = $this->params['projectId'] ?? ''; + $projectInternalId = $this->params['projectInternalId']; + $tags = ",projectInternalId={$projectInternalId},projectId={$projectId},version=" . App::getEnv('_APP_VERSION', 'UNKNOWN'); + + // the global namespace is prepended to every key (optional) + $this->statsd->setNamespace($this->namespace); + + $httpRequest = $this->params['project.{scope}.network.requests'] ?? 0; + $httpMethod = $this->params['httpMethod'] ?? ''; + if ($httpRequest >= 1) { + $this->statsd->increment('project.{scope}.network.requests' . $tags . ',method=' . \strtolower($httpMethod)); + } + + $inbound = $this->params['project.{scope}.network.inbound'] ?? 0; + $outbound = $this->params['project.{scope}.network.outbound'] ?? 0; + $this->statsd->count('project.{scope}.network.inbound' . $tags, $inbound); + $this->statsd->count('project.{scope}.network.outbound' . $tags, $outbound); + $this->statsd->count('project.{scope}.network.bandwidth' . $tags, $inbound + $outbound); + + $usersMetrics = [ + 'users.{scope}.requests.create', + 'users.{scope}.requests.read', + 'users.{scope}.requests.update', + 'users.{scope}.requests.delete', + 'users.{scope}.count.total', + ]; + + foreach ($usersMetrics as $metric) { + $value = $this->params[$metric] ?? 0; + if ($value === 1 || $value === -1) { + $this->statsd->count($metric . $tags, $value); + } + } + + $dbMetrics = [ + 'databases.{scope}.requests.create', + 'databases.{scope}.requests.read', + 'databases.{scope}.requests.update', + 'databases.{scope}.requests.delete', + 'collections.{scope}.requests.create', + 'collections.{scope}.requests.read', + 'collections.{scope}.requests.update', + 'collections.{scope}.requests.delete', + 'documents.{scope}.requests.create', + 'documents.{scope}.requests.read', + 'documents.{scope}.requests.update', + 'documents.{scope}.requests.delete', + 'databases.{scope}.count.total', + 'collections.{scope}.count.total', + 'documents.{scope}.count.total' + ]; + + foreach ($dbMetrics as $metric) { + $value = $this->params[$metric] ?? 0; + if ($value === 1 || $value === -1) { + $dbTags = $tags . ",collectionId=" . ($this->params['collectionId'] ?? '') . ",databaseId=" . ($this->params['databaseId'] ?? ''); + $this->statsd->count($metric . $dbTags, $value); + } + } + + $storageMertics = [ + 'buckets.{scope}.requests.create', + 'buckets.{scope}.requests.read', + 'buckets.{scope}.requests.update', + 'buckets.{scope}.requests.delete', + 'files.{scope}.requests.create', + 'files.{scope}.requests.read', + 'files.{scope}.requests.update', + 'files.{scope}.requests.delete', + 'buckets.{scope}.count.total', + 'files.{scope}.count.total', + 'files.{scope}.storage.size' + ]; + + foreach ($storageMertics as $metric) { + $value = $this->params[$metric] ?? 0; + if ($value !== 0) { + $storageTags = $tags . ",bucketId=" . ($this->params['bucketId'] ?? ''); + $this->statsd->count($metric . $storageTags, $value); + } + } + + $sessionsMetrics = [ + 'sessions.{scope}.requests.create', + 'sessions.{scope}.requests.update', + 'sessions.{scope}.requests.delete', + ]; + + foreach ($sessionsMetrics as $metric) { + $value = $this->params[$metric] ?? 0; + if ($value >= 1) { + $sessionTags = $tags . ",provider=" . ($this->params['provider'] ?? ''); + $this->statsd->count($metric . $sessionTags, $value); + } + } + + $functionId = $this->params['functionId'] ?? ''; + $functionExecution = $this->params['executions.{scope}.compute'] ?? 0; + $functionExecutionTime = ($this->params['executionTime'] ?? 0) * 1000; // ms + $functionExecutionStatus = $this->params['executionStatus'] ?? ''; + + $functionBuild = $this->params['builds.{scope}.compute'] ?? 0; + $functionBuildTime = ($this->params['buildTime'] ?? 0) * 1000; // ms + $functionBuildStatus = $this->params['buildStatus'] ?? ''; + $functionCompute = $functionExecutionTime + $functionBuildTime; + $functionTags = $tags . ',functionId=' . $functionId; + + $deploymentSize = $this->params['deployment.{scope}.storage.size'] ?? 0; + $storageSize = $this->params['files.{scope}.storage.size'] ?? 0; + if ($deploymentSize + $storageSize > 0 || $deploymentSize + $storageSize <= -1) { + $this->statsd->count('project.{scope}.storage.size' . $tags, $deploymentSize + $storageSize); + } + + if ($deploymentSize !== 0) { + $this->statsd->count('deployments.{scope}.storage.size' . $functionTags, $deploymentSize); + } + + if ($functionExecution >= 1) { + $this->statsd->increment('executions.{scope}.compute' . $functionTags . ',functionStatus=' . $functionExecutionStatus); + if ($functionExecutionTime > 0) { + $this->statsd->count('executions.{scope}.compute.time' . $functionTags, $functionExecutionTime); + } + } + if ($functionBuild >= 1) { + $this->statsd->increment('builds.{scope}.compute' . $functionTags . ',functionBuildStatus=' . $functionBuildStatus); + $this->statsd->count('builds.{scope}.compute.time' . $functionTags, $functionBuildTime); + } + if ($functionBuild + $functionExecution >= 1) { + $this->statsd->count('project.{scope}.compute.time' . $functionTags, $functionCompute); + } + + $this->reset(); + } + + public function reset(): self + { + $this->params = []; + $this->namespace = 'appwrite.usage'; + + return $this; + } +} diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php b/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php index 05b3326af1..427779efa5 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php @@ -5,10 +5,11 @@ namespace Appwrite\Utopia\Database\Validator\Queries; class Deployments extends Base { public const ALLOWED_ATTRIBUTES = [ - 'entrypoint', 'size', 'buildId', 'activate', + 'entrypoint', + 'commands' ]; /** diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php b/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php index 2bfe46e28d..ecceab7fae 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php @@ -7,7 +7,7 @@ class Executions extends Base public const ALLOWED_ATTRIBUTES = [ 'trigger', 'status', - 'statusCode', + 'responseStatusCode', 'duration' ]; diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php b/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php index a2ba368953..89f5d52c81 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php @@ -12,7 +12,10 @@ class Functions extends Base 'schedule', 'scheduleNext', 'schedulePrevious', - 'timeout' + 'timeout', + 'entrypoint', + 'commands', + 'installationId' ]; /** diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php b/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php new file mode 100644 index 0000000000..cb0462ee13 --- /dev/null +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Identities.php @@ -0,0 +1,23 @@ +getCommands($content['runtime'] ?? ''); + break; + case 'functions.update': + $content['commands'] = $this->getCommands($content['runtime'] ?? ''); + break; + case 'functions.createExecution': + $content['body'] = $content['data']; + unset($content['data']); + break; + } + + return $content; + } + + private function getCommands(string $runtime): string + { + if (\str_starts_with($runtime, 'node')) { + return 'npm install'; + } elseif (\str_starts_with($runtime, 'python')) { + return 'pip install --no-cache-dir -r requirements.txt'; + } elseif (\str_starts_with($runtime, 'dart')) { + return 'dart pub get'; + } elseif (\str_starts_with($runtime, 'php')) { + return 'composer update --no-interaction --ignore-platform-reqs --optimize-autoloader --prefer-dist --no-dev'; + } elseif (\str_starts_with($runtime, 'ruby')) { + return 'bundle install'; + } elseif (\str_starts_with($runtime, 'swift')) { + return 'swift package resolve'; + } elseif (\str_starts_with($runtime, 'dotnet')) { + return 'dotnet restore'; + } + + return ''; + } +} diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 63e9170008..7e52536eed 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -32,6 +32,7 @@ use Appwrite\Utopia\Response\Model\AttributeURL; use Appwrite\Utopia\Response\Model\AttributeDatetime; use Appwrite\Utopia\Response\Model\AttributeRelationship; use Appwrite\Utopia\Response\Model\BaseList; +use Appwrite\Utopia\Response\Model\Branch; use Appwrite\Utopia\Response\Model\Collection; use Appwrite\Utopia\Response\Model\Database; use Appwrite\Utopia\Response\Model\Continent; @@ -47,6 +48,7 @@ use Appwrite\Utopia\Response\Model\File; use Appwrite\Utopia\Response\Model\Bucket; use Appwrite\Utopia\Response\Model\ConsoleVariables; use Appwrite\Utopia\Response\Model\Func; +use Appwrite\Utopia\Response\Model\Identity; use Appwrite\Utopia\Response\Model\Index; use Appwrite\Utopia\Response\Model\JWT; use Appwrite\Utopia\Response\Model\Key; @@ -64,6 +66,8 @@ use Appwrite\Utopia\Response\Model\Platform; use Appwrite\Utopia\Response\Model\Project; use Appwrite\Utopia\Response\Model\Rule; use Appwrite\Utopia\Response\Model\Deployment; +use Appwrite\Utopia\Response\Model\Detection; +use Appwrite\Utopia\Response\Model\Headers; use Appwrite\Utopia\Response\Model\TemplateEmail; use Appwrite\Utopia\Response\Model\Token; use Appwrite\Utopia\Response\Model\Webhook; @@ -73,9 +77,10 @@ use Appwrite\Utopia\Response\Model\HealthQueue; use Appwrite\Utopia\Response\Model\HealthStatus; use Appwrite\Utopia\Response\Model\HealthTime; use Appwrite\Utopia\Response\Model\HealthVersion; +use Appwrite\Utopia\Response\Model\Installation; use Appwrite\Utopia\Response\Model\LocaleCode; -use Appwrite\Utopia\Response\Model\Mock; // Keep last use Appwrite\Utopia\Response\Model\Provider; +use Appwrite\Utopia\Response\Model\ProviderRepository; use Appwrite\Utopia\Response\Model\Runtime; use Appwrite\Utopia\Response\Model\TemplateSMS; use Appwrite\Utopia\Response\Model\UsageBuckets; @@ -88,6 +93,11 @@ use Appwrite\Utopia\Response\Model\UsageProject; use Appwrite\Utopia\Response\Model\UsageStorage; use Appwrite\Utopia\Response\Model\UsageUsers; use Appwrite\Utopia\Response\Model\Variable; +use Appwrite\Utopia\Response\Model\Migration; +use Appwrite\Utopia\Response\Model\MigrationFirebaseProject; +use Appwrite\Utopia\Response\Model\MigrationReport; +// Keep last +use Appwrite\Utopia\Response\Model\Mock; /** * @method int getStatusCode() @@ -145,6 +155,8 @@ class Response extends SwooleResponse public const MODEL_USER_LIST = 'userList'; public const MODEL_SESSION = 'session'; public const MODEL_SESSION_LIST = 'sessionList'; + public const MODEL_IDENTITY = 'identity'; + public const MODEL_IDENTITY_LIST = 'identityList'; public const MODEL_TOKEN = 'token'; public const MODEL_JWT = 'jwt'; public const MODEL_PREFERENCES = 'preferences'; @@ -185,6 +197,15 @@ class Response extends SwooleResponse public const MODEL_MEMBERSHIP = 'membership'; public const MODEL_MEMBERSHIP_LIST = 'membershipList'; + // VCS + public const MODEL_INSTALLATION = 'installation'; + public const MODEL_INSTALLATION_LIST = 'installationList'; + public const MODEL_PROVIDER_REPOSITORY = 'providerRepository'; + public const MODEL_PROVIDER_REPOSITORY_LIST = 'providerRepositoryList'; + public const MODEL_BRANCH = 'branch'; + public const MODEL_BRANCH_LIST = 'branchList'; + public const MODEL_DETECTION = 'detection'; + // Functions public const MODEL_FUNCTION = 'function'; public const MODEL_FUNCTION_LIST = 'functionList'; @@ -197,6 +218,18 @@ class Response extends SwooleResponse public const MODEL_BUILD = 'build'; public const MODEL_BUILD_LIST = 'buildList'; // Not used anywhere yet public const MODEL_FUNC_PERMISSIONS = 'funcPermissions'; + public const MODEL_HEADERS = 'headers'; + + // Proxy + public const MODEL_PROXY_RULE = 'proxyRule'; + public const MODEL_PROXY_RULE_LIST = 'proxyRuleList'; + + // Migrations + public const MODEL_MIGRATION = 'migration'; + public const MODEL_MIGRATION_LIST = 'migrationList'; + public const MODEL_MIGRATION_REPORT = 'migrationReport'; + public const MODEL_MIGRATION_FIREBASE_PROJECT = 'firebaseProject'; + public const MODEL_MIGRATION_FIREBASE_PROJECT_LIST = 'firebaseProjectList'; // Project public const MODEL_PROJECT = 'project'; @@ -209,10 +242,9 @@ class Response extends SwooleResponse public const MODEL_PROVIDER_LIST = 'providerList'; public const MODEL_PLATFORM = 'platform'; public const MODEL_PLATFORM_LIST = 'platformList'; - public const MODEL_DOMAIN = 'domain'; - public const MODEL_DOMAIN_LIST = 'domainList'; public const MODEL_VARIABLE = 'variable'; public const MODEL_VARIABLE_LIST = 'variableList'; + public const MODEL_VCS = 'vcs'; public const MODEL_SMS_TEMPLATE = 'smsTemplate'; public const MODEL_EMAIL_TEMPLATE = 'emailTemplate'; @@ -231,6 +263,8 @@ class Response extends SwooleResponse public const MODEL_PERMISSIONS = 'permissions'; public const MODEL_RULE = 'rule'; public const MODEL_TASK = 'task'; + public const MODEL_DOMAIN = 'domain'; + public const MODEL_DOMAIN_LIST = 'domainList'; // Tests (keep last) public const MODEL_MOCK = 'mock'; @@ -265,12 +299,16 @@ class Response extends SwooleResponse ->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX)) ->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER)) ->setModel(new BaseList('Sessions List', self::MODEL_SESSION_LIST, 'sessions', self::MODEL_SESSION)) + ->setModel(new BaseList('Identities List', self::MODEL_IDENTITY_LIST, 'identities', self::MODEL_IDENTITY)) ->setModel(new BaseList('Logs List', self::MODEL_LOG_LIST, 'logs', self::MODEL_LOG)) ->setModel(new BaseList('Files List', self::MODEL_FILE_LIST, 'files', self::MODEL_FILE)) ->setModel(new BaseList('Buckets List', self::MODEL_BUCKET_LIST, 'buckets', self::MODEL_BUCKET)) ->setModel(new BaseList('Teams List', self::MODEL_TEAM_LIST, 'teams', self::MODEL_TEAM)) ->setModel(new BaseList('Memberships List', self::MODEL_MEMBERSHIP_LIST, 'memberships', self::MODEL_MEMBERSHIP)) ->setModel(new BaseList('Functions List', self::MODEL_FUNCTION_LIST, 'functions', self::MODEL_FUNCTION)) + ->setModel(new BaseList('Installations List', self::MODEL_INSTALLATION_LIST, 'installations', self::MODEL_INSTALLATION)) + ->setModel(new BaseList('Provider Repositories List', self::MODEL_PROVIDER_REPOSITORY_LIST, 'providerRepositories', self::MODEL_PROVIDER_REPOSITORY)) + ->setModel(new BaseList('Branches List', self::MODEL_BRANCH_LIST, 'branches', self::MODEL_BRANCH)) ->setModel(new BaseList('Runtimes List', self::MODEL_RUNTIME_LIST, 'runtimes', self::MODEL_RUNTIME)) ->setModel(new BaseList('Deployments List', self::MODEL_DEPLOYMENT_LIST, 'deployments', self::MODEL_DEPLOYMENT)) ->setModel(new BaseList('Executions List', self::MODEL_EXECUTION_LIST, 'executions', self::MODEL_EXECUTION)) @@ -280,7 +318,6 @@ class Response extends SwooleResponse ->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false)) ->setModel(new BaseList('Providers List', self::MODEL_PROVIDER_LIST, 'platforms', self::MODEL_PROVIDER, true, false)) ->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM, true, false)) - ->setModel(new BaseList('Domains List', self::MODEL_DOMAIN_LIST, 'domains', self::MODEL_DOMAIN, true, false)) ->setModel(new BaseList('Countries List', self::MODEL_COUNTRY_LIST, 'countries', self::MODEL_COUNTRY)) ->setModel(new BaseList('Continents List', self::MODEL_CONTINENT_LIST, 'continents', self::MODEL_CONTINENT)) ->setModel(new BaseList('Languages List', self::MODEL_LANGUAGE_LIST, 'languages', self::MODEL_LANGUAGE)) @@ -289,7 +326,10 @@ class Response extends SwooleResponse ->setModel(new BaseList('Metric List', self::MODEL_METRIC_LIST, 'metrics', self::MODEL_METRIC, true, false)) ->setModel(new BaseList('Variables List', self::MODEL_VARIABLE_LIST, 'variables', self::MODEL_VARIABLE)) ->setModel(new BaseList('Status List', self::MODEL_HEALTH_STATUS_LIST, 'statuses', self::MODEL_HEALTH_STATUS)) + ->setModel(new BaseList('Rule List', self::MODEL_PROXY_RULE_LIST, 'rules', self::MODEL_PROXY_RULE)) ->setModel(new BaseList('Locale codes list', self::MODEL_LOCALE_CODE_LIST, 'localeCodes', self::MODEL_LOCALE_CODE)) + ->setModel(new BaseList('Migrations List', self::MODEL_MIGRATION_LIST, 'migrations', self::MODEL_MIGRATION)) + ->setModel(new BaseList('Migrations Firebase Projects List', self::MODEL_MIGRATION_FIREBASE_PROJECT_LIST, 'projects', self::MODEL_MIGRATION_FIREBASE_PROJECT)) // Entities ->setModel(new Database()) ->setModel(new Collection()) @@ -319,6 +359,7 @@ class Response extends SwooleResponse ->setModel(new Account()) ->setModel(new Preferences()) ->setModel(new Session()) + ->setModel(new Identity()) ->setModel(new Token()) ->setModel(new JWT()) ->setModel(new Locale()) @@ -328,6 +369,10 @@ class Response extends SwooleResponse ->setModel(new Team()) ->setModel(new Membership()) ->setModel(new Func()) + ->setModel(new Installation()) + ->setModel(new ProviderRepository()) + ->setModel(new Detection()) + ->setModel(new Branch()) ->setModel(new Runtime()) ->setModel(new Deployment()) ->setModel(new Execution()) @@ -335,7 +380,6 @@ class Response extends SwooleResponse ->setModel(new Project()) ->setModel(new Webhook()) ->setModel(new Key()) - ->setModel(new Domain()) ->setModel(new Provider()) ->setModel(new Platform()) ->setModel(new Variable()) @@ -359,9 +403,14 @@ class Response extends SwooleResponse ->setModel(new UsageFunctions()) ->setModel(new UsageFunction()) ->setModel(new UsageProject()) + ->setModel(new Headers()) + ->setModel(new Rule()) ->setModel(new TemplateSMS()) ->setModel(new TemplateEmail()) ->setModel(new ConsoleVariables()) + ->setModel(new Migration()) + ->setModel(new MigrationReport()) + ->setModel(new MigrationFirebaseProject()) // Verification // Recovery // Tests (keep last) @@ -431,7 +480,7 @@ class Response extends SwooleResponse */ public function dynamic(Document $document, string $model): void { - $output = $this->output(new Document($document->getArrayCopy()), $model); + $output = $this->output(clone $document, $model); // If filter is set, parse the output if (self::hasFilter()) { @@ -472,11 +521,11 @@ class Response extends SwooleResponse */ public function output(Document $document, string $model): array { - $data = new Document($document->getArrayCopy()); + $data = clone $document; $model = $this->getModel($model); $output = []; - $data = $model->filter($document); + $data = $model->filter($data); if ($model->isAny()) { $this->payload = $data->getArrayCopy(); @@ -485,7 +534,7 @@ class Response extends SwooleResponse } foreach ($model->getRules() as $key => $rule) { - if (!$document->isSet($key) && $rule['required']) { // do not set attribute in response if not required + if (!$data->isSet($key) && $rule['required']) { // do not set attribute in response if not required if (\array_key_exists('default', $rule)) { $data->setAttribute($key, $rule['default']); } else { @@ -494,11 +543,11 @@ class Response extends SwooleResponse } if ($rule['array']) { - if (!is_array($document[$key])) { + if (!is_array($data[$key])) { throw new Exception($key . ' must be an array of type ' . $rule['type']); } - foreach ($document[$key] as $index => $item) { + foreach ($data[$key] as $index => $item) { if ($item instanceof Document) { if (\is_array($rule['type'])) { foreach ($rule['type'] as $type) { @@ -526,7 +575,7 @@ class Response extends SwooleResponse } } } else { - if ($document[$key] instanceof Document) { + if ($data[$key] instanceof Document) { $data[$key] = $this->output($data[$key], $rule['type']); } } @@ -620,4 +669,16 @@ class Response extends SwooleResponse { return self::$filter != null; } + + /** + * Set Header + * + * @param string $key + * @param string $value + * @return void + */ + public function setHeader(string $key, string $value): void + { + $this->sendHeader($key, $value); + } } diff --git a/src/Appwrite/Utopia/Response/Filters/V16.php b/src/Appwrite/Utopia/Response/Filters/V16.php new file mode 100644 index 0000000000..6943bd8f4d --- /dev/null +++ b/src/Appwrite/Utopia/Response/Filters/V16.php @@ -0,0 +1,109 @@ +parseDeployment($parsedResponse); + break; + case Response::MODEL_PROXY_RULE: + // We won't be supporting the domain endpoints for older SDKs + // since these APIs are internal. As such, no filtering required + break; + case Response::MODEL_EXECUTION: + $parsedResponse = $this->parseExecution($parsedResponse); + break; + case Response::MODEL_FUNCTION: + $parsedResponse = $this->parseFunction($parsedResponse); + break; + case Response::MODEL_PROJECT: + $parsedResponse = $this->parseProject($parsedResponse); + break; + case Response::MODEL_VARIABLE: + $parsedResponse = $this->parseVariable($parsedResponse); + break; + } + + return $parsedResponse; + } + + protected function parseDeployment(array $content) + { + $content['buildStderr'] = ''; + $content['buildStdout'] = $content['buildLogs']; + unset($content['buildLogs']); + return $content; + } + + protected function parseExecution(array $content) + { + if (isset($content['responseStatusCode'])) { + $content['statusCode'] = $content['responseStatusCode']; + unset($content['responseStatusCode']); + } + + if (isset($content['responseBody'])) { + $content['response'] = $content['responseBody']; + unset($content['responseBody']); + } + + if (isset($content['logs'])) { + $content['stdout'] = $content['logs']; + unset($content['logs']); + } + + if (isset($content['errors'])) { + $content['stderr'] = $content['errors']; + unset($content['errors']); + } + + return $content; + } + + protected function parseFunction(array $content) + { + $content['schedulePrevious'] = ''; + $content['scheduleNext'] = ''; + + if (!empty($content['schedule'])) { + $cron = new CronExpression($content['schedule']); + $content['schedulePrevious'] = DateTime::formatTz(DateTime::format($cron->getPreviousRunDate())); + $content['scheduleNext'] = DateTime::formatTz(DateTime::format($cron->getNextRunDate())); + } + + return $content; + } + + protected function parseProject(array $content) + { + foreach ($content['providers'] ?? [] as $i => $provider) { + $content['providers'][$i]['name'] = \ucfirst($provider['key']); + unset($content['providers'][$i]['key']); + } + + $content['domains'] = []; + return $content; + } + + protected function parseVariable(array $content) + { + if (isset($content['resourceId'])) { + $content['functionId'] = $content['resourceId']; + unset($content['resourceId']); + } + + return $content; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/BaseList.php b/src/Appwrite/Utopia/Response/Model/BaseList.php index 06a5249388..d4ba6b0ab7 100644 --- a/src/Appwrite/Utopia/Response/Model/BaseList.php +++ b/src/Appwrite/Utopia/Response/Model/BaseList.php @@ -34,7 +34,7 @@ class BaseList extends Model $namesWithCap = [ 'documents', 'collections', 'users', 'files', 'buckets', 'functions', 'deployments', 'executions', 'projects', 'webhooks', 'keys', - 'platforms', 'domains', 'memberships', 'teams' + 'platforms', 'rules', 'memberships', 'teams' ]; if (\in_array($name, $namesWithCap)) { diff --git a/src/Appwrite/Utopia/Response/Model/Branch.php b/src/Appwrite/Utopia/Response/Model/Branch.php new file mode 100644 index 0000000000..9264006ecc --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Branch.php @@ -0,0 +1,40 @@ +addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Branch Name.', + 'default' => '', + 'example' => 'main', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Branch'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_BRANCH; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Build.php b/src/Appwrite/Utopia/Response/Model/Build.php index b76f0ee083..d80c17645a 100644 --- a/src/Appwrite/Utopia/Response/Model/Build.php +++ b/src/Appwrite/Utopia/Response/Model/Build.php @@ -63,6 +63,12 @@ class Build extends Model 'default' => 0, 'example' => 0, ]) + ->addRule('size', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'The code size in bytes.', + 'default' => 0, + 'example' => 128, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/Collection.php b/src/Appwrite/Utopia/Response/Model/Collection.php index ae3e283378..e634c88f3a 100644 --- a/src/Appwrite/Utopia/Response/Model/Collection.php +++ b/src/Appwrite/Utopia/Response/Model/Collection.php @@ -49,7 +49,7 @@ class Collection extends Model ]) ->addRule('enabled', [ 'type' => self::TYPE_BOOLEAN, - 'description' => 'Collection enabled.', + 'description' => 'Collection enabled. Can be \'enabled\' or \'disabled\'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.', 'default' => true, 'example' => false, ]) diff --git a/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php b/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php index e52638f82a..a82b8008cc 100644 --- a/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php +++ b/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php @@ -33,6 +33,24 @@ class ConsoleVariables extends Model 'description' => 'Defines if usage stats are enabled. This value is set to \'enabled\' by default, to disable the usage stats set the value to \'disabled\'.', 'default' => '', 'example' => 'enabled', + ]) + ->addRule('_APP_VCS_ENABLED', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines if VCS (Version Control System) is enabled.', + 'default' => false, + 'example' => true, + ]) + ->addRule('_APP_DOMAIN_ENABLED', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines if main domain is configured. If so, custom domains can be created.', + 'default' => false, + 'example' => true, + ]) + ->addRule('_APP_ASSISTANT_ENABLED', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines if AI assistant is enabled.', + 'default' => false, + 'example' => true, ]); } diff --git a/src/Appwrite/Utopia/Response/Model/Database.php b/src/Appwrite/Utopia/Response/Model/Database.php index bd9ae4625c..90b4ac8cb4 100644 --- a/src/Appwrite/Utopia/Response/Model/Database.php +++ b/src/Appwrite/Utopia/Response/Model/Database.php @@ -36,7 +36,7 @@ class Database extends Model ]) ->addRule('enabled', [ 'type' => self::TYPE_BOOLEAN, - 'description' => 'Database enabled.', + 'description' => 'If database is enabled. Can be \'enabled\' or \'disabled\'. When disabled, the database is inaccessible to users, but remains accessible to Server SDKs using API keys.', 'default' => true, 'example' => false, ]) diff --git a/src/Appwrite/Utopia/Response/Model/Deployment.php b/src/Appwrite/Utopia/Response/Model/Deployment.php index 8862d6a14e..46eb52afae 100644 --- a/src/Appwrite/Utopia/Response/Model/Deployment.php +++ b/src/Appwrite/Utopia/Response/Model/Deployment.php @@ -28,6 +28,12 @@ class Deployment extends Model 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Type of deployment.', + 'default' => '', + 'example' => 'vcs', + ]) ->addRule('resourceId', [ 'type' => self::TYPE_STRING, 'description' => 'Resource ID.', @@ -44,7 +50,7 @@ class Deployment extends Model 'type' => self::TYPE_STRING, 'description' => 'The entrypoint file to use to execute the deployment code.', 'default' => '', - 'example' => 'enabled', + 'example' => 'index.js', ]) ->addRule('size', [ 'type' => self::TYPE_INTEGER, @@ -66,21 +72,15 @@ class Deployment extends Model ]) ->addRule('status', [ 'type' => self::TYPE_STRING, - 'description' => 'The deployment status. Possible values are "processing", "building", "pending", "ready", and "failed".', + 'description' => 'The deployment status. Possible values are "processing", "building", "waiting", "ready", and "failed".', 'default' => '', 'example' => 'ready', ]) - ->addRule('buildStdout', [ + ->addRule('buildLogs', [ 'type' => self::TYPE_STRING, - 'description' => 'The build stdout.', + 'description' => 'The build logs.', 'default' => '', - 'example' => 'enabled', - ]) - ->addRule('buildStderr', [ - 'type' => self::TYPE_STRING, - 'description' => 'The build stderr.', - 'default' => '', - 'example' => 'enabled', + 'example' => 'Compiling source files...', ]) ->addRule('buildTime', [ 'type' => self::TYPE_INTEGER, @@ -88,7 +88,72 @@ class Deployment extends Model 'default' => 0, 'example' => 128, ]) - ; + ->addRule('providerRepositoryName', [ + 'type' => self::TYPE_STRING, + 'description' => 'The name of the vcs provider repository', + 'default' => '', + 'example' => 'database', + ]) + ->addRule('providerRepositoryOwner', [ + 'type' => self::TYPE_STRING, + 'description' => 'The name of the vcs provider repository owner', + 'default' => '', + 'example' => 'utopia', + ]) + ->addRule('providerRepositoryUrl', [ + 'type' => self::TYPE_STRING, + 'description' => 'The url of the vcs provider repository', + 'default' => '', + 'example' => 'https://github.com/vermakhushboo/g4-node-function', + ]) + ->addRule('providerBranch', [ + 'type' => self::TYPE_STRING, + 'description' => 'The branch name of the vcs provider repository', + 'default' => '', + 'example' => 'main', + ]) + ->addRule('providerCommitHash', [ + 'type' => self::TYPE_STRING, + 'description' => 'The commit hash of the vcs commit', + 'default' => '', + 'example' => '7c3f25d', + ]) + ->addRule('providerCommitAuthorUrl', [ + 'type' => self::TYPE_STRING, + 'description' => 'The url of vcs commit author', + 'default' => '', + 'example' => 'https://github.com/vermakhushboo', + ]) + ->addRule('providerCommitAuthor', [ + 'type' => self::TYPE_STRING, + 'description' => 'The name of vcs commit author', + 'default' => '', + 'example' => 'Khushboo Verma', + ]) + ->addRule('providerCommitMessage', [ + 'type' => self::TYPE_STRING, + 'description' => 'The commit message', + 'default' => '', + 'example' => 'Update index.js', + ]) + ->addRule('providerCommitUrl', [ + 'type' => self::TYPE_STRING, + 'description' => 'The url of the vcs commit', + 'default' => '', + 'example' => 'https://github.com/vermakhushboo/g4-node-function/commit/60c0416257a9cbcdd96b2d370c38d8f8d150ccfb', + ]) + ->addRule('providerBranch', [ + 'type' => self::TYPE_STRING, + 'description' => 'The branch of the vcs repository', + 'default' => '', + 'example' => '0.7.x', + ]) + ->addRule('providerBranchUrl', [ + 'type' => self::TYPE_STRING, + 'description' => 'The branch of the vcs repository', + 'default' => '', + 'example' => 'https://github.com/vermakhushboo/appwrite/tree/0.7.x', + ]); } /** diff --git a/src/Appwrite/Utopia/Response/Model/Detection.php b/src/Appwrite/Utopia/Response/Model/Detection.php new file mode 100644 index 0000000000..c71baa0b0c --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Detection.php @@ -0,0 +1,40 @@ +addRule('runtime', [ + 'type' => self::TYPE_STRING, + 'description' => 'Runtime', + 'default' => '', + 'example' => 'node', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Detection'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_DETECTION; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Domain.php b/src/Appwrite/Utopia/Response/Model/Domain.php deleted file mode 100644 index 135bb52f90..0000000000 --- a/src/Appwrite/Utopia/Response/Model/Domain.php +++ /dev/null @@ -1,88 +0,0 @@ -addRule('$id', [ - 'type' => self::TYPE_STRING, - 'description' => 'Domain ID.', - 'default' => '', - 'example' => '5e5ea5c16897e', - ]) - ->addRule('$createdAt', [ - 'type' => self::TYPE_DATETIME, - 'description' => 'Domain creation date in ISO 8601 format.', - 'default' => '', - 'example' => self::TYPE_DATETIME_EXAMPLE, - ]) - ->addRule('$updatedAt', [ - 'type' => self::TYPE_DATETIME, - 'description' => 'Domain update date in ISO 8601 format.', - 'default' => '', - 'example' => self::TYPE_DATETIME_EXAMPLE, - ]) - ->addRule('domain', [ - 'type' => self::TYPE_STRING, - 'description' => 'Domain name.', - 'default' => '', - 'example' => 'appwrite.company.com', - ]) - ->addRule('registerable', [ - 'type' => self::TYPE_STRING, - 'description' => 'Registerable domain name.', - 'default' => '', - 'example' => 'company.com', - ]) - ->addRule('tld', [ - 'type' => self::TYPE_STRING, - 'description' => 'TLD name.', - 'default' => '', - 'example' => 'com', - ]) - ->addRule('verification', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Verification process status.', - 'default' => false, - 'example' => true, - ]) - ->addRule('certificateId', [ - 'type' => self::TYPE_STRING, - 'description' => 'Certificate ID.', - 'default' => '', - 'example' => '6ejea5c13377e', - ]) - ; - } - - /** - * Get Name - * - * @return string - */ - public function getName(): string - { - return 'Domain'; - } - - /** - * Get Type - * - * @return string - */ - public function getType(): string - { - return Response::MODEL_DOMAIN; - } -} diff --git a/src/Appwrite/Utopia/Response/Model/Execution.php b/src/Appwrite/Utopia/Response/Model/Execution.php index 8672a91598..3ff171dfff 100644 --- a/src/Appwrite/Utopia/Response/Model/Execution.php +++ b/src/Appwrite/Utopia/Response/Model/Execution.php @@ -54,33 +54,59 @@ class Execution extends Model 'default' => '', 'example' => 'processing', ]) - ->addRule('statusCode', [ + ->addRule('requestMethod', [ + 'type' => self::TYPE_STRING, + 'description' => 'HTTP request method type.', + 'default' => '', + 'example' => 'GET', + ]) + ->addRule('requestPath', [ + 'type' => self::TYPE_STRING, + 'description' => 'HTTP request path and query.', + 'default' => '', + 'example' => '/articles?id=5', + ]) + ->addRule('requestHeaders', [ + 'type' => Response::MODEL_HEADERS, + 'description' => 'HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.', + 'default' => [], + 'example' => [['Content-Type' => 'application/json']], + 'array' => true, + ]) + ->addRule('responseStatusCode', [ 'type' => self::TYPE_INTEGER, - 'description' => 'The script status code.', + 'description' => 'HTTP response status code.', 'default' => 0, - 'example' => 0, + 'example' => 200, ]) - ->addRule('response', [ + ->addRule('responseBody', [ 'type' => self::TYPE_STRING, - 'description' => 'The script response output string. Logs the last 4,000 characters of the execution response output.', + '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, + 'description' => 'HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.', + 'default' => [], + 'example' => [['Content-Type' => 'application/json']], + 'array' => true, + ]) + ->addRule('logs', [ + 'type' => self::TYPE_STRING, + 'description' => 'Function logs. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.', 'default' => '', 'example' => '', ]) - ->addRule('stdout', [ + ->addRule('errors', [ 'type' => self::TYPE_STRING, - 'description' => 'The script stdout output string. Logs the last 4,000 characters of the execution stdout output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.', - 'default' => '', - 'example' => '', - ]) - ->addRule('stderr', [ - 'type' => self::TYPE_STRING, - 'description' => 'The script stderr output string. Logs the last 4,000 characters of the execution stderr output. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.', + 'description' => 'Function errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload.', 'default' => '', 'example' => '', ]) ->addRule('duration', [ 'type' => self::TYPE_FLOAT, - 'description' => 'The script execution duration in seconds.', + 'description' => 'Function execution duration in seconds.', 'default' => 0, 'example' => 0.400, ]) diff --git a/src/Appwrite/Utopia/Response/Model/Func.php b/src/Appwrite/Utopia/Response/Model/Func.php index c4044c0f2e..e32735b38e 100644 --- a/src/Appwrite/Utopia/Response/Model/Func.php +++ b/src/Appwrite/Utopia/Response/Model/Func.php @@ -49,6 +49,18 @@ class Func extends Model 'default' => true, 'example' => false, ]) + ->addRule('live', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is the function deployed with the latest configuration? This is set to false if you\'ve changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration.', + 'default' => true, + 'example' => false, + ]) + ->addRule('logging', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project.', + 'default' => true, + 'example' => false, + ]) ->addRule('runtime', [ 'type' => self::TYPE_STRING, 'description' => 'Function execution runtime.', @@ -85,7 +97,55 @@ class Func extends Model 'type' => self::TYPE_INTEGER, 'description' => 'Function execution timeout in seconds.', 'default' => 15, - 'example' => 15, + 'example' => 300, + ]) + ->addRule('entrypoint', [ + 'type' => self::TYPE_STRING, + 'description' => 'The entrypoint file used to execute the deployment.', + 'default' => '', + 'example' => 'index.js', + ]) + ->addRule('commands', [ + 'type' => self::TYPE_STRING, + 'description' => 'The build command used to build the deployment.', + 'default' => '', + 'example' => 'npm install', + ]) + ->addRule('version', [ + 'type' => self::TYPE_STRING, + 'description' => 'Version of Open Runtimes used for the function.', + 'default' => 'v3', + 'example' => 'v2', + ]) + ->addRule('installationId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Function VCS (Version Control System) installation id.', + 'default' => '', + 'example' => '6m40at4ejk5h2u9s1hboo', + ]) + ->addRule('providerRepositoryId', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) Repository ID', + 'default' => '', + 'example' => 'appwrite', + ]) + ->addRule('providerBranch', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) branch name', + 'default' => '', + 'example' => 'main', + ]) + ->addRule('providerRootDirectory', [ + 'type' => self::TYPE_STRING, + 'description' => 'Path to function in VCS (Version Control System) repository', + 'default' => '', + 'example' => 'functions/helloWorld', + ]) + ->addRule('providerSilentMode', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests', + 'default' => false, + 'example' => false, ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/Headers.php b/src/Appwrite/Utopia/Response/Model/Headers.php new file mode 100644 index 0000000000..38ac4da722 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Headers.php @@ -0,0 +1,46 @@ +addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Header name.', + 'default' => '', + 'example' => 'Content-Type', + ]) + ->addRule('value', [ + 'type' => self::TYPE_STRING, + 'description' => 'Header value.', + 'default' => '', + 'example' => 'application/json', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Headers'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_HEADERS; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Identity.php b/src/Appwrite/Utopia/Response/Model/Identity.php new file mode 100644 index 0000000000..ff7f57a3e6 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Identity.php @@ -0,0 +1,95 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Identity ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Identity creation date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Identity update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('userId', [ + 'type' => self::TYPE_STRING, + 'description' => 'User ID.', + 'default' => '', + 'example' => '5e5bb8c16897e', + ]) + ->addRule('provider', [ + 'type' => self::TYPE_STRING, + 'description' => 'Identity Provider.', + 'default' => '', + 'example' => 'email', + ]) + ->addRule('providerUid', [ + 'type' => self::TYPE_STRING, + 'description' => 'ID of the User in the Identity Provider.', + 'default' => '', + 'example' => '5e5bb8c16897e', + ]) + ->addRule('providerEmail', [ + 'type' => self::TYPE_STRING, + 'description' => 'Email of the User in the Identity Provider.', + 'default' => '', + 'example' => 'user@example.com', + ]) + ->addRule('providerAccessToken', [ + 'type' => self::TYPE_STRING, + 'description' => 'Identity Provider Access Token.', + 'default' => '', + 'example' => 'MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3', + ]) + ->addRule('providerAccessTokenExpiry', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'The date of when the access token expires in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('providerRefreshToken', [ + 'type' => self::TYPE_STRING, + 'description' => 'Identity Provider Refresh Token.', + 'default' => '', + 'example' => 'MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3', + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Identity'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_IDENTITY; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Installation.php b/src/Appwrite/Utopia/Response/Model/Installation.php new file mode 100644 index 0000000000..29d29e8d5a --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Installation.php @@ -0,0 +1,72 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Function ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Function creation date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Function update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('provider', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) provider name.', + 'default' => [], + 'example' => 'github', + 'array' => false, + ]) + ->addRule('organization', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) organization name.', + 'default' => [], + 'example' => 'appwrite', + 'array' => false, + ]) + ->addRule('providerInstallationId', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) installation ID.', + 'default' => '', + 'example' => '5322', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Installation'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_INSTALLATION; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Migration.php b/src/Appwrite/Utopia/Response/Model/Migration.php new file mode 100644 index 0000000000..78e8658032 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Migration.php @@ -0,0 +1,96 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Migration ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Variable creation date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Variable creation date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Migration status ( pending, processing, failed, completed ) ', + 'default' => '', + 'example' => 'pending', + ]) + ->addRule('stage', [ + 'type' => self::TYPE_STRING, + 'description' => 'Migration stage ( init, processing, source-check, destination-check, migrating, finished )', + 'default' => '', + 'example' => 'init', + ]) + ->addRule('source', [ + 'type' => self::TYPE_STRING, + 'description' => 'A string containing the type of source of the migration.', + 'default' => '', + 'example' => 'Appwrite', + ]) + ->addRule('resources', [ + 'type' => self::TYPE_STRING, + 'description' => 'Resources to migration.', + 'default' => [], + 'example' => ['user'], + 'array' => true + ]) + ->addRule('statusCounters', [ + 'type' => self::TYPE_JSON, + 'description' => 'A group of counters that represent the total progress of the migration.', + 'default' => [], + 'example' => '{"Database": {"PENDING": 0, "SUCCESS": 1, "ERROR": 0, "SKIP": 0, "PROCESSING": 0, "WARNING": 0}}', + ]) + ->addRule('resourceData', [ + 'type' => self::TYPE_JSON, + 'description' => 'An array of objects containing the report data of the resources that were migrated.', + 'default' => [], + 'example' => '[{"resource":"Database","id":"public","status":"SUCCESS","message":""}]', + ]) + ->addRule('errors', [ + 'type' => self::TYPE_STRING, + 'description' => 'All errors that occurred during the migration process.', + 'default' => [], + 'example' => [], + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Migration'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_MIGRATION; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/MigrationFirebaseProject.php b/src/Appwrite/Utopia/Response/Model/MigrationFirebaseProject.php new file mode 100644 index 0000000000..cf13c81483 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/MigrationFirebaseProject.php @@ -0,0 +1,46 @@ +addRule('projectId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Project ID.', + 'default' => '', + 'example' => 'my-project', + ]) + ->addRule('displayName', [ + 'type' => self::TYPE_STRING, + 'description' => 'Project display name.', + 'default' => '', + 'example' => 'My Project', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'MigrationFirebaseProject'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_MIGRATION_FIREBASE_PROJECT; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/MigrationReport.php b/src/Appwrite/Utopia/Response/Model/MigrationReport.php new file mode 100644 index 0000000000..15164d56fc --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/MigrationReport.php @@ -0,0 +1,89 @@ +addRule(Resource::TYPE_USER, [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of users to be migrated.', + 'default' => 0, + 'example' => 20, + ]) + ->addRule(Resource::TYPE_TEAM, [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of teams to be migrated.', + 'default' => 0, + 'example' => 20, + ]) + ->addRule(Resource::TYPE_DATABASE, [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of databases to be migrated.', + 'default' => 0, + 'example' => 20, + ]) + ->addRule(Resource::TYPE_DOCUMENT, [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of documents to be migrated.', + 'default' => 0, + 'example' => 20, + ]) + ->addRule(Resource::TYPE_FILE, [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of files to be migrated.', + 'default' => 0, + 'example' => 20, + ]) + ->addRule(Resource::TYPE_BUCKET, [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of buckets to be migrated.', + 'default' => 0, + 'example' => 20, + ]) + ->addRule(Resource::TYPE_FUNCTION, [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of functions to be migrated.', + 'default' => 0, + 'example' => 20, + ]) + ->addRule('size', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Size of files to be migrated in mb.', + 'default' => 0, + 'example' => 30000, + ]) + ->addRule('version', [ + 'type' => self::TYPE_STRING, + 'description' => 'Version of the Appwrite instance to be migrated.', + 'default' => '', + 'example' => '1.4.0', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Migration Report'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_MIGRATION_REPORT; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 45b3392fa4..20703ffbeb 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -166,13 +166,6 @@ class Project extends Model 'example' => new \stdClass(), 'array' => true, ]) - ->addRule('domains', [ - 'type' => Response::MODEL_DOMAIN, - 'description' => 'List of Domains.', - 'default' => [], - 'example' => new \stdClass(), - 'array' => true, - ]) ->addRule('smtpEnabled', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Status for custom SMTP', @@ -180,12 +173,24 @@ class Project extends Model 'example' => false, 'array' => false ]) - ->addRule('smtpSender', [ + ->addRule('smtpSenderName', [ + 'type' => self::TYPE_STRING, + 'description' => 'SMTP sender name', + 'default' => '', + 'example' => 'John Appwrite', + ]) + ->addRule('smtpSenderEmail', [ 'type' => self::TYPE_STRING, 'description' => 'SMTP sender email', 'default' => '', 'example' => 'john@appwrite.io', ]) + ->addRule('smtpReplyTo', [ + 'type' => self::TYPE_STRING, + 'description' => 'SMTP reply to email', + 'default' => '', + 'example' => 'support@appwrite.io', + ]) ->addRule('smtpHost', [ 'type' => self::TYPE_STRING, 'description' => 'SMTP server host name', @@ -284,7 +289,9 @@ class Project extends Model // SMTP $smtp = $document->getAttribute('smtp', []); $document->setAttribute('smtpEnabled', $smtp['enabled'] ?? false); - $document->setAttribute('smtpSender', $smtp['sender'] ?? ''); + $document->setAttribute('smtpSenderEmail', $smtp['senderEmail'] ?? ''); + $document->setAttribute('smtpSenderName', $smtp['senderName'] ?? ''); + $document->setAttribute('smtpReplyTo', $smtp['replyTo'] ?? ''); $document->setAttribute('smtpHost', $smtp['host'] ?? ''); $document->setAttribute('smtpPort', $smtp['port'] ?? ''); $document->setAttribute('smtpUsername', $smtp['username'] ?? ''); diff --git a/src/Appwrite/Utopia/Response/Model/ProviderRepository.php b/src/Appwrite/Utopia/Response/Model/ProviderRepository.php new file mode 100644 index 0000000000..c133ae3164 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/ProviderRepository.php @@ -0,0 +1,78 @@ +addRule('id', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) repository ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) repository name.', + 'default' => '', + 'example' => 'appwrite', + ]) + ->addRule('organization', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) organization name', + 'default' => [], + 'example' => 'appwrite', + 'array' => false, + ]) + ->addRule('provider', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) provider name.', + 'default' => '', + 'example' => 'github', + ]) + ->addRule('private', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is VCS (Version Control System) repository private?', + 'default' => false, + 'example' => true, + ]) + ->addRule('runtime', [ + 'type' => self::TYPE_STRING, + 'description' => 'Auto-detected runtime suggestion. Empty if getting response of getRuntime().', + 'default' => '', + 'example' => 'node', + ]) + ->addRule('pushedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Last commit date in ISO 8601 format.', + 'default' => APP_DATABASE_ATTRIBUTE_DATETIME, + 'example' => APP_DATABASE_ATTRIBUTE_DATETIME, + 'array' => false, + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'ProviderRepository'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_PROVIDER_REPOSITORY; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Rule.php b/src/Appwrite/Utopia/Response/Model/Rule.php new file mode 100644 index 0000000000..077455b4a7 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Rule.php @@ -0,0 +1,92 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Rule ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Rule creation date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Rule update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('domain', [ + 'type' => self::TYPE_STRING, + 'description' => 'Domain name.', + 'default' => '', + 'example' => 'appwrite.company.com', + ]) + ->addRule('resourceType', [ + 'type' => self::TYPE_STRING, + 'description' => 'Action definition for the rule. Possible values are "api", "function", or "redirect"', + 'default' => '', + 'example' => 'function', + ]) + ->addRule('resourceId', [ + 'type' => self::TYPE_STRING, + 'description' => 'ID of resource for the action type. If resourceType is "api" or "url", it is empty. If resourceType is "function", it is ID of the function.', + 'default' => '', + 'example' => 'myAwesomeFunction', + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Domain verification status. Possible values are "created", "verifying", "verified" and "unverified"', + 'default' => false, + 'example' => 'verified', + ]) + ->addRule('logs', [ + 'type' => self::TYPE_STRING, + 'description' => 'Certificate generation logs. This will return an empty string if generation did not run, or succeeded.', + 'default' => '', + 'example' => 'HTTP challegne failed.', + ]) + ->addRule('renewAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Certificate auto-renewal date in ISO 8601 format.', + 'default' => APP_DATABASE_ATTRIBUTE_DATETIME, + 'example' => APP_DATABASE_ATTRIBUTE_DATETIME, + 'array' => false, + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Rule'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_PROXY_RULE; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/UsageBuckets.php b/src/Appwrite/Utopia/Response/Model/UsageBuckets.php index 83b8744760..8c6c81f234 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageBuckets.php +++ b/src/Appwrite/Utopia/Response/Model/UsageBuckets.php @@ -16,7 +16,7 @@ class UsageBuckets extends Model 'default' => '', 'example' => '30d', ]) - ->addRule('filesTotal', [ + ->addRule('filesCount', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of files in this bucket.', 'default' => [], @@ -30,6 +30,34 @@ class UsageBuckets extends Model 'example' => [], 'array' => true ]) + ->addRule('filesCreate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for files created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('filesRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for files read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('filesUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for files updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('filesDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for files deleted.', + 'default' => [], + 'example' => [], + 'array' => true + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/UsageCollection.php b/src/Appwrite/Utopia/Response/Model/UsageCollection.php index 5abcf46b7d..8b6966fcd2 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageCollection.php +++ b/src/Appwrite/Utopia/Response/Model/UsageCollection.php @@ -16,13 +16,41 @@ class UsageCollection extends Model 'default' => '', 'example' => '30d', ]) - ->addRule('documentsTotal', [ + ->addRule('documentsCount', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], 'array' => true ]) + ->addRule('documentsCreate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents deleted.', + 'default' => [], + 'example' => [], + 'array' => true + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/UsageDatabase.php b/src/Appwrite/Utopia/Response/Model/UsageDatabase.php index 58d49c506e..0c84d796ba 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageDatabase.php +++ b/src/Appwrite/Utopia/Response/Model/UsageDatabase.php @@ -16,16 +16,72 @@ class UsageDatabase extends Model 'default' => '', 'example' => '30d', ]) - ->addRule('collectionsTotal', [ + ->addRule('documentsCount', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for total number of documents.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsCount', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of collections.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('documentsTotal', [ + ->addRule('documentsCreate', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for total number of documents.', + 'description' => 'Aggregated stats for documents created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents deleted.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsCreate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for collections created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for collections read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for collections updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for collections delete.', 'default' => [], 'example' => [], 'array' => true diff --git a/src/Appwrite/Utopia/Response/Model/UsageDatabases.php b/src/Appwrite/Utopia/Response/Model/UsageDatabases.php index a6008ca9e6..93488a47db 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageDatabases.php +++ b/src/Appwrite/Utopia/Response/Model/UsageDatabases.php @@ -16,23 +16,107 @@ class UsageDatabases extends Model 'default' => '', 'example' => '30d', ]) - ->addRule('databasesTotal', [ + ->addRule('databasesCount', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of documents.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('collectionsTotal', [ + ->addRule('documentsCount', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for total number of documents.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsCount', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of collections.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('documentsTotal', [ + ->addRule('databasesCreate', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for total number of documents.', + 'description' => 'Aggregated stats for documents created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('databasesRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('databasesUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('databasesDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for total number of collections.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsCreate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('documentsDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for documents deleted.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsCreate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for collections created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for collections read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for collections updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('collectionsDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for collections delete.', 'default' => [], 'example' => [], 'array' => true diff --git a/src/Appwrite/Utopia/Response/Model/UsageFunction.php b/src/Appwrite/Utopia/Response/Model/UsageFunction.php index 03acaa750a..58d76bbf41 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageFunction.php +++ b/src/Appwrite/Utopia/Response/Model/UsageFunction.php @@ -16,16 +16,30 @@ class UsageFunction extends Model 'default' => '', 'example' => '30d', ]) - ->addRule('deploymentsTotal', [ + ->addRule('executionsTotal', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for number of function deployments.', + 'description' => 'Aggregated stats for number of function executions.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('deploymentsStorage', [ + ->addRule('executionsFailure', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for function deployments storage.', + 'description' => 'Aggregated stats for function execution failures.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('executionsSuccess', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for function execution successes.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('executionsTime', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for function execution duration.', 'default' => [], 'example' => [], 'array' => true @@ -37,31 +51,23 @@ class UsageFunction extends Model 'example' => [], 'array' => true ]) - ->addRule('buildsStorage', [ + ->addRule('buildsFailure', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for builds storage.', + 'description' => 'Aggregated stats for function build failures.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('buildsSuccess', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for function build successes.', 'default' => [], 'example' => [], 'array' => true ]) ->addRule('buildsTime', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for function build compute.', - 'default' => [], - 'example' => [], - 'array' => true - ]) - ->addRule('executionsTotal', [ - 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for number of function executions.', - 'default' => [], - 'example' => [], - 'array' => true - ]) - - ->addRule('executionsTime', [ - 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for function execution compute.', + 'description' => 'Aggregated stats for function build duration.', 'default' => [], 'example' => [], 'array' => true diff --git a/src/Appwrite/Utopia/Response/Model/UsageFunctions.php b/src/Appwrite/Utopia/Response/Model/UsageFunctions.php index 6ab36e21ac..7adb0d4aa3 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageFunctions.php +++ b/src/Appwrite/Utopia/Response/Model/UsageFunctions.php @@ -16,23 +16,30 @@ class UsageFunctions extends Model 'default' => '', 'example' => '30d', ]) - ->addRule('functionsTotal', [ + ->addRule('executionsTotal', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for number of functions.', + 'description' => 'Aggregated stats for number of function executions.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('deploymentsTotal', [ + ->addRule('executionsFailure', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for number of function deployments.', + 'description' => 'Aggregated stats for function execution failures.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('deploymentsStorage', [ + ->addRule('executionsSuccess', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for function deployments storage.', + 'description' => 'Aggregated stats for function execution successes.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('executionsTime', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for function execution duration.', 'default' => [], 'example' => [], 'array' => true @@ -44,31 +51,23 @@ class UsageFunctions extends Model 'example' => [], 'array' => true ]) - ->addRule('buildsStorage', [ + ->addRule('buildsFailure', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for builds storage.', + 'description' => 'Aggregated stats for function build failures.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('buildsSuccess', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for function build successes.', 'default' => [], 'example' => [], 'array' => true ]) ->addRule('buildsTime', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for function build compute.', - 'default' => [], - 'example' => [], - 'array' => true - ]) - ->addRule('executionsTotal', [ - 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for number of function executions.', - 'default' => [], - 'example' => [], - 'array' => true - ]) - - ->addRule('executionsTime', [ - 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for function execution compute.', + 'description' => 'Aggregated stats for function build duration.', 'default' => [], 'example' => [], 'array' => true diff --git a/src/Appwrite/Utopia/Response/Model/UsageProject.php b/src/Appwrite/Utopia/Response/Model/UsageProject.php index 641613809a..e37bc5928d 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageProject.php +++ b/src/Appwrite/Utopia/Response/Model/UsageProject.php @@ -16,7 +16,7 @@ class UsageProject extends Model 'default' => '', 'example' => '30d', ]) - ->addRule('requestsTotal', [ + ->addRule('requests', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of requests.', 'default' => [], @@ -30,42 +30,42 @@ class UsageProject extends Model 'example' => [], 'array' => true ]) - ->addRule('executionsTotal', [ + ->addRule('executions', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for function executions.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('documentsTotal', [ + ->addRule('documents', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of documents.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('databasesTotal', [ + ->addRule('databases', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of databases.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('usersTotal', [ + ->addRule('users', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of users.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('filesStorage', [ + ->addRule('storage', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for the occupied storage size (in bytes).', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('bucketsTotal', [ + ->addRule('buckets', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for number of buckets.', 'default' => [], diff --git a/src/Appwrite/Utopia/Response/Model/UsageStorage.php b/src/Appwrite/Utopia/Response/Model/UsageStorage.php index 88d0beca01..7e3c08e12a 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageStorage.php +++ b/src/Appwrite/Utopia/Response/Model/UsageStorage.php @@ -16,23 +16,79 @@ class UsageStorage extends Model 'default' => '', 'example' => '30d', ]) - ->addRule('bucketsTotal', [ + ->addRule('storage', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for total number of buckets.', + 'description' => 'Aggregated stats for the occupied storage size (in bytes).', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('filesTotal', [ + ->addRule('filesCount', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of files.', 'default' => [], 'example' => [], 'array' => true ]) - ->addRule('filesStorage', [ + ->addRule('bucketsCount', [ 'type' => Response::MODEL_METRIC, - 'description' => 'Aggregated stats for the occupied storage size (in bytes).', + 'description' => 'Aggregated stats for total number of buckets.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('bucketsCreate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for buckets created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('bucketsRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for buckets read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('bucketsUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for buckets updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('bucketsDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for buckets deleted.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('filesCreate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for files created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('filesRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for files read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('filesUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for files updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('filesDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for files deleted.', 'default' => [], 'example' => [], 'array' => true diff --git a/src/Appwrite/Utopia/Response/Model/UsageUsers.php b/src/Appwrite/Utopia/Response/Model/UsageUsers.php index c0cc4baa54..4c7b37d50f 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageUsers.php +++ b/src/Appwrite/Utopia/Response/Model/UsageUsers.php @@ -16,21 +16,62 @@ class UsageUsers extends Model 'default' => '', 'example' => '30d', ]) - ->addRule('usersTotal', [ + ->addRule('usersCount', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for total number of users.', 'default' => [], 'example' => [], 'array' => true ]) - - ->addRule('sessionsTotal', [ + ->addRule('usersCreate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for users created.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('usersRead', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for users read.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('usersUpdate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for users updated.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('usersDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for users deleted.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('sessionsCreate', [ 'type' => Response::MODEL_METRIC, 'description' => 'Aggregated stats for sessions created.', 'default' => [], 'example' => [], 'array' => true ]) + ->addRule('sessionsProviderCreate', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for sessions created for a provider ( email, anonymous or oauth2 ).', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('sessionsDelete', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated stats for sessions deleted.', + 'default' => [], + 'example' => [], + 'array' => true + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/Variable.php b/src/Appwrite/Utopia/Response/Model/Variable.php index f4b3bcf2bb..88fcd14ca1 100644 --- a/src/Appwrite/Utopia/Response/Model/Variable.php +++ b/src/Appwrite/Utopia/Response/Model/Variable.php @@ -41,11 +41,17 @@ class Variable extends Model 'default' => '', 'example' => 'myPa$$word1', ]) - ->addRule('functionId', [ + ->addRule('resourceType', [ 'type' => self::TYPE_STRING, - 'description' => 'Function ID.', + 'description' => 'Service to which the variable belongs. Possible values are "project", "function"', 'default' => '', - 'example' => '5e5ea5c16897e', + 'example' => 'function', + ]) + ->addRule('resourceId', [ + 'type' => self::TYPE_STRING, + 'description' => 'ID of resource to which the variable belongs. If resourceType is "project", it is empty. If resourceType is "function", it is ID of the function.', + 'default' => '', + 'example' => 'myAwesomeFunction', ]) ; } diff --git a/src/Appwrite/Vcs/Comment.php b/src/Appwrite/Vcs/Comment.php new file mode 100644 index 0000000000..1107e0ee70 --- /dev/null +++ b/src/Appwrite/Vcs/Comment.php @@ -0,0 +1,126 @@ +builds) === 0; + } + + public function addBuild(Document $project, Document $function, string $buildStatus, string $deploymentId, array $action): void + { + // Unique index + $id = $project->getId() . '_' . $function->getId(); + + $this->builds[$id] = [ + 'projectName' => $project->getAttribute('name'), + 'projectId' => $project->getId(), + 'functionName' => $function->getAttribute('name'), + 'functionId' => $function->getId(), + 'buildStatus' => $buildStatus, + 'deploymentId' => $deploymentId, + 'action' => $action, + ]; + } + + public function generateComment(): string + { + $json = \json_encode($this->builds); + + $text = $this->statePrefix . \base64_encode($json) . "\n\n"; + + $projects = []; + + foreach ($this->builds as $id => $build) { + if (!\array_key_exists($build['projectId'], $projects)) { + $projects[$build['projectId']] = [ + 'name' => $build['projectName'], + 'functions' => [] + ]; + } + + $projects[$build['projectId']]['functions'][$build['functionId']] = [ + 'name' => $build['functionName'], + 'status' => $build['buildStatus'], + 'deploymentId' => $build['deploymentId'], + 'action' => $build['action'], + ]; + } + + //TODO: Update link to documentation + $text .= "**Your function has been automatically deployed.** Learn more about Appwrite [Function Deployments](https://appwrite.io/docs/functions).\n\n"; + + foreach ($projects as $projectId => $project) { + $text .= "**{$project['name']}** `{$projectId}`\n\n"; + $text .= "| Function | ID | Status | Action |\n"; + $text .= "| :- | :- | :- | :- |\n"; + + $protocol = App::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; + $hostname = App::getEnv('_APP_DOMAIN'); + + foreach ($project['functions'] as $functionId => $function) { + $generateImage = function (string $status) use ($protocol, $hostname) { + $extention = $status === 'building' ? 'gif' : 'png'; + $imagesUrl = $protocol . '://' . $hostname . '/images/vcs/'; + $imageUrl = '' . $status . ''; + + return $imageUrl; + }; + + $status = match ($function['status']) { + 'waiting' => $generateImage('waiting') . ' Waiting to build', + 'processing' => $generateImage('processing') . ' Processing', + 'building' => $generateImage('building') . ' Building', + 'ready' => $generateImage('ready') . ' Ready', + 'failed' => $generateImage('failed') . ' Failed', + }; + + if ($function['action']['type'] === 'logs') { + $action = '[View Logs](' . $protocol . '://' . $hostname . '/console/project-' . $projectId . '/functions/function-' . $functionId . '/deployment-' . $function['deploymentId'] . ')'; + } else { + $action = '[Authorize](' . $function['action']['url'] . ')'; + } + + $text .= "| {$function['name']} | `{$functionId}` | {$status} | {$action} |\n"; + } + + $text .= "\n\n"; + } + //TODO: Update did you know section + $tip = $this->tips[array_rand($this->tips)]; + $text .= "> **💡 Did you know?** \n " . $tip . "\n\n"; + + return $text; + } + + public function parseComment(string $comment): self + { + $state = \explode("\n", $comment)[0] ?? ''; + $state = substr($state, strlen($this->statePrefix)); + + $json = \base64_decode($state); + + $builds = \json_decode($json, true); + $this->builds = $builds; + + return $this; + } +} diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index bd49e5cf20..36f6ad0dc5 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -35,10 +35,11 @@ class Executor $this->endpoint = $endpoint; $this->cpus = \intval(App::getEnv('_APP_FUNCTIONS_CPUS', '1')); - $this->memory = intval(App::getEnv('_APP_FUNCTIONS_MEMORY', '512')); + $this->memory = \intval(App::getEnv('_APP_FUNCTIONS_MEMORY', '512')); $this->headers = [ 'content-type' => 'application/json', 'authorization' => 'Bearer ' . App::getEnv('_APP_EXECUTOR_SECRET', ''), + 'x-opr-addressing-method' => 'anycast-efficient' ]; } @@ -53,43 +54,90 @@ class Executor * @param string $image * @param bool $remove * @param string $entrypoint - * @param string $workdir * @param string $destination * @param array $variables - * @param array $commands + * @param string $command */ public function createRuntime( string $deploymentId, string $projectId, string $source, string $image, + string $version, bool $remove = false, string $entrypoint = '', - string $workdir = '', string $destination = '', array $variables = [], - array $commands = [] + string $command = null, ) { $runtimeId = "$projectId-$deploymentId"; $route = "/runtimes"; - $headers = [ 'x-opr-runtime-id' => $runtimeId ]; $params = [ 'runtimeId' => $runtimeId, 'source' => $source, 'destination' => $destination, 'image' => $image, 'entrypoint' => $entrypoint, - 'workdir' => $workdir, 'variables' => $variables, 'remove' => $remove, - 'commands' => $commands, + 'command' => $command, 'cpus' => $this->cpus, 'memory' => $this->memory, + 'version' => $version, ]; $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); - $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $timeout); + $response = $this->call(self::METHOD_POST, $route, [ 'x-opr-runtime-id' => $runtimeId ], $params, true, $timeout); + + $status = $response['headers']['status-code']; + if ($status >= 400) { + $message = \is_string($response['body']) ? $response['body'] : $response['body']['message']; + throw new \Exception($message, $status); + } + + return $response['body']; + } + + /** + * Listen to realtime logs stream of a runtime + * + * @param string $deploymentId + * @param string $projectId + * @param callable $callback + */ + public function getLogs( + string $deploymentId, + string $projectId, + callable $callback + ) { + $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); + + $runtimeId = "$projectId-$deploymentId"; + $route = "/runtimes/{$runtimeId}/logs"; + $params = [ + 'timeout' => $timeout + ]; + + $this->call(self::METHOD_GET, $route, [ 'x-opr-runtime-id' => $runtimeId ], $params, true, $timeout, $callback); + } + + /** + * Delete Runtime + * + * Deletes a runtime and cleans up any containers remaining. + * + * @param string $projectId + * @param string $deploymentId + */ + public function deleteRuntime(string $projectId, string $deploymentId) + { + $runtimeId = "$projectId-$deploymentId"; + $route = "/runtimes/$runtimeId"; + + $response = $this->call(self::METHOD_DELETE, $route, [ + 'x-opr-addressing-method' => 'broadcast' + ], [], true, 30); $status = $response['headers']['status-code']; if ($status >= 400) { @@ -105,44 +153,58 @@ class Executor * * @param string $projectId * @param string $deploymentId - * @param string $payload + * @param string $body * @param array $variables * @param int $timeout * @param string $image * @param string $source * @param string $entrypoint + * @param string $runtimeEntrypoint * * @return array */ public function createExecution( string $projectId, string $deploymentId, - string $payload, + ?string $body, array $variables, int $timeout, string $image, string $source, string $entrypoint, + string $version, + string $path, + string $method, + array $headers, + string $runtimeEntrypoint = null, ) { + if (empty($headers['host'])) { + $headers['host'] = App::getEnv('_APP_DOMAIN', ''); + } + $runtimeId = "$projectId-$deploymentId"; $route = '/runtimes/' . $runtimeId . '/execution'; - $headers = [ 'x-opr-runtime-id' => $runtimeId ]; $params = [ 'runtimeId' => $runtimeId, 'variables' => $variables, - 'payload' => $payload, + 'body' => $body, 'timeout' => $timeout, + 'path' => $path, + 'method' => $method, + 'headers' => $headers, 'image' => $image, 'source' => $source, 'entrypoint' => $entrypoint, 'cpus' => $this->cpus, 'memory' => $this->memory, + 'version' => $version, + 'runtimeEntrypoint' => $runtimeEntrypoint, ]; $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); - $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $timeout); + $response = $this->call(self::METHOD_POST, $route, [ 'x-opr-runtime-id' => $runtimeId ], $params, true, $timeout); $status = $response['headers']['status-code']; if ($status >= 400) { @@ -166,7 +228,7 @@ class Executor * @return array|string * @throws Exception */ - public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true, int $timeout = 15) + public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true, int $timeout = 15, callable $callback = null) { $headers = array_merge($this->headers, $headers); $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); @@ -194,8 +256,20 @@ class Executor unset($headers[$i]); } + if (isset($callback)) { + $headers[] = 'accept: text/event-stream'; + + $handleEvent = function ($ch, $data) use ($callback) { + $callback($data); + return \strlen($data); + }; + + curl_setopt($ch, CURLOPT_WRITEFUNCTION, $handleEvent); + } else { + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + } + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); @@ -224,6 +298,12 @@ class Executor } $responseBody = curl_exec($ch); + + if (isset($callback)) { + curl_close($ch); + return []; + } + $responseType = $responseHeaders['content-type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index c8c4f21165..fdea53d68b 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -2,6 +2,7 @@ namespace Tests\E2E\General; +use Appwrite\Tests\Retry; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; @@ -9,733 +10,789 @@ use Tests\E2E\Scopes\SideServer; use CURLFile; use Tests\E2E\Services\Functions\FunctionsBase; use Utopia\Database\DateTime; -use Utopia\Database\Helpers\Permission; -use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Datetime as DatetimeValidator; - -class UsageTest extends Scope -{ - use ProjectCustom; - use SideServer; - use FunctionsBase; - - private const WAIT = 35; - private const CREATE = 20; - - protected string $projectId; - - public function setUp(): void - { - parent::setUp(); - } - - protected static string $formatTz = 'Y-m-d\TH:i:s.vP'; - - protected function validateDates(array $metrics): void - { - foreach ($metrics as $metric) { - $this->assertIsObject(\DateTime::createFromFormat("Y-m-d\TH:i:s.vP", $metric['date'])); - } - } - - public function testPrepareUsersStats(): array - { - $project = $this->getProject(true); - $projectId = $project['$id']; - $headers['x-appwrite-project'] = $project['$id']; - $headers['x-appwrite-key'] = $project['apiKey']; - $headers['content-type'] = 'application/json'; - - $usersTotal = 0; - $requestsTotal = 0; - for ($i = 0; $i < self::CREATE; $i++) { - $email = uniqid() . 'user@usage.test'; - $password = 'password'; - $name = uniqid() . 'User'; - $res = $this->client->call( - Client::METHOD_POST, - '/users', - $headers, - [ - 'userId' => 'unique()', - 'email' => $email, - 'password' => $password, - 'name' => $name, - ] - ); - - $this->assertEquals($email, $res['body']['email']); - $this->assertNotEmpty($res['body']['$id']); - $usersTotal++; - $requestsTotal++; - - if ($i < (self::CREATE / 2)) { - $userId = $res['body']['$id']; - $res = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, $headers); - $this->assertEmpty($res['body']); - $requestsTotal++; - $usersTotal--; - } - } - - return [ - 'projectId' => $projectId, - 'headers' => $headers, - 'usersTotal' => $usersTotal, - 'requestsTotal' => $requestsTotal - ]; - } - - /** - * @depends testPrepareUsersStats - */ - public function testUsersStats(array $data): array - { - sleep(self::WAIT); - - $projectId = $data['projectId']; - $headers = $data['headers']; - $usersTotal = $data['usersTotal']; - $requestsTotal = $data['requestsTotal']; - - $consoleHeaders = [ - 'origin' => 'http://localhost', - 'x-appwrite-project' => 'console', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], - 'x-appwrite-project' => $projectId, - 'x-appwrite-mode' => 'admin', - ]; - - $res = $this->client->call( - Client::METHOD_GET, - '/project/usage?range=24h', - $consoleHeaders - ); - $res = $res['body']; - - $this->assertEquals('24h', $res['range']); - $this->assertEquals(9, count($res)); - $this->assertEquals(24, count($res['requestsTotal'])); - $this->assertEquals(24, count($res['usersTotal'])); - $this->assertEquals($usersTotal, $res['usersTotal'][array_key_last($res['usersTotal'])]['value']); - $this->validateDates($res['usersTotal']); - $this->assertEquals($requestsTotal, $res['requestsTotal'][array_key_last($res['requestsTotal'])]['value']); - $this->validateDates($res['requestsTotal']); - - $res = $this->client->call( - Client::METHOD_GET, - '/users/usage?range=90d', - $consoleHeaders - ); - - $res = $res['body']; - $this->assertEquals('90d', $res['range']); - $this->assertEquals(90, count($res['usersTotal'])); - $this->assertEquals(90, count($res['sessionsTotal'])); - $this->assertEquals((self::CREATE / 2), $res['usersTotal'][array_key_last($res['usersTotal'])]['value']); - - return [ - 'projectId' => $projectId, - 'headers' => $headers, - 'consoleHeaders' => $consoleHeaders, - 'requestsTotal' => $requestsTotal, - ]; - } - - /** @depends testUsersStats */ - public function testPrepareStorageStats(array $data): array - { - $headers = $data['headers']; - $bucketsTotal = 0; - $requestsTotal = $data['requestsTotal']; - $storageTotal = 0; - $filesTotal = 0; - - - for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid() . ' bucket'; - $res = $this->client->call( - Client::METHOD_POST, - '/storage/buckets', - $headers, - [ - 'bucketId' => 'unique()', - 'name' => $name, - 'fileSecurity' => false, - 'permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - ] - ); - $this->assertEquals($name, $res['body']['name']); - $this->assertNotEmpty($res['body']['$id']); - $bucketId = $res['body']['$id']; - $bucketsTotal++; - $requestsTotal++; - - if ($i < (self::CREATE / 2)) { - $res = $this->client->call( - Client::METHOD_DELETE, - '/storage/buckets/' . $bucketId, - $headers - ); - $this->assertEmpty($res['body']); - $requestsTotal++; - $bucketsTotal--; - } - } - - // upload some files - $files = [ - [ - 'path' => realpath(__DIR__ . '/../../resources/logo.png'), - 'name' => 'logo.png', - ], - [ - 'path' => realpath(__DIR__ . '/../../resources/file.png'), - 'name' => 'file.png', - ], - [ - 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-3.gif'), - 'name' => 'kitten-3.gif', - ], - [ - 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'), - 'name' => 'kitten-1.jpg', - ], - ]; - - for ($i = 0; $i < self::CREATE; $i++) { - $file = $files[$i % count($files)]; - - $res = $this->client->call( - Client::METHOD_POST, - '/storage/buckets/' . $bucketId . '/files', - array_merge($headers, ['content-type' => 'multipart/form-data']), - [ - 'fileId' => 'unique()', - 'file' => new CURLFile($file['path'], '', $file['name']), - ] - ); - - $this->assertNotEmpty($res['body']['$id']); - - $fileSize = $res['body']['sizeOriginal']; - $storageTotal += $fileSize; - $filesTotal++; - $requestsTotal++; - - $fileId = $res['body']['$id']; - if ($i < (self::CREATE / 2)) { - $res = $this->client->call( - Client::METHOD_DELETE, - '/storage/buckets/' . $bucketId . '/files/' . $fileId, - $headers - ); - $this->assertEmpty($res['body']); - $requestsTotal++; - $filesTotal--; - $storageTotal -= $fileSize; - } - } - - return array_merge($data, [ - 'bucketId' => $bucketId, - 'bucketsTotal' => $bucketsTotal, - 'requestsTotal' => $requestsTotal, - 'storageTotal' => $storageTotal, - 'filesTotal' => $filesTotal, - ]); - } - - /** - * @depends testPrepareStorageStats - */ - public function testStorageStats(array $data): array - { - $bucketId = $data['bucketId']; - $bucketsTotal = $data['bucketsTotal']; - $requestsTotal = $data['requestsTotal']; - $storageTotal = $data['storageTotal']; - $filesTotal = $data['filesTotal']; - - sleep(self::WAIT); - - $res = $this->client->call( - Client::METHOD_GET, - '/project/usage?range=30d', - array_merge( - $data['headers'], - $data['consoleHeaders'] - ) - ); - $res = $res['body']; - - $this->assertEquals(9, count($res)); - $this->assertEquals(30, count($res['requestsTotal'])); - $this->assertEquals(30, count($res['filesStorage'])); - $this->assertEquals($requestsTotal, $res['requestsTotal'][array_key_last($res['requestsTotal'])]['value']); - $this->validateDates($res['requestsTotal']); - $this->assertEquals($storageTotal, $res['filesStorage'][array_key_last($res['filesStorage'])]['value']); - $this->validateDates($res['filesStorage']); - - $res = $this->client->call( - Client::METHOD_GET, - '/storage/usage?range=30d', - array_merge( - $data['headers'], - $data['consoleHeaders'] - ) - ); - - $res = $res['body']; - $this->assertEquals($storageTotal, $res['filesStorage'][array_key_last($res['filesStorage'])]['value']); - $this->validateDates($res['filesStorage']); - $this->assertEquals($bucketsTotal, $res['bucketsTotal'][array_key_last($res['bucketsTotal'])]['value']); - $this->validateDates($res['bucketsTotal']); - $this->assertEquals($filesTotal, $res['filesTotal'][array_key_last($res['filesTotal'])]['value']); - $this->validateDates($res['filesTotal']); - - $res = $this->client->call( - Client::METHOD_GET, - '/storage/' . $bucketId . '/usage?range=30d', - array_merge( - $data['headers'], - $data['consoleHeaders'] - ) - ); - - $res = $res['body']; - $this->assertEquals($storageTotal, $res['filesStorage'][array_key_last($res['filesStorage'])]['value']); - $this->assertEquals($filesTotal, $res['filesTotal'][array_key_last($res['filesTotal'])]['value']); - - $data['requestsTotal'] = $requestsTotal; - - return $data; - } - - /** @depends testStorageStats */ - public function testPrepareDatabaseStats(array $data): array - { - $headers = $data['headers']; - - $requestsTotal = $data['requestsTotal']; - $databasesTotal = 0; - $collectionsTotal = 0; - $documentsTotal = 0; - - for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid() . ' database'; - $res = $this->client->call( - Client::METHOD_POST, - '/databases', - $headers, - [ - 'databaseId' => 'unique()', - 'name' => $name, - ] - ); - - - $this->assertEquals($name, $res['body']['name']); - $this->assertNotEmpty($res['body']['$id']); - $databaseId = $res['body']['$id']; - - $requestsTotal++; - $databasesTotal++; - - if ($i < (self::CREATE / 2)) { - $res = $this->client->call( - Client::METHOD_DELETE, - '/databases/' . $databaseId, - $headers - ); - $this->assertEmpty($res['body']); - - $databasesTotal--; - $requestsTotal++; - } - } - - for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid() . ' collection'; - $res = $this->client->call( - Client::METHOD_POST, - '/databases/' . $databaseId . '/collections', - $headers, - [ - 'collectionId' => 'unique()', - 'name' => $name, - 'documentSecurity' => false, - 'permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - ] - ); - - $this->assertEquals($name, $res['body']['name']); - $this->assertNotEmpty($res['body']['$id']); - $collectionId = $res['body']['$id']; - - $requestsTotal++; - $collectionsTotal++; - - if ($i < (self::CREATE / 2)) { - $res = $this->client->call( - Client::METHOD_DELETE, - '/databases/' . $databaseId . '/collections/' . $collectionId, - $headers - ); - $this->assertEmpty($res['body']); - $collectionsTotal--; - $requestsTotal++; - } - } - - $res = $this->client->call( - Client::METHOD_POST, - '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes' . '/string', - $headers, - [ - 'key' => 'name', - 'size' => 255, - 'required' => true, - ] - ); - - $this->assertEquals('name', $res['body']['key']); - $requestsTotal++; - - sleep(self::WAIT); - - for ($i = 0; $i < self::CREATE; $i++) { - $name = uniqid() . ' collection'; - $res = $this->client->call( - Client::METHOD_POST, - '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', - $headers, - [ - 'documentId' => 'unique()', - 'data' => ['name' => $name] - ] - ); - $this->assertEquals($name, $res['body']['name']); - $this->assertNotEmpty($res['body']['$id']); - $documentId = $res['body']['$id']; - - $requestsTotal++; - $documentsTotal++; - - if ($i < (self::CREATE / 2)) { - $res = $this->client->call( - Client::METHOD_DELETE, - '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, - $headers - ); - $this->assertEmpty($res['body']); - $documentsTotal--; - $requestsTotal++; - } - } - - return array_merge($data, [ - 'databaseId' => $databaseId, - 'collectionId' => $collectionId, - 'requestsTotal' => $requestsTotal, - 'databasesTotal' => $databasesTotal, - 'collectionsTotal' => $collectionsTotal, - 'documentsTotal' => $documentsTotal, - ]); - } - - /** @depends testPrepareDatabaseStats */ - - public function testDatabaseStats(array $data): array - { - - $projectId = $data['projectId']; - $databaseId = $data['databaseId']; - $collectionId = $data['collectionId']; - $requestsTotal = $data['requestsTotal']; - $databasesTotal = $data['databasesTotal']; - $collectionsTotal = $data['collectionsTotal']; - $documentsTotal = $data['documentsTotal']; - - sleep(self::WAIT); - - $res = $this->client->call( - Client::METHOD_GET, - '/project/usage?range=30d', - $data['consoleHeaders'] - ); - $res = $res['body']; - - $this->assertEquals(9, count($res)); - $this->assertEquals(30, count($res['requestsTotal'])); - $this->assertEquals(30, count($res['filesStorage'])); - $this->assertEquals($requestsTotal, $res['requestsTotal'][array_key_last($res['requestsTotal'])]['value']); - $this->validateDates($res['requestsTotal']); - $this->assertEquals($databasesTotal, $res['databasesTotal'][array_key_last($res['databasesTotal'])]['value']); - $this->validateDates($res['databasesTotal']); - $this->assertEquals($documentsTotal, $res['documentsTotal'][array_key_last($res['documentsTotal'])]['value']); - $this->validateDates($res['documentsTotal']); - - $res = $this->client->call( - Client::METHOD_GET, - '/databases/usage?range=30d', - $data['consoleHeaders'] - ); - $res = $res['body']; - - $this->assertEquals($databasesTotal, $res['databasesTotal'][array_key_last($res['databasesTotal'])]['value']); - $this->validateDates($res['databasesTotal']); - $this->assertEquals($collectionsTotal, $res['collectionsTotal'][array_key_last($res['collectionsTotal'])]['value']); - $this->validateDates($res['collectionsTotal']); - $this->assertEquals($documentsTotal, $res['documentsTotal'][array_key_last($res['documentsTotal'])]['value']); - $this->validateDates($res['documentsTotal']); - - $res = $this->client->call( - Client::METHOD_GET, - '/databases/' . $databaseId . '/usage?range=30d', - $data['consoleHeaders'] - ); - $res = $res['body']; - - $this->assertEquals($collectionsTotal, $res['collectionsTotal'][array_key_last($res['collectionsTotal'])]['value']); - $this->validateDates($res['collectionsTotal']); - - $this->assertEquals($documentsTotal, $res['documentsTotal'][array_key_last($res['documentsTotal'])]['value']); - $this->validateDates($res['documentsTotal']); - - $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', $data['consoleHeaders']); - $res = $res['body']; - - $this->assertEquals($documentsTotal, $res['documentsTotal'][array_key_last($res['documentsTotal'])]['value']); - $this->validateDates($res['documentsTotal']); - - $data['requestsTotal'] = $requestsTotal; - - return $data; - } - - - /** @depends testDatabaseStats */ - public function testPrepareFunctionsStats(array $data): array - { - $dateValidator = new DatetimeValidator(); - $headers = $data['headers']; - $executionTime = 0; - $executions = 0; - $failures = 0; - - $response1 = $this->client->call( - Client::METHOD_POST, - '/functions', - $headers, - [ - 'functionId' => 'unique()', - 'name' => 'Test', - 'runtime' => 'php-8.0', - 'vars' => [ - 'funcKey1' => 'funcValue1', - 'funcKey2' => 'funcValue2', - 'funcKey3' => 'funcValue3', - ], - 'events' => [ - 'users.*.create', - 'users.*.delete', - ], - 'schedule' => '0 0 1 1 *', - 'timeout' => 10, - ] - ); - - $functionId = $response1['body']['$id'] ?? ''; - - $this->assertEquals(201, $response1['headers']['status-code']); - $this->assertNotEmpty($response1['body']['$id']); - - $code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz"; - $this->packageCode('php'); - - $deployment = $this->client->call( - Client::METHOD_POST, - '/functions/' . $functionId . '/deployments', - array_merge($headers, ['content-type' => 'multipart/form-data',]), - [ - '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->assertNotEmpty($deployment['body']['$id']); - $this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt'])); - $this->assertEquals('index.php', $deployment['body']['entrypoint']); - - // Wait for deployment to build. - sleep(self::WAIT + 20); - - $response = $this->client->call( - Client::METHOD_PATCH, - '/functions/' . $functionId . '/deployments/' . $deploymentId, - $headers - ); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertNotEmpty($response['body']['$id']); - - $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['$createdAt'])); - $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['$updatedAt'])); - $this->assertEquals($deploymentId, $response['body']['deployment']); - - $execution = $this->client->call( - Client::METHOD_POST, - '/functions/' . $functionId . '/executions', - $headers, - [ - 'async' => false, - ] - ); - - $this->assertEquals(201, $execution['headers']['status-code']); - $this->assertNotEmpty($execution['body']['$id']); - $this->assertEquals($functionId, $execution['body']['functionId']); - - $executionTime += (int) ($execution['body']['duration'] * 1000); - - if ($execution['body']['status'] == 'failed') { - $failures++; - } elseif ($execution['body']['status'] == 'completed') { - $executions++; - } - - $execution = $this->client->call( - Client::METHOD_POST, - '/functions/' . $functionId . '/executions', - $headers, - [ - 'async' => false, - ] - ); - - $this->assertEquals(201, $execution['headers']['status-code']); - $this->assertNotEmpty($execution['body']['$id']); - $this->assertEquals($functionId, $execution['body']['functionId']); - if ($execution['body']['status'] == 'failed') { - $failures++; - } elseif ($execution['body']['status'] == 'completed') { - $executions++; - } - $executionTime += (int) ($execution['body']['duration'] * 1000); - - $execution = $this->client->call( - Client::METHOD_POST, - '/functions/' . $functionId . '/executions', - $headers, - [ - 'async' => true, - ] - ); - - $this->assertEquals(202, $execution['headers']['status-code']); - $this->assertNotEmpty($execution['body']['$id']); - $this->assertEquals($functionId, $execution['body']['functionId']); - - sleep(self::WAIT); - - $execution = $this->client->call( - Client::METHOD_GET, - '/functions/' . $functionId . '/executions/' . $execution['body']['$id'], - $headers - ); - - if ($execution['body']['status'] == 'failed') { - $failures++; - } elseif ($execution['body']['status'] == 'completed') { - $executions++; - } - - $executionTime += (int) ($execution['body']['duration'] * 1000); - - return array_merge($data, [ - 'functionId' => $functionId, - 'executionTime' => $executionTime, - 'executions' => $executions, - 'failures' => $failures, - ]); - } - - /** @depends testPrepareFunctionsStats */ - public function testFunctionsStats(array $data): void - { - $functionId = $data['functionId']; - $executionTime = $data['executionTime']; - $executions = $data['executions']; - - sleep(self::WAIT); - - $response = $this->client->call( - Client::METHOD_GET, - '/functions/' . $functionId . '/usage?range=30d', - $data['consoleHeaders'] - ); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(8, count($response['body'])); - $this->assertEquals('30d', $response['body']['range']); - $this->assertIsArray($response['body']['deploymentsTotal']); - $this->assertIsArray($response['body']['deploymentsStorage']); - $this->assertIsArray($response['body']['buildsTotal']); - $this->assertIsArray($response['body']['buildsTime']); - $this->assertIsArray($response['body']['executionsTotal']); - $this->assertIsArray($response['body']['executionsTime']); - - $response = $response['body']; - - $this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']); - $this->validateDates($response['executionsTotal']); - $this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']); - $this->validateDates($response['executionsTime']); - - $response = $this->client->call( - Client::METHOD_GET, - '/functions/usage?range=30d', - $data['consoleHeaders'] - ); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(9, count($response['body'])); - $this->assertEquals($response['body']['range'], '30d'); - $this->assertIsArray($response['body']['functionsTotal']); - $this->assertIsArray($response['body']['deploymentsTotal']); - $this->assertIsArray($response['body']['deploymentsStorage']); - $this->assertIsArray($response['body']['buildsTotal']); - $this->assertIsArray($response['body']['buildsTime']); - $this->assertIsArray($response['body']['executionsTotal']); - $this->assertIsArray($response['body']['executionsTime']); - - $response = $response['body']; - - $this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']); - $this->validateDates($response['executionsTotal']); - $this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']); - $this->validateDates($response['executionsTime']); - $this->assertGreaterThan(0, $response['buildsTime'][array_key_last($response['buildsTime'])]['value']); - $this->validateDates($response['buildsTime']); - } - - public function tearDown(): void - { - $this->projectId = ''; - } -} +use Utopia\Database\Permission; +use Utopia\Database\Role; + +// TODO @christyjacob4 : enable test once usage stats are fixed +// class UsageTest extends Scope +// { +// use ProjectCustom; +// use SideServer; +// use FunctionsBase; + +// protected string $projectId; + +// protected function setUp(): void +// { +// parent::setUp(); +// } + +// protected static string $formatTz = 'Y-m-d\TH:i:s.vP'; + +// protected function validateDates(array $metrics): void +// { +// foreach ($metrics as $metric) { +// $this->assertIsObject(\DateTime::createFromFormat("Y-m-d\TH:i:s.vP", $metric['date'])); +// } +// } + +// public function testPrepareUsersStats(): array +// { +// $project = $this->getProject(true); +// $projectId = $project['$id']; +// $headers['x-appwrite-project'] = $project['$id']; +// $headers['x-appwrite-key'] = $project['apiKey']; +// $headers['content-type'] = 'application/json'; + +// $usersCount = 0; +// $requestsCount = 0; +// for ($i = 0; $i < 10; $i++) { +// $email = uniqid() . 'user@usage.test'; +// $password = 'password'; +// $name = uniqid() . 'User'; +// $res = $this->client->call(Client::METHOD_POST, '/users', $headers, [ +// 'userId' => 'unique()', +// 'email' => $email, +// 'password' => $password, +// 'name' => $name, +// ]); +// $this->assertEquals($email, $res['body']['email']); +// $this->assertNotEmpty($res['body']['$id']); +// $usersCount++; +// $requestsCount++; + +// if ($i < 5) { +// $userId = $res['body']['$id']; +// $res = $this->client->call(Client::METHOD_GET, '/users/' . $userId, $headers); +// $this->assertEquals($userId, $res['body']['$id']); +// $res = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, $headers); +// $this->assertEmpty($res['body']); +// $requestsCount += 2; +// $usersCount--; +// } +// } + +// return [ +// 'projectId' => $projectId, +// 'headers' => $headers, +// 'usersCount' => $usersCount, +// 'requestsCount' => $requestsCount +// ]; +// } + +// /** +// * @depends testPrepareUsersStats +// */ +// #[Retry(count: 1)] +// public function testUsersStats(array $data): array +// { +// sleep(20); + +// $projectId = $data['projectId']; +// $headers = $data['headers']; +// $usersCount = $data['usersCount']; +// $requestsCount = $data['requestsCount']; + +// // console request +// $headers = [ +// 'origin' => 'http://localhost', +// 'x-appwrite-project' => 'console', +// 'cookie' => 'a_session_console=' . $this->getRoot()['session'], +// 'x-appwrite-project' => $projectId, +// 'x-appwrite-mode' => 'admin', +// ]; + +// $res = $this->client->call(Client::METHOD_GET, '/project/usage?range=30d', $headers); +// $res = $res['body']; + +// $this->assertEquals(9, count($res)); +// $this->assertEquals(30, count($res['requests'])); +// $this->assertEquals(30, count($res['users'])); +// $this->assertEquals($usersCount, $res['users'][array_key_last($res['users'])]['value']); +// $this->validateDates($res['users']); +// $this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']); +// $this->validateDates($res['requests']); + +// $res = $this->client->call(Client::METHOD_GET, '/users/usage?range=30d', array_merge($headers, [ +// 'x-appwrite-project' => $projectId, +// 'x-appwrite-mode' => 'admin' +// ])); +// $requestsCount++; +// $res = $res['body']; +// $this->assertEquals(10, $res['usersCreate'][array_key_last($res['usersCreate'])]['value']); +// $this->validateDates($res['usersCreate']); +// $this->assertEquals(5, $res['usersRead'][array_key_last($res['usersRead'])]['value']); +// $this->validateDates($res['usersRead']); +// $this->assertEquals(5, $res['usersDelete'][array_key_last($res['usersDelete'])]['value']); +// $this->validateDates($res['usersDelete']); + +// return ['projectId' => $projectId, 'headers' => $headers, 'requestsCount' => $requestsCount]; +// } + +// /** @depends testUsersStats */ +// public function testPrepareStorageStats(array $data): array +// { +// $projectId = $data['projectId']; +// $headers = $data['headers']; + +// $bucketId = ''; +// $bucketsCount = 0; +// $requestsCount = $data['requestsCount']; +// $storageTotal = 0; +// $bucketsCreate = 0; +// $bucketsDelete = 0; +// $bucketsRead = 0; +// $filesCount = 0; +// $filesRead = 0; +// $filesCreate = 0; +// $filesDelete = 0; + +// for ($i = 0; $i < 10; $i++) { +// $name = uniqid() . ' bucket'; +// $res = $this->client->call(Client::METHOD_POST, '/storage/buckets', \array_merge($headers, [ +// 'content-type' => 'application/json' +// ]), [ +// 'bucketId' => 'unique()', +// 'name' => $name, +// 'fileSecurity' => false, +// 'permissions' => [ +// Permission::read(Role::any()), +// Permission::create(Role::any()), +// Permission::update(Role::any()), +// Permission::delete(Role::any()), +// ], +// ]); +// $this->assertEquals($name, $res['body']['name']); +// $this->assertNotEmpty($res['body']['$id']); +// $bucketId = $res['body']['$id']; + +// $bucketsCreate++; +// $bucketsCount++; +// $requestsCount++; + +// if ($i < 5) { +// $res = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId, $headers); +// $this->assertEquals($bucketId, $res['body']['$id']); +// $bucketsRead++; + +// $res = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId, $headers); +// $this->assertEmpty($res['body']); +// $bucketsDelete++; + +// $requestsCount += 2; +// $bucketsCount--; +// } +// } + +// // upload some files +// $files = [ +// [ +// 'path' => realpath(__DIR__ . '/../../resources/logo.png'), +// 'name' => 'logo.png', +// ], +// [ +// 'path' => realpath(__DIR__ . '/../../resources/file.png'), +// 'name' => 'file.png', +// ], +// [ +// 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-3.gif'), +// 'name' => 'kitten-3.gif', +// ], +// [ +// 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'), +// 'name' => 'kitten-1.jpg', +// ], +// ]; + +// for ($i = 0; $i < 10; $i++) { +// $file = $files[$i % count($files)]; +// $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge($headers, ['content-type' => 'multipart/form-data']), [ +// 'fileId' => 'unique()', +// 'file' => new CURLFile($file['path'], '', $file['name']), +// ]); +// $this->assertNotEmpty($res['body']['$id']); + +// $fileSize = $res['body']['sizeOriginal']; +// $storageTotal += $fileSize; +// $filesCount++; +// $filesCreate++; +// $requestsCount++; + +// $fileId = $res['body']['$id']; +// if ($i < 5) { +// $res = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, $headers); +// $this->assertEquals($fileId, $res['body']['$id']); +// $filesRead++; + +// $res = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, $headers); +// $this->assertEmpty($res['body']); +// $filesDelete++; +// $requestsCount += 2; +// $filesCount--; +// $storageTotal -= $fileSize; +// } +// } + +// return array_merge($data, [ +// 'bucketId' => $bucketId, +// 'bucketsCount' => $bucketsCount, +// 'requestsCount' => $requestsCount, +// 'storageTotal' => $storageTotal, +// 'bucketsCreate' => $bucketsCreate, +// 'bucketsDelete' => $bucketsDelete, +// 'bucketsRead' => $bucketsRead, +// 'filesCount' => $filesCount, +// 'filesRead' => $filesRead, +// 'filesCreate' => $filesCreate, +// 'filesDelete' => $filesDelete, +// ]); +// } + +// /** +// * @depends testPrepareStorageStats +// */ +// #[Retry(count: 1)] +// public function testStorageStats(array $data): array +// { +// $projectId = $data['projectId']; +// $bucketId = $data['bucketId']; +// $bucketsCount = $data['bucketsCount']; +// $requestsCount = $data['requestsCount']; +// $storageTotal = $data['storageTotal']; +// $bucketsCreate = $data['bucketsCreate']; +// $bucketsDelete = $data['bucketsDelete']; +// $bucketsRead = $data['bucketsRead']; +// $filesCount = $data['filesCount']; +// $filesRead = $data['filesRead']; +// $filesCreate = $data['filesCreate']; +// $filesDelete = $data['filesDelete']; + +// sleep(20); + +// // console request +// $headers = [ +// 'origin' => 'http://localhost', +// 'x-appwrite-project' => 'console', +// 'cookie' => 'a_session_console=' . $this->getRoot()['session'], +// 'x-appwrite-project' => $projectId, +// 'x-appwrite-mode' => 'admin', +// ]; + +// $res = $this->client->call(Client::METHOD_GET, '/project/usage?range=30d', $headers); +// $res = $res['body']; + +// $this->assertEquals(9, count($res)); +// $this->assertEquals(30, count($res['requests'])); +// $this->assertEquals(30, count($res['storage'])); +// $this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']); +// $this->validateDates($res['requests']); +// $this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']); +// $this->validateDates($res['storage']); + +// $res = $this->client->call(Client::METHOD_GET, '/storage/usage?range=30d', array_merge($headers, [ +// 'x-appwrite-project' => $projectId, +// 'x-appwrite-mode' => 'admin' +// ])); +// $requestsCount++; +// $res = $res['body']; +// $this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']); +// $this->validateDates($res['storage']); +// $this->assertEquals($bucketsCount, $res['bucketsCount'][array_key_last($res['bucketsCount'])]['value']); +// $this->validateDates($res['bucketsCount']); +// $this->assertEquals($bucketsRead, $res['bucketsRead'][array_key_last($res['bucketsRead'])]['value']); +// $this->validateDates($res['bucketsRead']); +// $this->assertEquals($bucketsCreate, $res['bucketsCreate'][array_key_last($res['bucketsCreate'])]['value']); +// $this->validateDates($res['bucketsCreate']); +// $this->assertEquals($bucketsDelete, $res['bucketsDelete'][array_key_last($res['bucketsDelete'])]['value']); +// $this->validateDates($res['bucketsDelete']); +// $this->assertEquals($filesCount, $res['filesCount'][array_key_last($res['filesCount'])]['value']); +// $this->validateDates($res['filesCount']); +// $this->assertEquals($filesRead, $res['filesRead'][array_key_last($res['filesRead'])]['value']); +// $this->validateDates($res['filesRead']); +// $this->assertEquals($filesCreate, $res['filesCreate'][array_key_last($res['filesCreate'])]['value']); +// $this->validateDates($res['filesCreate']); +// $this->assertEquals($filesDelete, $res['filesDelete'][array_key_last($res['filesDelete'])]['value']); +// $this->validateDates($res['filesDelete']); + +// $res = $this->client->call(Client::METHOD_GET, '/storage/' . $bucketId . '/usage?range=30d', array_merge($headers, [ +// 'x-appwrite-project' => $projectId, +// 'x-appwrite-mode' => 'admin' +// ])); +// $requestsCount++; +// $res = $res['body']; +// $this->assertEquals($storageTotal, $res['filesStorage'][array_key_last($res['filesStorage'])]['value']); +// $this->assertEquals($filesCount, $res['filesCount'][array_key_last($res['filesCount'])]['value']); +// $this->assertEquals($filesRead, $res['filesRead'][array_key_last($res['filesRead'])]['value']); +// $this->assertEquals($filesCreate, $res['filesCreate'][array_key_last($res['filesCreate'])]['value']); +// $this->assertEquals($filesDelete, $res['filesDelete'][array_key_last($res['filesDelete'])]['value']); + +// $data['requestsCount'] = $requestsCount; +// return $data; +// } + +// /** @depends testStorageStats */ +// public function testPrepareDatabaseStats(array $data): array +// { +// $headers = $data['headers']; +// $projectId = $data['projectId']; + +// $databaseId = ''; +// $collectionId = ''; + +// $requestsCount = $data['requestsCount']; +// $databasesCount = 0; +// $databasesCreate = 0; +// $databasesRead = 0; +// $databasesDelete = 0; + +// $collectionsCount = 0; +// $collectionsCreate = 0; +// $collectionsRead = 0; +// $collectionsUpdate = 0; +// $collectionsDelete = 0; + +// $documentsCount = 0; +// $documentsCreate = 0; +// $documentsRead = 0; +// $documentsDelete = 0; + +// for ($i = 0; $i < 10; $i++) { +// $name = uniqid() . ' database'; +// $res = $this->client->call(Client::METHOD_POST, '/databases', $headers, [ +// 'databaseId' => 'unique()', +// 'name' => $name, +// ]); +// $this->assertEquals($name, $res['body']['name']); +// $this->assertNotEmpty($res['body']['$id']); +// $databaseId = $res['body']['$id']; + +// $requestsCount++; +// $databasesCount++; +// $databasesCreate++; + +// if ($i < 5) { +// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId, $headers); +// $this->assertEquals($databaseId, $res['body']['$id']); +// $databasesRead++; + +// $res = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, $headers); +// $this->assertEmpty($res['body']); +// $databasesDelete++; + +// $databasesCount--; +// $requestsCount += 2; +// } +// } + +// for ($i = 0; $i < 10; $i++) { +// $name = uniqid() . ' collection'; +// $res = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $headers, [ +// 'collectionId' => 'unique()', +// 'name' => $name, +// 'documentSecurity' => false, +// 'permissions' => [ +// Permission::read(Role::any()), +// Permission::create(Role::any()), +// Permission::update(Role::any()), +// Permission::delete(Role::any()), +// ], +// ]); +// $this->assertEquals($name, $res['body']['name']); +// $this->assertNotEmpty($res['body']['$id']); +// $collectionId = $res['body']['$id']; + +// $requestsCount++; +// $collectionsCount++; +// $collectionsCreate++; + +// if ($i < 5) { +// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, $headers); +// $this->assertEquals($collectionId, $res['body']['$id']); +// $collectionsRead++; + +// $res = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, $headers); +// $this->assertEmpty($res['body']); +// $collectionsDelete++; + +// $collectionsCount--; +// $requestsCount += 2; +// } +// } + +// $res = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes' . '/string', $headers, [ +// 'key' => 'name', +// 'size' => 255, +// 'required' => true, +// ]); +// $this->assertEquals('name', $res['body']['key']); +// $collectionsUpdate++; +// $requestsCount++; +// sleep(20); + +// for ($i = 0; $i < 10; $i++) { +// $name = uniqid() . ' collection'; +// $res = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', $headers, [ +// 'documentId' => 'unique()', +// 'data' => ['name' => $name] +// ]); +// $this->assertEquals($name, $res['body']['name']); +// $this->assertNotEmpty($res['body']['$id']); +// $documentId = $res['body']['$id']; + +// $requestsCount++; +// $documentsCount++; +// $documentsCreate++; + +// if ($i < 5) { +// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, $headers); +// $this->assertEquals($documentId, $res['body']['$id']); +// $documentsRead++; + +// $res = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, $headers); +// $this->assertEmpty($res['body']); +// $documentsDelete++; + +// $documentsCount--; +// $requestsCount += 2; +// } +// } + +// $data = array_merge($data, [ +// 'databaseId' => $databaseId, +// 'collectionId' => $collectionId, + +// 'requestsCount' => $requestsCount, +// 'databasesCount' => $databasesCount, +// 'databasesCreate' => $databasesCreate, +// 'databasesRead' => $databasesRead, +// 'databasesDelete' => $databasesDelete, + +// 'collectionsCount' => $collectionsCount, +// 'collectionsCreate' => $collectionsCreate, +// 'collectionsRead' => $collectionsRead, +// 'collectionsUpdate' => $collectionsUpdate, +// 'collectionsDelete' => $collectionsDelete, + +// 'documentsCount' => $documentsCount, +// 'documentsCreate' => $documentsCreate, +// 'documentsRead' => $documentsRead, +// 'documentsDelete' => $documentsDelete, +// ]); + +// return $data; +// } + +// /** @depends testPrepareDatabaseStats */ +// #[Retry(count: 1)] +// public function testDatabaseStats(array $data): array +// { +// $headers = $data['headers']; +// $projectId = $data['projectId']; + +// $databaseId = $data['databaseId']; +// $collectionId = $data['collectionId']; + +// $requestsCount = $data['requestsCount']; +// $databasesCount = $data['databasesCount']; +// $databasesCreate = $data['databasesCreate']; +// $databasesRead = $data['databasesRead']; +// $databasesDelete = $data['databasesDelete']; + +// $collectionsCount = $data['collectionsCount']; +// $collectionsCreate = $data['collectionsCreate']; +// $collectionsRead = $data['collectionsRead']; +// $collectionsUpdate = $data['collectionsUpdate']; +// $collectionsDelete = $data['collectionsDelete']; + +// $documentsCount = $data['documentsCount']; +// $documentsCreate = $data['documentsCreate']; +// $documentsRead = $data['documentsRead']; +// $documentsDelete = $data['documentsDelete']; + +// sleep(20); + +// // check datbase stats +// $headers = [ +// 'origin' => 'http://localhost', +// 'x-appwrite-project' => 'console', +// 'cookie' => 'a_session_console=' . $this->getRoot()['session'], +// 'x-appwrite-project' => $projectId, +// 'x-appwrite-mode' => 'admin', +// ]; + +// $res = $this->client->call(Client::METHOD_GET, '/project/usage?range=30d', $headers); +// $res = $res['body']; + +// $this->assertEquals(9, count($res)); +// $this->assertEquals(30, count($res['requests'])); +// $this->assertEquals(30, count($res['storage'])); +// $this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']); +// $this->validateDates($res['requests']); +// $this->assertEquals($databasesCount, $res['databases'][array_key_last($res['databases'])]['value']); +// $this->validateDates($res['databases']); +// $this->assertEquals($documentsCount, $res['documents'][array_key_last($res['documents'])]['value']); +// $this->validateDates($res['documents']); + +// $res = $this->client->call(Client::METHOD_GET, '/databases/usage?range=30d', array_merge($headers, [ +// 'x-appwrite-project' => $projectId, +// 'x-appwrite-mode' => 'admin' +// ])); +// $res = $res['body']; +// $this->assertEquals($databasesCount, $res['databasesCount'][array_key_last($res['databasesCount'])]['value']); +// $this->validateDates($res['databasesCount']); +// $this->assertEquals($collectionsCount, $res['collectionsCount'][array_key_last($res['collectionsCount'])]['value']); +// $this->validateDates($res['collectionsCount']); +// $this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']); +// $this->validateDates($res['documentsCount']); + +// $this->assertEquals($databasesCreate, $res['databasesCreate'][array_key_last($res['databasesCreate'])]['value']); +// $this->validateDates($res['databasesCreate']); +// $this->assertEquals($databasesRead, $res['databasesRead'][array_key_last($res['databasesRead'])]['value']); +// $this->validateDates($res['databasesRead']); +// $this->assertEquals($databasesDelete, $res['databasesDelete'][array_key_last($res['databasesDelete'])]['value']); +// $this->validateDates($res['databasesDelete']); + +// $this->assertEquals($collectionsCreate, $res['collectionsCreate'][array_key_last($res['collectionsCreate'])]['value']); +// $this->validateDates($res['collectionsCreate']); +// $this->assertEquals($collectionsRead, $res['collectionsRead'][array_key_last($res['collectionsRead'])]['value']); +// $this->validateDates($res['collectionsRead']); +// $this->assertEquals($collectionsUpdate, $res['collectionsUpdate'][array_key_last($res['collectionsUpdate'])]['value']); +// $this->validateDates($res['collectionsUpdate']); +// $this->assertEquals($collectionsDelete, $res['collectionsDelete'][array_key_last($res['collectionsDelete'])]['value']); +// $this->validateDates($res['collectionsDelete']); + +// $this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']); +// $this->validateDates($res['documentsCreate']); +// $this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']); +// $this->validateDates($res['documentsRead']); +// $this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']); +// $this->validateDates($res['documentsDelete']); + +// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage?range=30d', array_merge($headers, [ +// 'x-appwrite-project' => $projectId, +// 'x-appwrite-mode' => 'admin' +// ])); +// $res = $res['body']; +// $this->assertEquals($collectionsCount, $res['collectionsCount'][array_key_last($res['collectionsCount'])]['value']); +// $this->validateDates($res['collectionsCount']); +// $this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']); +// $this->validateDates($res['documentsCount']); + +// $this->assertEquals($collectionsCreate, $res['collectionsCreate'][array_key_last($res['collectionsCreate'])]['value']); +// $this->validateDates($res['collectionsCreate']); +// $this->assertEquals($collectionsRead, $res['collectionsRead'][array_key_last($res['collectionsRead'])]['value']); +// $this->validateDates($res['collectionsRead']); +// $this->assertEquals($collectionsUpdate, $res['collectionsUpdate'][array_key_last($res['collectionsUpdate'])]['value']); +// $this->validateDates($res['collectionsUpdate']); +// $this->assertEquals($collectionsDelete, $res['collectionsDelete'][array_key_last($res['collectionsDelete'])]['value']); +// $this->validateDates($res['collectionsDelete']); + +// $this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']); +// $this->validateDates($res['documentsCreate']); +// $this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']); +// $this->validateDates($res['documentsRead']); +// $this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']); +// $this->validateDates($res['documentsDelete']); + +// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', array_merge($headers, [ +// 'x-appwrite-project' => $projectId, +// 'x-appwrite-mode' => 'admin' +// ])); +// $res = $res['body']; +// $this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']); +// $this->validateDates($res['documentsCount']); + +// $this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']); +// $this->validateDates($res['documentsCreate']); +// $this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']); +// $this->validateDates($res['documentsRead']); +// $this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']); +// $this->validateDates($res['documentsDelete']); + +// $data['requestsCount'] = $requestsCount; +// return $data; +// } + + +// /** @depends testDatabaseStats */ +// public function testPrepareFunctionsStats(array $data): array +// { +// $headers = $data['headers']; +// $functionId = ''; +// $executionTime = 0; +// $executions = 0; +// $failures = 0; + +// $response1 = $this->client->call(Client::METHOD_POST, '/functions', $headers, [ +// 'functionId' => 'unique()', +// 'name' => 'Test', +// 'runtime' => 'php-8.0', +// 'vars' => [ +// 'funcKey1' => 'funcValue1', +// 'funcKey2' => 'funcValue2', +// 'funcKey3' => 'funcValue3', +// ], +// 'events' => [ +// 'users.*.create', +// 'users.*.delete', +// ], +// 'schedule' => '0 0 1 1 *', +// 'timeout' => 10, +// ]); + +// $functionId = $response1['body']['$id'] ?? ''; + +// $this->assertEquals(201, $response1['headers']['status-code']); +// $this->assertNotEmpty($response1['body']['$id']); + +// $code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz"; +// $this->packageCode('php'); + +// $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge($headers, ['content-type' => 'multipart/form-data',]), [ +// '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->assertNotEmpty($deployment['body']['$id']); +// $this->assertEquals(true, DateTime::isValid($deployment['body']['$createdAt'])); +// $this->assertEquals('index.php', $deployment['body']['entrypoint']); + +// // Wait for deployment to build. +// sleep(30); + +// $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, $headers, []); + +// $this->assertEquals(200, $response['headers']['status-code']); +// $this->assertNotEmpty($response['body']['$id']); +// $this->assertEquals(true, DateTime::isValid($response['body']['$createdAt'])); +// $this->assertEquals(true, DateTime::isValid($response['body']['$updatedAt'])); +// $this->assertEquals($deploymentId, $response['body']['deployment']); + +// $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', $headers, [ +// 'async' => false, +// ]); + +// $this->assertEquals(201, $execution['headers']['status-code']); +// $this->assertNotEmpty($execution['body']['$id']); +// $this->assertEquals($functionId, $execution['body']['functionId']); +// $executionTime += (int) ($execution['body']['duration'] * 1000); +// if ($execution['body']['status'] == 'failed') { +// $failures++; +// } elseif ($execution['body']['status'] == 'completed') { +// $executions++; +// } + +// $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', $headers, [ +// 'async' => false, +// ]); + +// $this->assertEquals(201, $execution['headers']['status-code']); +// $this->assertNotEmpty($execution['body']['$id']); +// $this->assertEquals($functionId, $execution['body']['functionId']); +// if ($execution['body']['status'] == 'failed') { +// $failures++; +// } elseif ($execution['body']['status'] == 'completed') { +// $executions++; +// } +// $executionTime += (int) ($execution['body']['duration'] * 1000); + +// $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', $headers, [ +// 'async' => true, +// ]); + +// sleep(10); + +// $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $execution['body']['$id'], $headers); + +// if ($execution['body']['status'] == 'failed') { +// $failures++; +// } elseif ($execution['body']['status'] == 'completed') { +// $executions++; +// } +// $executionTime += (int) ($execution['body']['duration'] * 1000); + +// $data = array_merge($data, [ +// 'functionId' => $functionId, +// 'executionTime' => $executionTime, +// 'executions' => $executions, +// 'failures' => $failures, +// ]); + +// return $data; +// } + +// /** @depends testPrepareFunctionsStats */ +// #[Retry(count: 1)] +// public function testFunctionsStats(array $data): void +// { +// $headers = $data['headers']; +// $functionId = $data['functionId']; +// $executionTime = $data['executionTime']; +// $executions = $data['executions']; +// $failures = $data['failures']; + +// sleep(20); + +// $response = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', $headers, [ +// 'range' => '30d' +// ]); + +// $this->assertEquals(200, $response['headers']['status-code']); +// $this->assertEquals(9, count($response['body'])); +// $this->assertEquals('30d', $response['body']['range']); +// $this->assertIsArray($response['body']['executionsTotal']); +// $this->assertIsArray($response['body']['executionsFailure']); +// $this->assertIsArray($response['body']['executionsSuccess']); +// $this->assertIsArray($response['body']['executionsTime']); +// $this->assertIsArray($response['body']['buildsTotal']); +// $this->assertIsArray($response['body']['buildsFailure']); +// $this->assertIsArray($response['body']['buildsSuccess']); +// $this->assertIsArray($response['body']['buildsTime']); +// $response = $response['body']; + +// $this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']); +// $this->validateDates($response['executionsTotal']); +// $this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']); +// $this->validateDates($response['executionsTime']); +// $this->assertEquals($failures, $response['executionsFailure'][array_key_last($response['executionsFailure'])]['value']); +// $this->validateDates($response['executionsFailure']); + +// $response = $this->client->call(Client::METHOD_GET, '/functions/usage', $headers, [ +// 'range' => '30d' +// ]); + +// $this->assertEquals(200, $response['headers']['status-code']); +// $this->assertEquals(9, count($response['body'])); +// $this->assertEquals($response['body']['range'], '30d'); +// $this->assertIsArray($response['body']['executionsTotal']); +// $this->assertIsArray($response['body']['executionsFailure']); +// $this->assertIsArray($response['body']['executionsSuccess']); +// $this->assertIsArray($response['body']['executionsTime']); +// $this->assertIsArray($response['body']['buildsTotal']); +// $this->assertIsArray($response['body']['buildsFailure']); +// $this->assertIsArray($response['body']['buildsSuccess']); +// $this->assertIsArray($response['body']['buildsTime']); +// $response = $response['body']; + +// $this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']); +// $this->validateDates($response['executionsTotal']); +// $this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']); +// $this->validateDates($response['executionsTime']); +// $this->assertGreaterThan(0, $response['buildsTime'][array_key_last($response['buildsTime'])]['value']); +// $this->validateDates($response['buildsTime']); +// $this->assertEquals($failures, $response['executionsFailure'][array_key_last($response['executionsFailure'])]['value']); +// $this->validateDates($response['executionsFailure']); +// } + +// protected function tearDown(): void +// { +// $this->usersCount = 0; +// $this->requestsCount = 0; +// $projectId = ''; +// $headers = []; +// } +// } diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index 1bd4de501c..408b8c8fe7 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -109,6 +109,21 @@ trait ProjectCustom $this->assertEquals(201, $webhook['headers']['status-code']); $this->assertNotEmpty($webhook['body']); + $this->client->call(Client::METHOD_PATCH, '/projects/' . $project['body']['$id'] . '/smtp', [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'x-appwrite-project' => 'console', + ], [ + 'enabled' => true, + 'senderEmail' => 'mailer@appwrite.io', + 'senderName' => 'Mailer', + 'host' => 'maildev', + 'port' => 1025, + 'username' => '', + 'password' => '', + ]); + $project = [ '$id' => $project['body']['$id'], 'name' => $project['body']['name'], diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 291d55b221..e64cf2c4ca 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -346,7 +346,7 @@ trait AccountBase */ public function testGetAccountLogs($data): array { - sleep(10); + sleep(5); $session = $data['session'] ?? ''; $sessionId = $data['sessionId'] ?? ''; $userId = $data['id'] ?? ''; diff --git a/tests/e2e/Services/Account/AccountConsoleClientTest.php b/tests/e2e/Services/Account/AccountConsoleClientTest.php index b517d8c408..3d4445dcc9 100644 --- a/tests/e2e/Services/Account/AccountConsoleClientTest.php +++ b/tests/e2e/Services/Account/AccountConsoleClientTest.php @@ -15,85 +15,4 @@ class AccountConsoleClientTest extends Scope use AccountBase; use ProjectConsole; use SideClient; - - public function testCreateAccountWithInvite(): void - { - $email = uniqid() . 'user@localhost.test'; - $password = 'password'; - $name = 'User Name'; - - /** - * Test for FAILURE - */ - $response = $this->client->call(Client::METHOD_POST, '/account/invite', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'userId' => ID::unique(), - 'email' => $email, - 'password' => $password, - 'name' => $name, - 'code' => 'Invalid Code' - ]); - - $this->assertEquals($response['headers']['status-code'], 401); - $this->assertEquals($response['body']['type'], Exception::USER_INVALID_CODE); - - $response = $this->client->call(Client::METHOD_POST, '/account/invite', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'userId' => ID::unique(), - 'email' => $email, - 'password' => $password, - 'name' => $name, - ]); - - $this->assertEquals($response['headers']['status-code'], 401); - $this->assertEquals($response['body']['type'], Exception::USER_INVALID_CODE); - - /** - * Test for SUCCESS - */ - $response = $this->client->call(Client::METHOD_POST, '/account/invite', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'userId' => ID::unique(), - 'email' => $email, - 'password' => $password, - 'name' => $name, - 'code' => 'code-zero' - ]); - - $this->assertEquals(201, $response['headers']['status-code']); - $this->assertNotEmpty($response['body']); - $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['registration'])); - $this->assertEquals($response['body']['email'], $email); - $this->assertEquals($response['body']['name'], $name); - - $email = uniqid() . 'user@localhost.test'; - $response = $this->client->call(Client::METHOD_POST, '/account/invite', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'userId' => ID::unique(), - 'email' => $email, - 'password' => $password, - 'name' => $name, - 'code' => 'code-one' - ]); - - $this->assertEquals(201, $response['headers']['status-code']); - $this->assertNotEmpty($response['body']); - $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['registration'])); - $this->assertEquals($response['body']['email'], $email); - $this->assertEquals($response['body']['name'], $name); - } } diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index d225496a65..1441ab7f98 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -21,32 +21,6 @@ class AccountCustomClientTest extends Scope use ProjectCustom; use SideClient; - public function testCreateAccountWithInvite(): void - { - $email = uniqid() . 'user@localhost.test'; - $password = 'password'; - $name = 'User Name'; - - /** - * Test for FAILURE - * Make sure the invite endpoint is only accessible through the console project. - */ - $response = $this->client->call(Client::METHOD_POST, '/account/invite', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'userId' => ID::unique(), - 'email' => $email, - 'password' => $password, - 'name' => $name, - 'code' => 'Invalid Code' - ]); - - $this->assertEquals($response['headers']['status-code'], 401); - $this->assertEquals($response['body']['type'], Exception::GENERAL_ACCESS_FORBIDDEN); - } - /** * @depends testCreateAccountSession */ @@ -408,6 +382,7 @@ class AccountCustomClientTest extends Scope ])); $this->assertEquals($response['headers']['status-code'], 200); $this->assertArrayHasKey('accessedAt', $response['body']); + $this->assertNotEmpty($response['body']['accessedAt']); /** diff --git a/tests/e2e/Services/Avatars/AvatarsBase.php b/tests/e2e/Services/Avatars/AvatarsBase.php index e2ddc1a863..1652e01514 100644 --- a/tests/e2e/Services/Avatars/AvatarsBase.php +++ b/tests/e2e/Services/Avatars/AvatarsBase.php @@ -287,26 +287,6 @@ trait AvatarsBase $this->assertEquals('image/png', $response['headers']['content-type']); $this->assertNotEmpty($response['body']); - // $response = $this->client->call(Client::METHOD_GET, '/avatars/favicon', [ - // 'x-appwrite-project' => $this->getProject()['$id'], - // ], [ - // 'url' => 'https://www.bbc.com/', - // ]); - - // $this->assertEquals(200, $response['headers']['status-code']); - // $this->assertEquals('image/png', $response['headers']['content-type']); - // $this->assertNotEmpty($response['body']); - - // $response = $this->client->call(Client::METHOD_GET, '/avatars/favicon', [ - // 'x-appwrite-project' => $this->getProject()['$id'], - // ], [ - // 'url' => 'https://edition.cnn.com/', - // ]); - - // $this->assertEquals(200, $response['headers']['status-code']); - // $this->assertEquals('image/x-icon', $response['headers']['content-type']); - // $this->assertNotEmpty($response['body']); - /** * Test for FAILURE */ @@ -326,6 +306,14 @@ trait AvatarsBase $this->assertEquals(404, $response['headers']['status-code']); + $response = $this->client->call(Client::METHOD_GET, '/avatars/favicon', [ + 'x-appwrite-project' => $this->getProject()['$id'], + ], [ + 'url' => 'http://localhost', + ]); + + $this->assertEquals(404, $response['headers']['status-code']); + return []; } diff --git a/tests/e2e/Services/Console/ConsoleConsoleClientTest.php b/tests/e2e/Services/Console/ConsoleConsoleClientTest.php index 3c1e973821..ca9287cdca 100644 --- a/tests/e2e/Services/Console/ConsoleConsoleClientTest.php +++ b/tests/e2e/Services/Console/ConsoleConsoleClientTest.php @@ -21,13 +21,16 @@ class ConsoleConsoleClientTest extends Scope $response = $this->client->call(Client::METHOD_GET, '/console/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), []); + ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(4, $response['body']); + $this->assertCount(7, $response['body']); $this->assertIsString($response['body']['_APP_DOMAIN_TARGET']); $this->assertIsInt($response['body']['_APP_STORAGE_LIMIT']); $this->assertIsInt($response['body']['_APP_FUNCTIONS_SIZE_LIMIT']); $this->assertIsString($response['body']['_APP_DOMAIN_TARGET']); + $this->assertIsBool($response['body']['_APP_DOMAIN_ENABLED']); + $this->assertIsBool($response['body']['_APP_VCS_ENABLED']); + $this->assertIsBool($response['body']['_APP_ASSISTANT_ENABLED']); } } diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index c2c1c70bd6..88a7f99314 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -344,6 +344,63 @@ trait DatabasesBase $this->assertEquals(400, $response['headers']['status-code']); } + public function testUpdateAttributeEnum(): void + { + $database = $this->client->call(Client::METHOD_POST, '/databases', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'databaseId' => ID::unique(), + 'name' => 'Test Database 2' + ]); + + $players = $this->client->call(Client::METHOD_POST, '/databases/' . $database['body']['$id'] . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::unique(), + 'name' => 'Players', + 'documentSecurity' => true, + 'permissions' => [ + Permission::create(Role::user($this->getUser()['$id'])), + ], + ]); + + // Create enum attribute + $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $database['body']['$id'] . '/collections/' . $players['body']['$id'] . '/attributes/enum', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'key' => 'position', + 'elements' => ['goalkeeper', 'defender', 'midfielder', 'forward'], + 'required' => true, + 'array' => false, + ]); + + $this->assertEquals(202, $attribute['headers']['status-code']); + $this->assertEquals($attribute['body']['key'], 'position'); + $this->assertEquals($attribute['body']['elements'], ['goalkeeper', 'defender', 'midfielder', 'forward']); + + \sleep(2); + + // Update enum attribute + $attribute = $this->client->call(Client::METHOD_PATCH, '/databases/' . $database['body']['$id'] . '/collections/' . $players['body']['$id'] . '/attributes/enum/' . $attribute['body']['key'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'elements' => ['goalkeeper', 'defender', 'midfielder', 'forward', 'coach'], + 'required' => true, + 'default' => null + ]); + + $this->assertEquals(200, $attribute['headers']['status-code']); + $this->assertEquals($attribute['body']['elements'], ['goalkeeper', 'defender', 'midfielder', 'forward', 'coach']); + } + /** * @depends testCreateAttributes */ @@ -1284,62 +1341,6 @@ trait DatabasesBase return ['documents' => $documents['body']['documents'], 'databaseId' => $databaseId]; } - public function testCreateCollectionAlias(): array - { - // Create default database - $database = $this->client->call(Client::METHOD_POST, '/databases', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'databaseId' => ID::custom('default'), - 'name' => 'Default' - ]); - - $this->assertNotEmpty($database['body']['$id']); - $this->assertEquals(201, $database['headers']['status-code']); - - /** - * Test for SUCCESS - */ - - $movies = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Movies', - 'permissions' => [], - 'documentSecurity' => true, - ]); - - $this->assertEquals(201, $movies['headers']['status-code']); - $this->assertEquals('Movies', $movies['body']['name']); - - return ['moviesId' => $movies['body']['$id']]; - } - - /** - * @depends testCreateCollectionAlias - */ - public function testListDocumentsAlias(array $data): array - { - /** - * Test for SUCCESS - */ - - $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(0, $documents['body']['total']); - - return []; - } - /** * @depends testListDocuments */ @@ -2862,8 +2863,6 @@ trait DatabasesBase $collectionId = $collection['body']['$id']; - sleep(2); - $attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -2877,8 +2876,7 @@ trait DatabasesBase $this->assertEquals(202, $attribute['headers']['status-code'], 202); $this->assertEquals('attribute', $attribute['body']['key']); - // wait for db to add attribute - sleep(2); + \sleep(2); $index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([ 'content-type' => 'application/json', @@ -2893,8 +2891,7 @@ trait DatabasesBase $this->assertEquals(202, $index['headers']['status-code']); $this->assertEquals('key_attribute', $index['body']['key']); - // wait for db to add attribute - sleep(2); + \sleep(2); $document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ 'content-type' => 'application/json', @@ -2993,7 +2990,7 @@ trait DatabasesBase 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, ]); - // Current user has no collection permissions and document permissions are disabled + // other2 has no collection permissions and document permissions are disabled $this->assertEquals(404, $document3GetWithDocumentRead['headers']['status-code']); $documentsUser2 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [ @@ -3003,8 +3000,8 @@ trait DatabasesBase 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session2, ]); - // Current user has no collection permissions and document permissions are disabled - $this->assertEquals(404, $documentsUser2['headers']['status-code']); + // other2 has no collection permissions and document permissions are disabled + $this->assertEquals(401, $documentsUser2['headers']['status-code']); // Enable document permissions $collection = $this->client->call(CLient::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId, [ diff --git a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php index 17059adf88..04ac00c263 100644 --- a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php +++ b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php @@ -29,6 +29,7 @@ class DatabasesConsoleClientTest extends Scope $this->assertTrue($database['body']['enabled']); $databaseId = $database['body']['$id']; + /** * Test for SUCCESS */ @@ -51,7 +52,7 @@ class DatabasesConsoleClientTest extends Scope $this->assertEquals($movies['body']['name'], 'Movies'); /** - * Test When database is disabled but can still create collections + * Test when database is disabled but can still create collections */ $database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, array_merge([ 'content-type' => 'application/json', @@ -78,6 +79,17 @@ class DatabasesConsoleClientTest extends Scope 'documentSecurity' => true, ]); + /** + * Test when collection is disabled but can still modify collections + */ + $database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $movies['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'name' => 'Movies', + 'enabled' => false, + ]); + $this->assertEquals(201, $tvShows['headers']['status-code']); $this->assertEquals($tvShows['body']['name'], 'TvShows'); @@ -87,11 +99,12 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection * @param array $data + * @throws \Exception */ public function testListCollection(array $data) { /** - * Test When database is disabled but can still call list collections + * Test when database is disabled but can still call list collections */ $databaseId = $data['databaseId']; @@ -108,6 +121,7 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection * @param array $data + * @throws \Exception */ public function testGetCollection(array $data) { @@ -115,7 +129,7 @@ class DatabasesConsoleClientTest extends Scope $moviesCollectionId = $data['moviesId']; /** - * Test When database is disabled but can still call get collection + * Test when database and collection are disabled but can still call get collection */ $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $moviesCollectionId, array_merge([ 'content-type' => 'application/json', @@ -125,12 +139,14 @@ class DatabasesConsoleClientTest extends Scope $this->assertEquals(200, $collection['headers']['status-code']); $this->assertEquals('Movies', $collection['body']['name']); $this->assertEquals($moviesCollectionId, $collection['body']['$id']); - $this->assertTrue($collection['body']['enabled']); + $this->assertFalse($collection['body']['enabled']); } /** * @depends testCreateCollection * @param array $data + * @throws \Exception + * @throws \Exception */ public function testUpdateCollection(array $data) { @@ -138,7 +154,7 @@ class DatabasesConsoleClientTest extends Scope $moviesCollectionId = $data['moviesId']; /** - * Test When database is disabled but can still call update collection + * Test When database and collection are disabled but can still call update collection */ $collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $moviesCollectionId, array_merge([ 'content-type' => 'application/json', @@ -157,6 +173,8 @@ class DatabasesConsoleClientTest extends Scope /** * @depends testCreateCollection * @param array $data + * @throws \Exception + * @throws \Exception */ public function testDeleteCollection(array $data) { @@ -164,7 +182,7 @@ class DatabasesConsoleClientTest extends Scope $tvShowsId = $data['tvShowsId']; /** - * Test When database is disabled but can still call Delete collection + * Test when database and collection are disabled but can still call delete collection */ $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $tvShowsId, array_merge([ 'content-type' => 'application/json', @@ -175,44 +193,6 @@ class DatabasesConsoleClientTest extends Scope $this->assertEquals($response['body'], ""); } - /** - * @depends testCreateCollection - */ - public function testGetDatabaseUsage(array $data) - { - $databaseId = $data['databaseId']; - /** - * Test for FAILURE - */ - - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] - ], $this->getHeaders()), [ - 'range' => '32h' - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - - /** - * Test for SUCCESS - */ - - $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] - ], $this->getHeaders()), [ - 'range' => '24h' - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(count($response['body']), 3); - $this->assertEquals($response['body']['range'], '24h'); - $this->assertIsArray($response['body']['documentsTotal']); - $this->assertIsArray($response['body']['collectionsTotal']); - } - - /** * @depends testCreateCollection */ @@ -250,10 +230,15 @@ class DatabasesConsoleClientTest extends Scope ], $this->getHeaders()), [ 'range' => '24h' ]); + $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(count($response['body']), 2); + $this->assertEquals(count($response['body']), 6); $this->assertEquals($response['body']['range'], '24h'); - $this->assertIsArray($response['body']['documentsTotal']); + $this->assertIsArray($response['body']['documentsCount']); + $this->assertIsArray($response['body']['documentsCreate']); + $this->assertIsArray($response['body']['documentsRead']); + $this->assertIsArray($response['body']['documentsUpdate']); + $this->assertIsArray($response['body']['documentsDelete']); } /** diff --git a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php index b0ab884a07..743df9e53a 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php @@ -316,4 +316,420 @@ class DatabasesCustomClientTest extends Scope $this->assertEquals($relation['body']['relatedCollection'], $collection1RelationAttribute['relatedCollection']); $this->assertEquals('restrict', $collection1RelationAttribute['onDelete']); } + + public function testUpdateWithoutRelationPermission(): void + { + $userId = $this->getUser()['$id']; + $database = $this->client->call(Client::METHOD_POST, '/databases', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'databaseId' => ID::unique(), + 'name' => ID::unique(), + ]); + + $databaseId = $database['body']['$id']; + + // Creating collection 1 + $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::custom('collection1'), + 'name' => ID::custom('collection1'), + 'documentSecurity' => false, + 'permissions' => [ + Permission::create(Role::user($userId)), + Permission::read(Role::user($userId)), + Permission::delete(Role::user($userId)), + ] + ]); + + // Creating collection 2 + $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::custom('collection2'), + 'name' => ID::custom('collection2'), + 'documentSecurity' => false, + 'permissions' => [ + Permission::read(Role::user($userId)), + ] + ]); + + $collection3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::custom('collection3'), + 'name' => ID::custom('collection3'), + 'documentSecurity' => false, + 'permissions' => [ + Permission::create(Role::user($userId)), + Permission::read(Role::user($userId)), + Permission::delete(Role::user($userId)), + ] + ]); + + $collection4 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::custom('collection4'), + 'name' => ID::custom('collection4'), + 'documentSecurity' => false, + 'permissions' => [ + Permission::read(Role::user($userId)), + ] + ]); + + $collection5 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::custom('collection5'), + 'name' => ID::custom('collection5'), + 'documentSecurity' => false, + 'permissions' => [ + Permission::create(Role::user($userId)), + Permission::read(Role::user($userId)), + Permission::delete(Role::user($userId)), + ] + ]); + + // Creating one to one relationship from collection 1 to colletion 2 + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/attributes/relationship', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'relatedCollectionId' => $collection2['body']['$id'], + 'type' => 'oneToOne', + 'twoWay' => false, + 'onDelete' => 'setNull', + 'key' => $collection2['body']['$id'] + ]); + + // Creating one to one relationship from collection 2 to colletion 3 + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/attributes/relationship', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'relatedCollectionId' => $collection3['body']['$id'], + 'type' => 'oneToOne', + 'twoWay' => false, + 'onDelete' => 'setNull', + 'key' => $collection3['body']['$id'] + ]); + + // Creating one to one relationship from collection 3 to colletion 4 + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection3['body']['$id'] . '/attributes/relationship', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'relatedCollectionId' => $collection4['body']['$id'], + 'type' => 'oneToOne', + 'twoWay' => false, + 'onDelete' => 'setNull', + 'key' => $collection4['body']['$id'] + ]); + + // Creating one to one relationship from collection 4 to colletion 5 + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection4['body']['$id'] . '/attributes/relationship', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'relatedCollectionId' => $collection5['body']['$id'], + 'type' => 'oneToOne', + 'twoWay' => false, + 'onDelete' => 'setNull', + 'key' => $collection5['body']['$id'] + ]); + + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/attributes/string', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => "Title", + 'size' => 100, + 'required' => false, + 'array' => false, + 'default' => null, + ]); + + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/attributes/string', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => "Rating", + 'size' => 100, + 'required' => false, + 'array' => false, + 'default' => null, + ]); + + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection3['body']['$id'] . '/attributes/string', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => "Rating", + 'size' => 100, + 'required' => false, + 'array' => false, + 'default' => null, + ]); + + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection4['body']['$id'] . '/attributes/string', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => "Rating", + 'size' => 100, + 'required' => false, + 'array' => false, + 'default' => null, + ]); + + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection5['body']['$id'] . '/attributes/string', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => "Rating", + 'size' => 100, + 'required' => false, + 'array' => false, + 'default' => null, + ]); + + \sleep(2); + // Creating parent document with a child reference to test the permissions + $parentDocument = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'documentId' => ID::custom($collection1['body']['$id']), + 'data' => [ + 'Title' => 'Captain America', + $collection2['body']['$id'] => [ + '$id' => ID::custom($collection2['body']['$id']), + 'Rating' => '10', + $collection3['body']['$id'] => [ + '$id' => ID::custom($collection3['body']['$id']), + 'Rating' => '10', + $collection4['body']['$id'] => [ + '$id' => ID::custom($collection4['body']['$id']), + 'Rating' => '10', + $collection5['body']['$id'] => [ + '$id' => ID::custom($collection5['body']['$id']), + 'Rating' => '10' + ] + ] + ] + ] + ] + ]); + + $this->assertEquals(201, $parentDocument['headers']['status-code']); + // This is the point of the test. We should not need any authorization permission to update the document with same data. + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documentId' => ID::custom($collection1['body']['$id']), + 'data' => [ + 'Title' => 'Captain America', + $collection2['body']['$id'] => [ + '$id' => $collection2['body']['$id'], + 'Rating' => '10', + $collection3['body']['$id'] => [ + '$id' => $collection3['body']['$id'], + 'Rating' => '10', + $collection4['body']['$id'] => [ + '$id' => $collection4['body']['$id'], + 'Rating' => '10', + $collection5['body']['$id'] => [ + '$id' => $collection5['body']['$id'], + 'Rating' => '10' + ] + ] + ] + ] + ] + ]); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($parentDocument['body'], $response['body']); + + // Giving update permission of collection 3 to user. + $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/collection3', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::custom('collection3'), + 'name' => ID::custom('collection3'), + 'documentSecurity' => false, + 'permissions' => [ + Permission::create(Role::user($userId)), + Permission::read(Role::user($userId)), + Permission::update(Role::user($userId)), + Permission::delete(Role::user($userId)), + ] + ]); + + // This is the point of this test. We should be allowed to do this action, and it should not fail on permission check + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'Title' => 'Captain America', + $collection2['body']['$id'] => [ + '$id' => ID::custom($collection2['body']['$id']), + 'Rating' => '10', + $collection3['body']['$id'] => [ + '$id' => ID::custom($collection3['body']['$id']), + 'Rating' => '11', + $collection4['body']['$id'] => [ + '$id' => ID::custom($collection4['body']['$id']), + 'Rating' => '10', + $collection5['body']['$id'] => [ + '$id' => ID::custom($collection5['body']['$id']), + 'Rating' => '11' + ] + ] + ] + ] + ] + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(11, $response['body'][$collection2['body']['$id']]['collection3']['Rating']); + + // We should not be allowed to update the document as we do not have permission for collection 2. + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'Title' => 'Captain America', + $collection2['body']['$id'] => [ + '$id' => ID::custom($collection2['body']['$id']), + 'Rating' => '11', + $collection3['body']['$id'] => null, + ] + ] + ]); + + $this->assertEquals(401, $response['headers']['status-code']); + + // We should not be allowed to update the document as we do not have permission for collection 2. + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/documents/' . $collection2['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'Rating' => '11', + ] + ]); + + $this->assertEquals(401, $response['headers']['status-code']); + + // Removing update permission from collection 3. + $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/collection3', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::custom('collection3'), + 'name' => ID::custom('collection3'), + 'documentSecurity' => false, + 'permissions' => [ + Permission::create(Role::user($userId)), + Permission::read(Role::user($userId)), + Permission::delete(Role::user($userId)), + ] + ]); + + // Giving update permission to collection 2. + $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/collection2', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::custom('collection2'), + 'name' => ID::custom('collection2'), + 'documentSecurity' => false, + 'permissions' => [ + Permission::create(Role::user($userId)), + Permission::update(Role::user($userId)), + Permission::read(Role::user($userId)), + Permission::delete(Role::user($userId)), + ] + ]); + + // Creating collection 3 new document + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection3['body']['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'documentId' => ID::custom('collection3Doc1'), + 'data' => [ + 'Rating' => '20' + ] + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + + // We should be allowed to link a new document from collection 3 to collection 2. + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'Title' => 'Captain America', + $collection2['body']['$id'] => [ + '$id' => ID::custom($collection2['body']['$id']), + $collection3['body']['$id'] => 'collection3Doc1', + ] + ] + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + + // We should be allowed to link and create a new document from collection 3 to collection 2. + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/documents/' . $collection1['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'Title' => 'Captain America', + $collection2['body']['$id'] => [ + '$id' => ID::custom($collection2['body']['$id']), + $collection3['body']['$id'] => [ + '$id' => ID::custom('collection3Doc2') + ], + ] + ] + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + } } diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index 5e734fbcb2..648a4de800 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -593,6 +593,110 @@ class DatabasesCustomServerTest extends Scope $this->assertFalse($collection['body']['enabled']); } + /** + * @depends testListCollections + */ + public function testCreateEncryptedAttribute(array $data): void + { + + $databaseId = $data['databaseId']; + + /** + * Test for SUCCESS + */ + + // Create collection + $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::unique(), + 'name' => 'Encrypted Actors Data', + 'permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'documentSecurity' => true, + ]); + + $this->assertEquals(201, $actors['headers']['status-code']); + $this->assertEquals($actors['body']['name'], 'Encrypted Actors Data'); + + /** + * Test for creating encrypted attributes + */ + + $attributesPath = '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes'; + + $firstName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'firstName', + 'size' => 256, + 'required' => true, + ]); + + $lastName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'lastName', + 'size' => 256, + 'required' => true, + 'encrypt' => true, + ]); + + + /** + * Check status of every attribute + */ + $this->assertEquals(202, $firstName['headers']['status-code']); + $this->assertEquals('firstName', $firstName['body']['key']); + $this->assertEquals('string', $firstName['body']['type']); + + $this->assertEquals(202, $lastName['headers']['status-code']); + $this->assertEquals('lastName', $lastName['body']['key']); + $this->assertEquals('string', $lastName['body']['type']); + + // Wait for database worker to finish creating attributes + sleep(2); + + // Creating document to ensure cache is purged on schema change + $document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'documentId' => ID::unique(), + 'data' => [ + 'firstName' => 'Jonah', + 'lastName' => 'Jameson', + ], + 'permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + ]); + + // Check document to ensure cache is purged on schema change + $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents/' . $document['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ])); + + $this->assertEquals(200, $document['headers']['status-code']); + $this->assertEquals('Jonah', $document['body']['firstName']); + $this->assertEquals('Jameson', $document['body']['lastName']); + } + public function testDeleteAttribute(): array { $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php index dcbf3e4bff..8377b9c803 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php @@ -176,7 +176,7 @@ class DatabasesPermissionsTeamTest extends Scope if ($success) { $this->assertCount(1, $documents['body']['documents']); } else { - $this->assertEquals(404, $documents['headers']['status-code']); + $this->assertEquals(401, $documents['headers']['status-code']); } } diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php index e28bdd233f..b458a4316b 100644 --- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php @@ -24,6 +24,7 @@ class FunctionsConsoleClientTest extends Scope 'name' => 'Test', 'execute' => [Role::user($this->getUser()['$id'])->toString()], 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'events' => [ 'users.*.create', 'users.*.delete', @@ -41,7 +42,8 @@ class FunctionsConsoleClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test Failure', 'execute' => ['some-random-string'], - 'runtime' => 'php-8.0' + 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', ]); $this->assertEquals(400, $response['headers']['status-code']); @@ -54,7 +56,7 @@ class FunctionsConsoleClientTest extends Scope /** * @depends testCreateFunction */ - public function testGetFunctionUsage(array $data) + public function testGetCollectionUsage(array $data) { /** * Test for FAILURE @@ -90,15 +92,16 @@ class FunctionsConsoleClientTest extends Scope ]); $this->assertEquals($response['headers']['status-code'], 200); - $this->assertEquals(count($response['body']), 8); + $this->assertEquals(count($response['body']), 9); $this->assertEquals($response['body']['range'], '24h'); - $this->assertIsArray($response['body']['deployments']); - $this->assertIsArray($response['body']['deploymentsStorage']); - $this->assertIsArray($response['body']['builds']); - $this->assertIsArray($response['body']['buildsStorage']); - $this->assertIsArray($response['body']['buildsCompute']); - $this->assertIsArray($response['body']['executions']); - $this->assertIsArray($response['body']['executionsCompute']); + $this->assertIsArray($response['body']['executionsTotal']); + $this->assertIsArray($response['body']['executionsFailure']); + $this->assertIsArray($response['body']['executionsSuccess']); + $this->assertIsArray($response['body']['executionsTime']); + $this->assertIsArray($response['body']['buildsTotal']); + $this->assertIsArray($response['body']['buildsFailure']); + $this->assertIsArray($response['body']['buildsSuccess']); + $this->assertIsArray($response['body']['buildsTime']); } /** diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php index 713814e17f..c49608222d 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php @@ -54,6 +54,7 @@ class FunctionsCustomClientTest extends Scope 'name' => 'Test', 'execute' => [Role::user($this->getUser()['$id'])->toString()], 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'events' => [ 'users.*.create', 'users.*.delete', @@ -114,8 +115,25 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); - // Wait for deployment to be built. - sleep(20); + // Poll until deployment is built + while (true) { + $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + if ( + $deployment['headers']['status-code'] >= 400 + || \in_array($deployment['body']['status'], ['ready', 'failed']) + ) { + break; + } + + \sleep(1); + } + + $this->assertEquals('ready', $deployment['body']['status']); $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [ 'content-type' => 'application/json', @@ -172,6 +190,7 @@ class FunctionsCustomClientTest extends Scope 'name' => 'Test', 'execute' => [Role::any()->toString()], 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'timeout' => 10, ]); @@ -227,10 +246,25 @@ class FunctionsCustomClientTest extends Scope $deploymentId = $deployment['body']['$id'] ?? ''; - // Wait for deployment to be built. - sleep(20); + // Poll until deployment is built + while (true) { + $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); - $this->assertEquals(202, $deployment['headers']['status-code']); + if ( + $deployment['headers']['status-code'] >= 400 + || \in_array($deployment['body']['status'], ['ready', 'failed']) + ) { + break; + } + + \sleep(1); + } + + $this->assertEquals('ready', $deployment['body']['status']); $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [ 'content-type' => 'application/json', @@ -244,25 +278,14 @@ class FunctionsCustomClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ - 'data' => 'foobar', - 'async' => true + 'body' => 'foobar', + 'async' => false ]); - $this->assertEquals(202, $execution['headers']['status-code']); - - $executionId = $execution['body']['$id'] ?? ''; - - sleep(20); - - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $projectId, - 'x-appwrite-key' => $apikey, - ]); - - $output = json_decode($executions['body']['response'], true); - $this->assertEquals(200, $executions['headers']['status-code']); - $this->assertEquals('completed', $executions['body']['status']); + $output = json_decode($execution['body']['responseBody'], true); + $this->assertEquals(201, $execution['headers']['status-code']); + $this->assertEquals(200, $execution['body']['responseStatusCode']); + $this->assertEquals('completed', $execution['body']['status']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); $this->assertEquals('Test', $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); @@ -270,12 +293,35 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); $this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT_DATA']); $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']); + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getHeaders()), [ + 'body' => 'foobar', + 'async' => true + ]); + + $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']); + return [ 'functionId' => $functionId ]; @@ -298,6 +344,7 @@ class FunctionsCustomClientTest extends Scope 'name' => 'Test', 'execute' => [Role::any()->toString()], 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'vars' => [ 'funcKey1' => 'funcValue1', 'funcKey2' => 'funcValue2', @@ -326,10 +373,25 @@ class FunctionsCustomClientTest extends Scope $deploymentId = $deployment['body']['$id'] ?? ''; - // Wait for deployment to be built. - sleep(20); + // Poll until deployment is built + while (true) { + $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); - $this->assertEquals(202, $deployment['headers']['status-code']); + if ( + $deployment['headers']['status-code'] >= 400 + || \in_array($deployment['body']['status'], ['ready', 'failed']) + ) { + break; + } + + \sleep(1); + } + + $this->assertEquals('ready', $deployment['body']['status']); // Why do we have to do this? $function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [ @@ -362,6 +424,7 @@ class FunctionsCustomClientTest extends Scope 'name' => 'Test', 'execute' => [], 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'timeout' => 10, ]); @@ -390,13 +453,10 @@ class FunctionsCustomClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ - 'data' => 'foobar', - 'async' => true + 'data' => 'foobar' ]); - $this->assertEquals(202, $execution['headers']['status-code']); - - sleep(20); + $this->assertEquals(201, $execution['headers']['status-code']); $base = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', @@ -405,7 +465,7 @@ class FunctionsCustomClientTest extends Scope ]); $this->assertEquals(200, $base['headers']['status-code']); - $this->assertCount(2, $base['body']['executions']); + $this->assertCount(3, $base['body']['executions']); $this->assertEquals('completed', $base['body']['executions'][0]['status']); $this->assertEquals('completed', $base['body']['executions'][1]['status']); @@ -429,7 +489,7 @@ class FunctionsCustomClientTest extends Scope ]); $this->assertEquals(200, $executions['headers']['status-code']); - $this->assertCount(1, $executions['body']['executions']); + $this->assertCount(2, $executions['body']['executions']); $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', @@ -440,7 +500,7 @@ class FunctionsCustomClientTest extends Scope ]); $this->assertEquals(200, $executions['headers']['status-code']); - $this->assertCount(2, $executions['body']['executions']); + $this->assertCount(3, $executions['body']['executions']); $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [ 'content-type' => 'application/json', @@ -461,7 +521,7 @@ class FunctionsCustomClientTest extends Scope 'queries' => [ 'cursorAfter("' . $base['body']['executions'][0]['$id'] . '")' ], ]); - $this->assertCount(1, $executions['body']['executions']); + $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', [ @@ -500,6 +560,7 @@ class FunctionsCustomClientTest extends Scope 'name' => 'Test', 'execute' => [Role::any()->toString()], 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'timeout' => 10, ]); @@ -557,14 +618,31 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); - // Wait for deployment to be built. - sleep(20); + // Poll until deployment is built + while (true) { + $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + if ( + $deployment['headers']['status-code'] >= 400 + || \in_array($deployment['body']['status'], ['ready', 'failed']) + ) { + break; + } + + \sleep(1); + } + + $this->assertEquals('ready', $deployment['body']['status']); $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']); @@ -572,13 +650,14 @@ class FunctionsCustomClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ - 'data' => 'foobar', + 'body' => 'foobar', // Testing default value, should be 'async' => false ]); - $output = json_decode($execution['body']['response'], true); + $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']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); $this->assertEquals('Test', $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); @@ -586,14 +665,13 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); $this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT_DATA']); $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']); // Client should never see logs and errors - $this->assertEmpty($execution['body']['stdout']); - $this->assertEmpty($execution['body']['stderr']); + $this->assertEmpty($execution['body']['logs']); + $this->assertEmpty($execution['body']['errors']); // Cleanup : Delete function $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index ab931f14e4..052c3ca936 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -30,6 +30,7 @@ class FunctionsCustomServerTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'events' => [ 'users.*.create', 'users.*.delete', @@ -188,6 +189,7 @@ class FunctionsCustomServerTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test 2', 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'events' => [ 'users.*.create', 'users.*.delete', @@ -322,7 +324,9 @@ class FunctionsCustomServerTest extends Scope 'users.*.update.email', ], 'schedule' => '0 0 1 1 *', - 'timeout' => 5, + 'timeout' => 15, + 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', ]); $this->assertEquals(200, $response1['headers']['status-code']); @@ -337,7 +341,7 @@ class FunctionsCustomServerTest extends Scope 'users.*.update.email', ], $response1['body']['events']); $this->assertEquals('0 0 1 1 *', $response1['body']['schedule']); - $this->assertEquals(5, $response1['body']['timeout']); + $this->assertEquals(15, $response1['body']['timeout']); /** * Test for FAILURE @@ -362,7 +366,6 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'entrypoint' => 'index.php', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), 'activate' => true ]); @@ -374,8 +377,26 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt'])); $this->assertEquals('index.php', $deployment['body']['entrypoint']); - // Wait for deployment to build. - sleep(60); + // Poll until deployment is built + 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'], + ]); + + if ( + $deployment['headers']['status-code'] >= 400 + || \in_array($deployment['body']['status'], ['ready', 'failed']) + ) { + break; + } + + \sleep(1); + } + + $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertEquals('ready', $deployment['body']['status']); return array_merge($data, ['deploymentId' => $deploymentId]); } @@ -572,10 +593,9 @@ class FunctionsCustomServerTest extends Scope ], $this->getHeaders())); $this->assertEquals(200, $function['headers']['status-code']); - $this->assertEquals(0, $function['body']['buildTime']); + $this->assertGreaterThan(0, $function['body']['buildTime']); $this->assertNotEmpty($function['body']['status']); - $this->assertNotEmpty($function['body']['buildStdout']); - $this->assertArrayHasKey('buildStderr', $function['body']); + $this->assertNotEmpty($function['body']['buildLogs']); /** * Test for FAILURE @@ -602,50 +622,28 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'async' => true, + 'async' => false, ]); $executionId = $execution['body']['$id'] ?? ''; - $this->assertEquals(202, $execution['headers']['status-code']); - $this->assertNotEmpty($execution['body']['$id']); - $this->assertNotEmpty($execution['body']['functionId']); - $this->assertEquals(true, (new DatetimeValidator())->isValid($execution['body']['$createdAt'])); - $this->assertEquals($data['functionId'], $execution['body']['functionId']); - $this->assertEquals('waiting', $execution['body']['status']); - $this->assertEquals(0, $execution['body']['statusCode']); - $this->assertEquals('', $execution['body']['response']); - $this->assertEquals('', $execution['body']['stderr']); - $this->assertEquals(0, $execution['body']['duration']); - - sleep(10); - - $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/' . $executionId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - + $this->assertEquals(201, $execution['headers']['status-code']); $this->assertNotEmpty($execution['body']['$id']); $this->assertNotEmpty($execution['body']['functionId']); $this->assertEquals(true, (new DatetimeValidator())->isValid($execution['body']['$createdAt'])); $this->assertEquals($data['functionId'], $execution['body']['functionId']); $this->assertEquals('completed', $execution['body']['status']); - $this->assertEquals(200, $execution['body']['statusCode']); - $this->assertStringContainsString($execution['body']['functionId'], $execution['body']['response']); - $this->assertStringContainsString($data['deploymentId'], $execution['body']['response']); - $this->assertStringContainsString('Test1', $execution['body']['response']); - $this->assertStringContainsString('http', $execution['body']['response']); - $this->assertStringContainsString('PHP', $execution['body']['response']); - $this->assertStringContainsString('8.0', $execution['body']['response']); - $this->assertStringContainsString('êä', $execution['body']['response']); // tests unknown utf-8 chars - $this->assertEquals('', $execution['body']['stderr']); - $this->assertLessThan(3, $execution['body']['duration']); - - /** - * Test for FAILURE - */ - - sleep(20); + $this->assertEquals(200, $execution['body']['responseStatusCode']); + $this->assertStringContainsString($execution['body']['functionId'], $execution['body']['responseBody']); + $this->assertStringContainsString($data['deploymentId'], $execution['body']['responseBody']); + $this->assertStringContainsString('Test1', $execution['body']['responseBody']); + $this->assertStringContainsString('http', $execution['body']['responseBody']); + $this->assertStringContainsString('PHP', $execution['body']['responseBody']); + $this->assertStringContainsString('8.0', $execution['body']['responseBody']); + // $this->assertStringContainsString('êä', $execution['body']['responseBody']); // tests unknown utf-8 chars + $this->assertEquals('', $execution['body']['errors']); + $this->assertEquals('', $execution['body']['logs']); + $this->assertLessThan(10, $execution['body']['duration']); return array_merge($data, ['executionId' => $executionId]); } @@ -749,13 +747,13 @@ class FunctionsCustomServerTest extends Scope ]); $this->assertEquals(201, $execution['headers']['status-code']); - $this->assertEquals('completed', $execution['body']['status']); - $this->assertStringContainsString('Test1', $execution['body']['response']); - $this->assertStringContainsString('http', $execution['body']['response']); - $this->assertStringContainsString('PHP', $execution['body']['response']); - $this->assertStringContainsString('8.0', $execution['body']['response']); - $this->assertStringContainsString('êä', $execution['body']['response']); // tests unknown utf-8 chars + $this->assertEquals(200, $execution['body']['responseStatusCode']); + $this->assertStringContainsString('Test1', $execution['body']['responseBody']); + $this->assertStringContainsString('http', $execution['body']['responseBody']); + $this->assertStringContainsString('PHP', $execution['body']['responseBody']); + $this->assertStringContainsString('8.0', $execution['body']['responseBody']); + // $this->assertStringContainsString('êä', $execution['body']['response']); // tests unknown utf-8 chars $this->assertLessThan(1.500, $execution['body']['duration']); return $data; @@ -854,7 +852,7 @@ class FunctionsCustomServerTest extends Scope { $name = 'php-8.0'; $entrypoint = 'index.php'; - $timeout = 2; + $timeout = 15; $folder = 'timeout'; $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); @@ -866,6 +864,7 @@ class FunctionsCustomServerTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test ' . $name, 'runtime' => $name, + 'entrypoint' => $entrypoint, 'events' => [], 'timeout' => $timeout, ]); @@ -883,10 +882,29 @@ class FunctionsCustomServerTest extends Scope 'activate' => true, ]); + $deploymentId = $deployment['body']['$id'] ?? ''; + $this->assertEquals(202, $deployment['headers']['status-code']); - // Allow build step to run - sleep(40); + // Poll until deployment is built + while (true) { + $deployment = $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'], + ]); + + if ( + $deployment['headers']['status-code'] >= 400 + || \in_array($deployment['body']['status'], ['ready', 'failed']) + ) { + break; + } + + \sleep(1); + } + + $this->assertEquals('ready', $deployment['body']['status']); $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ 'content-type' => 'application/json', @@ -913,11 +931,12 @@ class FunctionsCustomServerTest extends Scope $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]['statusCode'], 500); + $this->assertEquals($executions['body']['executions'][0]['responseStatusCode'], 500); $this->assertGreaterThan(2, $executions['body']['executions'][0]['duration']); - $this->assertLessThan(6, $executions['body']['executions'][0]['duration']); - $this->assertEquals($executions['body']['executions'][0]['response'], ''); - $this->assertEquals($executions['body']['executions'][0]['stderr'], 'An internal curl error has occurred within the executor! Error Msg: Operation timed out'); + $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']); // Cleanup : Delete function $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ @@ -930,14 +949,33 @@ class FunctionsCustomServerTest extends Scope } /** + * + * @return array + */ + public function provideCustomExecutions(): array + { + return [ + [ 'folder' => 'php-fn', 'name' => 'php-8.0', 'entrypoint' => 'index.php', 'runtimeName' => 'PHP', 'runtimeVersion' => '8.0' ], + [ 'folder' => 'node', 'name' => 'node-18.0', 'entrypoint' => 'index.js', 'runtimeName' => 'Node.js', 'runtimeVersion' => '18.0' ], + [ 'folder' => 'python', 'name' => 'python-3.9', 'entrypoint' => 'main.py', 'runtimeName' => 'Python', 'runtimeVersion' => '3.9' ], + [ 'folder' => 'ruby', 'name' => 'ruby-3.1', 'entrypoint' => 'main.rb', 'runtimeName' => 'Ruby', 'runtimeVersion' => '3.1' ], + // Swift and Dart disabled as it's very slow. + // [ 'folder' => 'dart', 'name' => 'dart-2.15', 'entrypoint' => 'main.dart', 'runtimeName' => 'Dart', 'runtimeVersion' => '2.15' ], + // [ 'folder' => 'swift', 'name' => 'swift-5.5', 'entrypoint' => 'index.swift', 'runtimeName' => 'Swift', 'runtimeVersion' => '5.5' ], + ]; + } + + /** + * @param string $folder + * @param string $name + * @param string $entrypoint + * + * @dataProvider provideCustomExecutions * @depends testTimeout */ - public function testCreateCustomPHPExecution() + public function testCreateCustomExecution(string $folder, string $name, string $entrypoint, string $runtimeName, string $runtimeVersion) { - $name = 'php-8.0'; - $entrypoint = 'index.php'; $timeout = 2; - $folder = 'php-fn'; $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; $this->packageCode($folder); @@ -948,6 +986,7 @@ class FunctionsCustomServerTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test ' . $name, 'runtime' => $name, + 'entrypoint' => $entrypoint, 'events' => [], 'timeout' => $timeout, ]); @@ -956,6 +995,16 @@ class FunctionsCustomServerTest extends Scope $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()), [ + 'key' => 'CUSTOM_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'], @@ -968,8 +1017,23 @@ class FunctionsCustomServerTest extends Scope $deploymentId = $deployment['body']['$id'] ?? ''; $this->assertEquals(202, $deployment['headers']['status-code']); - // Allow build step to run - sleep(20); + // Poll until deployment is built + while (true) { + $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + if ( + $deployment['headers']['status-code'] >= 400 + || \in_array($deployment['body']['status'], ['ready', 'failed']) + ) { + break; + } + + \sleep(1); + } $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([ 'content-type' => 'application/json', @@ -982,266 +1046,30 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'data' => 'foobar', - 'async' => true + 'body' => 'foobar', + 'async' => false ]); $executionId = $execution['body']['$id'] ?? ''; + $output = json_decode($execution['body']['responseBody'], true); - $this->assertEquals(202, $execution['headers']['status-code']); - - $executionId = $execution['body']['$id'] ?? ''; - - sleep(20); - - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $output = json_decode($executions['body']['response'], true); - - $this->assertEquals(200, $executions['headers']['status-code']); - $this->assertEquals('completed', $executions['body']['status']); + $this->assertEquals(201, $execution['headers']['status-code']); + $this->assertEquals('completed', $execution['body']['status']); + $this->assertEquals(200, $execution['body']['responseStatusCode']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); - $this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); - $this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); + $this->assertEquals($runtimeName, $output['APPWRITE_FUNCTION_RUNTIME_NAME']); + $this->assertEquals($runtimeVersion, $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT_DATA']); - $this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_USER_ID']); - $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); - $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); - $this->assertStringContainsString('Amazing Function Log', $executions['body']['stdout']); - - $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($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->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); - - // 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 testCreateCustomNodeExecution() - { - $name = 'node-18.0'; - $folder = 'node'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; - $this->packageCode($folder); - - $entrypoint = 'index.js'; - $timeout = 2; - - $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'functionId' => ID::unique(), - 'name' => 'Test ' . $name, - 'runtime' => $name, - 'events' => [], - 'timeout' => $timeout, - ]); - - $functionId = $function['body']['$id'] ?? ''; - - $this->assertEquals(201, $function['headers']['status-code']); - - // Create variable - $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'key' => 'CUSTOM_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()), [ - 'entrypoint' => $entrypoint, - 'code' => new CURLFile($code, 'application/x-gzip', basename($code)), - 'activate' => true, - ]); - - $deploymentId = $deployment['body']['$id'] ?? ''; - $this->assertEquals(202, $deployment['headers']['status-code']); - - // Allow build step to run - sleep(20); - - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => 'foobar', - 'async' => true - ]); - - $executionId = $execution['body']['$id'] ?? ''; - - $this->assertEquals(202, $execution['headers']['status-code']); - - $executionId = $execution['body']['$id'] ?? ''; - - sleep(20); - - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $output = json_decode($executions['body']['response'], true); - - $this->assertEquals(200, $executions['headers']['status-code']); - $this->assertEquals('completed', $executions['body']['status']); - $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); - $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); - $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); - $this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); - $this->assertEquals('18.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT_DATA']); - $this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_USER_ID']); - $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); - $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_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->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->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); - - // 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 testCreateCustomPythonExecution() - { - $name = 'python-3.9'; - $folder = 'python'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; - $this->packageCode($folder); - - $entrypoint = 'main.py'; - $timeout = 2; - - $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'functionId' => ID::unique(), - 'name' => 'Test ' . $name, - 'runtime' => $name, - 'events' => [], - 'timeout' => $timeout, - ]); - - $functionId = $function['body']['$id'] ?? ''; - - $this->assertEquals(201, $function['headers']['status-code']); - - /** 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()), [ - 'key' => 'CUSTOM_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()), [ - 'entrypoint' => $entrypoint, - 'code' => new CURLFile($code, 'application/x-gzip', basename($code)), - 'activate' => true, - ]); - - $deploymentId = $deployment['body']['$id'] ?? ''; - $this->assertEquals(202, $deployment['headers']['status-code']); - - // Allow build step to run - sleep(60); - - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => 'foobar', - 'async' => true - ]); - - $executionId = $execution['body']['$id'] ?? ''; - - $this->assertEquals(202, $execution['headers']['status-code']); - - $executionId = $execution['body']['$id'] ?? ''; - - sleep(60); - - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $output = json_decode($executions['body']['response'], true); - - $this->assertEquals(200, $executions['headers']['status-code']); - $this->assertEquals('completed', $executions['body']['status']); - $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); - $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); - $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); - $this->assertEquals('Python', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); - $this->assertEquals('3.9', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT_DATA']); $this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']); $this->assertEquals('variable', $output['CUSTOM_VARIABLE']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_USER_ID']); + $this->assertEmpty($output['APPWRITE_FUNCTION_USER_ID']); $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); + $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', @@ -1254,7 +1082,7 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(1, $executions['body']['executions']); $this->assertEquals($executions['body']['executions'][0]['$id'], $executionId); $this->assertEquals($executions['body']['executions'][0]['trigger'], 'http'); - $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); + $this->assertStringContainsString('Amazing Function Log', $executions['body']['executions'][0]['logs']); // Cleanup : Delete function $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ @@ -1266,336 +1094,6 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } - // public function testCreateCustomDartExecution() - // { - // $name = 'dart-2.15'; - // $folder = 'dart'; - // $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; - // $this->packageCode($folder); - - // $entrypoint = 'main.dart'; - // $timeout = 2; - - // $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // ], $this->getHeaders()), [ - // 'functionId' => ID::unique(), - // 'name' => 'Test ' . $name, - // 'runtime' => $name, - // 'events' => [], - // 'timeout' => $timeout, - // ]); - - // $functionId = $function['body']['$id'] ?? ''; - - // $this->assertEquals(201, $function['headers']['status-code']); - - // /** 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()), [ - // 'key' => 'CUSTOM_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()), [ - // 'entrypoint' => $entrypoint, - // 'code' => new CURLFile($code, 'application/x-gzip', basename($code)), - // 'activate' => true, - // ]); - - // $deploymentId = $deployment['body']['$id'] ?? ''; - // $this->assertEquals(202, $deployment['headers']['status-code']); - - // // Allow build step to run - // sleep(80); - - // $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // ], $this->getHeaders()), [ - // 'data' => 'foobar', - // 'async' => true - // ]); - - // $executionId = $execution['body']['$id'] ?? ''; - - // $this->assertEquals(202, $execution['headers']['status-code']); - - // $executionId = $execution['body']['$id'] ?? ''; - - // sleep(20); - - // $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // ], $this->getHeaders())); - - // $output = json_decode($executions['body']['response'], true); - - // $this->assertEquals(200, $executions['headers']['status-code']); - // $this->assertEquals('completed', $executions['body']['status']); - // $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - // $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); - // $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); - // $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); - // $this->assertEquals('Dart', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); - // $this->assertEquals('2.15', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); - // $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); - // $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT_DATA']); - // $this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']); - // $this->assertEquals('', $output['APPWRITE_FUNCTION_USER_ID']); - // $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); - // $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_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->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->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); - - // // 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']); - // } - - #[Retry(count: 1)] - public function testCreateCustomRubyExecution() - { - $name = 'ruby-3.1'; - $folder = 'ruby'; - $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; - $this->packageCode($folder); - - $entrypoint = 'main.rb'; - $timeout = 2; - - $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'functionId' => ID::unique(), - 'name' => 'Test ' . $name, - 'runtime' => $name, - 'events' => [], - 'timeout' => $timeout, - ]); - - $functionId = $function['body']['$id'] ?? ''; - - $this->assertEquals(201, $function['headers']['status-code']); - - /** 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()), [ - 'key' => 'CUSTOM_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()), [ - 'entrypoint' => $entrypoint, - 'code' => new CURLFile($code, 'application/x-gzip', basename($code)), - 'activate' => true, - ]); - - $deploymentId = $deployment['body']['$id'] ?? ''; - $this->assertEquals(202, $deployment['headers']['status-code']); - - // Allow build step to run - sleep(60); - - $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => 'foobar', - 'async' => true - ]); - - $executionId = $execution['body']['$id'] ?? ''; - - $this->assertEquals(202, $execution['headers']['status-code']); - - $executionId = $execution['body']['$id'] ?? ''; - - sleep(20); - - $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $output = json_decode($executions['body']['response'], true); - - $this->assertEquals(200, $executions['headers']['status-code']); - $this->assertEquals('completed', $executions['body']['status']); - $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); - $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); - $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); - $this->assertEquals('Ruby', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); - $this->assertEquals('3.1', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT_DATA']); - $this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_USER_ID']); - $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); - $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_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->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->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); - - // 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 testCreateCustomSwiftExecution() - // { - // $name = 'swift-5.5'; - // $folder = 'swift'; - // $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz"; - // $this->packageCode($folder); - - // $entrypoint = 'index.swift'; - // $timeout = 5; - - // $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // ], $this->getHeaders()), [ - // 'functionId' => ID::unique(), - // 'name' => 'Test '.$name, - // 'runtime' => $name, - // 'vars' => [ - // 'CUSTOM_VARIABLE' => 'variable', - // ], - // 'events' => [], - // 'schedule' => '', - // 'timeout' => $timeout, - // ]); - - // $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()), [ - // 'entrypoint' => $entrypoint, - // 'code' => new CURLFile($code, 'application/x-gzip', basename($code)), - // 'activate' => true, - // ]); - - // $deploymentId = $deployment['body']['$id'] ?? ''; - // $this->assertEquals(202, $deployment['headers']['status-code']); - - // // Allow (slow) build step to run - // sleep(300); - - // $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // ], $this->getHeaders()), [ - // 'data' => 'foobar', - // ]); - - // $executionId = $execution['body']['$id'] ?? ''; - - // $this->assertEquals(202, $execution['headers']['status-code']); - - // $executionId = $execution['body']['$id'] ?? ''; - - // sleep(10); - - // $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([ - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // ], $this->getHeaders())); - - // $output = json_decode($executions['body']['response'], true); - - // $this->assertEquals(200, $executions['headers']['status-code']); - // $this->assertEquals('completed', $executions['body']['status']); - // $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - // $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']); - // $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); - // $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); - // $this->assertEquals('Swift', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); - // $this->assertEquals('5.5', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); - // $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); - // $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT_DATA']); - // $this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']); - // $this->assertEquals('variable', $output['CUSTOM_VARIABLE']); - // $this->assertEquals('', $output['APPWRITE_FUNCTION_USER_ID']); - // $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); - // $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_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->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->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']); - - // // 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 testGetRuntimes() { $runtimes = $this->client->call(Client::METHOD_GET, '/functions/runtimes', array_merge([ diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 124eec26f3..3a4b88e2c2 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -120,7 +120,7 @@ trait Base public static string $GET_TEAM_MEMBERSHIP = 'get_team_membership'; public static string $GET_TEAM_MEMBERSHIPS = 'list_team_memberships'; public static string $CREATE_TEAM_MEMBERSHIP = 'create_team_membership'; - public static string $UPDATE_TEAM_MEMBERSHIP_ROLES = 'update_team_membership_roles'; + public static string $UPDATE_TEAM_MEMBERSHIP = 'update_team_membership'; public static string $UPDATE_TEAM_MEMBERSHIP_STATUS = 'update_membership_status'; public static string $DELETE_TEAM_MEMBERSHIP = 'delete_team_membership'; @@ -1296,9 +1296,9 @@ trait Base roles } }'; - case self::$UPDATE_TEAM_MEMBERSHIP_ROLES: - return 'mutation updateTeamMembershipRoles($teamId: String!, $membershipId: String!, $roles: [String!]!){ - teamsUpdateMembershipRoles(teamId: $teamId, membershipId: $membershipId, roles: $roles) { + case self::$UPDATE_TEAM_MEMBERSHIP: + return 'mutation updateTeamMembership($teamId: String!, $membershipId: String!, $roles: [String!]!){ + teamsUpdateMembership(teamId: $teamId, membershipId: $membershipId, roles: $roles) { _id userId teamId @@ -1368,8 +1368,7 @@ trait Base total deployments { _id - buildStdout - buildStderr + buildLogs } } }'; @@ -1377,14 +1376,15 @@ trait Base return 'query getDeployment($functionId: String!, $deploymentId: String!) { functionsGetDeployment(functionId: $functionId, deploymentId: $deploymentId) { _id + resourceId buildId - buildStdout - buildStderr + buildLogs + status } }'; case self::$CREATE_FUNCTION: - return 'mutation createFunction($functionId: String!, $name: String!, $execute: [String!]!, $runtime: String! $events: [String], $schedule: String, $timeout: Int) { - functionsCreate(functionId: $functionId, name: $name, execute: $execute, runtime: $runtime, events: $events, schedule: $schedule, timeout: $timeout) { + return 'mutation createFunction($functionId: String!, $name: String!, $runtime: String!, $execute: [String!]!, $events: [String], $schedule: String, $timeout: Int, $entrypoint: String!) { + functionsCreate(functionId: $functionId, name: $name, execute: $execute, runtime: $runtime, events: $events, schedule: $schedule, timeout: $timeout, entrypoint: $entrypoint) { _id name runtime @@ -1392,8 +1392,8 @@ trait Base } }'; case self::$UPDATE_FUNCTION: - return 'mutation updateFunction($functionId: String!, $name: String!, $execute: [String!]!, $events: [String], $schedule: String, $timeout: Int) { - functionsUpdate(functionId: $functionId, name: $name, execute: $execute, events: $events, schedule: $schedule, timeout: $timeout) { + return 'mutation updateFunction($functionId: String!, $name: String!, $execute: [String!]!, $runtime: String!, $entrypoint: String!, $events: [String], $schedule: String, $timeout: Int) { + functionsUpdate(functionId: $functionId, name: $name, execute: $execute, runtime: $runtime, entrypoint: $entrypoint, events: $events, schedule: $schedule, timeout: $timeout) { _id name runtime @@ -1457,15 +1457,14 @@ trait Base } }'; case self::$CREATE_DEPLOYMENT: - return 'mutation createDeployment($functionId: String!, $entrypoint: String!, $code: InputFile!, $activate: Boolean!) { - functionsCreateDeployment(functionId: $functionId, entrypoint: $entrypoint, code: $code, activate: $activate) { + return 'mutation createDeployment($functionId: String!, $code: InputFile!, $activate: Boolean!) { + functionsCreateDeployment(functionId: $functionId, code: $code, activate: $activate) { _id buildId entrypoint size status - buildStdout - buildStderr + buildLogs } }'; case self::$DELETE_DEPLOYMENT: @@ -1478,8 +1477,10 @@ trait Base return 'query getExecution($functionId: String!$executionId: String!) { functionsGetExecution(functionId: $functionId, executionId: $executionId) { _id + functionId status - stderr + logs + errors } }'; case self::$GET_EXECUTIONS: @@ -1488,17 +1489,21 @@ trait Base total executions { _id + functionId status - stderr + logs + errors } } }'; case self::$CREATE_EXECUTION: - return 'mutation createExecution($functionId: String!, $data: String, $async: Boolean) { - functionsCreateExecution(functionId: $functionId, data: $data, async: $async) { + return 'mutation createExecution($functionId: String!, $body: String, $async: Boolean) { + functionsCreateExecution(functionId: $functionId, body: $body, async: $async) { _id + functionId status - stderr + logs + errors } }'; case self::$DELETE_EXECUTION: diff --git a/tests/e2e/Services/GraphQL/FunctionsClientTest.php b/tests/e2e/Services/GraphQL/FunctionsClientTest.php index d5b50250d4..363f7a0fb1 100644 --- a/tests/e2e/Services/GraphQL/FunctionsClientTest.php +++ b/tests/e2e/Services/GraphQL/FunctionsClientTest.php @@ -26,6 +26,7 @@ class FunctionsClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test Function', 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'execute' => [Role::any()->toString()], ] ]; @@ -36,7 +37,6 @@ class FunctionsClientTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'], ], $gqlPayload); - $this->assertIsArray($function['body']['data']); $this->assertArrayNotHasKey('errors', $function['body']); @@ -88,7 +88,6 @@ class FunctionsClientTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - 'entrypoint' => 'index.php', 'activate' => true, 'code' => null, ] @@ -108,9 +107,44 @@ class FunctionsClientTest extends Scope $this->assertIsArray($deployment['body']['data']); $this->assertArrayNotHasKey('errors', $deployment['body']); - sleep(15); + // Poll get deployment until an error, or status is either 'ready' or 'failed' + $deployment = $deployment['body']['data']['functionsCreateDeployment']; + $deploymentId = $deployment['_id']; - return $deployment['body']['data']['functionsCreateDeployment']; + $query = $this->getQuery(self::$GET_DEPLOYMENT); + $gqlPayload = [ + 'query' => $query, + 'variables' => [ + 'functionId' => $function['_id'], + 'deploymentId' => $deploymentId, + ] + ]; + + while (true) { + $deployment = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], $gqlPayload); + + $this->assertIsArray($deployment['body']['data']); + $this->assertArrayNotHasKey('errors', $deployment['body']); + + $deployment = $deployment['body']['data']['functionsGetDeployment']; + + if ( + $deployment['status'] === 'ready' + || $deployment['status'] === 'failed' + ) { + break; + } + + \sleep(1); + } + + $this->assertEquals('ready', $deployment['status']); + + return $deployment; } /** diff --git a/tests/e2e/Services/GraphQL/FunctionsServerTest.php b/tests/e2e/Services/GraphQL/FunctionsServerTest.php index 75aa0d5d04..49a8fd61f2 100644 --- a/tests/e2e/Services/GraphQL/FunctionsServerTest.php +++ b/tests/e2e/Services/GraphQL/FunctionsServerTest.php @@ -25,6 +25,7 @@ class FunctionsServerTest extends Scope 'variables' => [ 'functionId' => ID::unique(), 'name' => 'Test Function', + 'entrypoint' => 'index.php', 'runtime' => 'php-8.0', 'execute' => [Role::any()->toString()], ] @@ -86,7 +87,6 @@ class FunctionsServerTest extends Scope 'query' => $query, 'variables' => [ 'functionId' => $function['_id'], - 'entrypoint' => 'index.php', 'activate' => true, 'code' => null, ] @@ -105,26 +105,59 @@ class FunctionsServerTest extends Scope $this->assertIsArray($deployment['body']['data']); $this->assertArrayNotHasKey('errors', $deployment['body']); - sleep(15); + // Poll get deployment until an error, or status is either 'ready' or 'failed' + $deployment = $deployment['body']['data']['functionsCreateDeployment']; + $deploymentId = $deployment['_id']; - return $deployment['body']['data']['functionsCreateDeployment']; + $query = $this->getQuery(self::$GET_DEPLOYMENT); + $gqlPayload = [ + 'query' => $query, + 'variables' => [ + 'functionId' => $function['_id'], + 'deploymentId' => $deploymentId, + ] + ]; + + while (true) { + $deployment = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getHeaders()), $gqlPayload); + + $this->assertIsArray($deployment['body']['data']); + $this->assertArrayNotHasKey('errors', $deployment['body']); + + $deployment = $deployment['body']['data']['functionsGetDeployment']; + + if ( + $deployment['status'] === 'ready' + || $deployment['status'] === 'failed' + ) { + break; + } + + \sleep(1); + } + + $this->assertEquals('ready', $deployment['status']); + + return $deployment; } /** - * * @depends testCreateFunction * @depends testCreateDeployment - * @param $function + * @param $deployment * @return array * @throws \Exception */ - public function testCreateExecution($function): array + public function testCreateExecution($deployment): array { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_EXECUTION); $gqlPayload = [ 'query' => $query, 'variables' => [ - 'functionId' => $function['_id'], + 'functionId' => $deployment['resourceId'], ] ]; @@ -140,33 +173,31 @@ class FunctionsServerTest extends Scope } /** - * @depends testCreateFunction * @depends testGetDeployment - * @param $function * @param $deployment - * @return array + * @return void * @throws \Exception */ - public function testCreateRetryBuild($function, $deployment): void + public function testCreateRetryBuild($deployment): void { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$RETRY_BUILD); $gqlPayload = [ 'query' => $query, 'variables' => [ - 'functionId' => $function['_id'], + 'functionId' => $deployment['resourceId'], 'deploymentId' => $deployment['_id'], 'buildId' => $deployment['buildId'], ] ]; - $retryBuild = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), $gqlPayload); - $this->assertIsArray($retryBuild['body']['errors']); - $this->assertEquals("Build not failed", $retryBuild['body']['errors'][0]['message']); + $this->assertIsNotArray($response['body']); + $this->assertEquals(204, $response['headers']['status-code']); } public function testGetFunctions(): array @@ -272,20 +303,19 @@ class FunctionsServerTest extends Scope } /** - * @depends testCreateFunction * @depends testCreateDeployment - * @param $function + * @param $deployment * @return array * @throws \Exception */ - public function testGetDeployment($function, $deployment) + public function testGetDeployment($deployment) { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$GET_DEPLOYMENT); $gqlPayload = [ 'query' => $query, 'variables' => [ - 'functionId' => $function['_id'], + 'functionId' => $deployment['resourceId'], 'deploymentId' => $deployment['_id'], ] ]; @@ -334,21 +364,19 @@ class FunctionsServerTest extends Scope } /** - * @depends testCreateFunction * @depends testCreateExecution - * @param $function * @param $execution * @return array * @throws \Exception */ - public function testGetExecution($function, $execution): array + public function testGetExecution($execution): array { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$GET_EXECUTION); $gqlPayload = [ 'query' => $query, 'variables' => [ - 'functionId' => $function['_id'], + 'functionId' => $execution['functionId'], 'executionId' => $execution['_id'], ] ]; @@ -382,6 +410,8 @@ class FunctionsServerTest extends Scope 'functionId' => $function['_id'], 'name' => 'Test Function Updated', 'execute' => [Role::any()->toString()], + 'entrypoint' => 'index.php', + 'runtime' => 'php-8.0', 'vars' => [ 'name' => 'John Doe', 'age' => 42, @@ -403,20 +433,18 @@ class FunctionsServerTest extends Scope } /** - * @depends testCreateFunction * @depends testCreateDeployment - * @param $function * @param $deployment * @throws \Exception */ - public function testDeleteDeployment($function, $deployment): void + public function testDeleteDeployment($deployment): array { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$DELETE_DEPLOYMENT); $gqlPayload = [ 'query' => $query, 'variables' => [ - 'functionId' => $function['_id'], + 'functionId' => $deployment['resourceId'], 'deploymentId' => $deployment['_id'], ] ]; @@ -428,22 +456,23 @@ class FunctionsServerTest extends Scope $this->assertIsNotArray($response['body']); $this->assertEquals(204, $response['headers']['status-code']); + + return $deployment; } /** - * @depends testCreateFunction * @depends testDeleteDeployment - * @param $function + * @param $deployment * @throws \Exception */ - public function testDeleteFunction($function): void + public function testDeleteFunction($deployment): void { $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$DELETE_FUNCTION); $gqlPayload = [ 'query' => $query, 'variables' => [ - 'functionId' => $function['_id'], + 'functionId' => $deployment['resourceId'], ] ]; diff --git a/tests/e2e/Services/GraphQL/TeamsServerTest.php b/tests/e2e/Services/GraphQL/TeamsServerTest.php index 9654501fe4..33c7847113 100644 --- a/tests/e2e/Services/GraphQL/TeamsServerTest.php +++ b/tests/e2e/Services/GraphQL/TeamsServerTest.php @@ -251,7 +251,7 @@ class TeamsServerTest extends Scope public function testUpdateTeamMembershipRoles($team, $membership) { $projectId = $this->getProject()['$id']; - $query = $this->getQuery(self::$UPDATE_TEAM_MEMBERSHIP_ROLES); + $query = $this->getQuery(self::$UPDATE_TEAM_MEMBERSHIP); $graphQLPayload = [ 'query' => $query, 'variables' => [ @@ -268,7 +268,7 @@ class TeamsServerTest extends Scope $this->assertIsArray($membership['body']['data']); $this->assertArrayNotHasKey('errors', $membership['body']); - $membership = $membership['body']['data']['teamsUpdateMembershipRoles']; + $membership = $membership['body']['data']['teamsUpdateMembership']; $this->assertEquals(['developer', 'admin'], $membership['roles']); } diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 67c8ae2c6e..ff3f8e8e94 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -130,7 +130,6 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(409, $response['headers']['status-code']); $this->assertEquals(409, $response['body']['code']); $this->assertEquals(Exception::PROJECT_ALREADY_EXISTS, $response['body']['type']); - $this->assertEquals('Project with the requested ID already exists.', $response['body']['message']); } /** @group projectsCRUD */ @@ -446,7 +445,7 @@ class ProjectsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_GET, '/project/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/usage', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); @@ -455,14 +454,14 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(count($response['body']), 9); $this->assertNotEmpty($response['body']); $this->assertEquals('30d', $response['body']['range']); - $this->assertIsArray($response['body']['requestsTotal']); + $this->assertIsArray($response['body']['requests']); $this->assertIsArray($response['body']['network']); - $this->assertIsArray($response['body']['executionsTotal']); - $this->assertIsArray($response['body']['documentsTotal']); - $this->assertIsArray($response['body']['databasesTotal']); - $this->assertIsArray($response['body']['bucketsTotal']); - $this->assertIsArray($response['body']['usersTotal']); - $this->assertIsArray($response['body']['filesStorage']); + $this->assertIsArray($response['body']['executions']); + $this->assertIsArray($response['body']['documents']); + $this->assertIsArray($response['body']['databases']); + $this->assertIsArray($response['body']['buckets']); + $this->assertIsArray($response['body']['users']); + $this->assertIsArray($response['body']['storage']); /** * Test for FAILURE @@ -541,7 +540,8 @@ class ProjectsConsoleClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'enabled' => true, - 'sender' => 'mailer@appwrite.io', + 'senderEmail' => 'mailer@appwrite.io', + 'senderName' => 'Mailer', 'host' => 'maildev', 'port' => 1025, 'username' => 'user', @@ -550,7 +550,8 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertTrue($response['body']['smtpEnabled']); - $this->assertEquals('mailer@appwrite.io', $response['body']['smtpSender']); + $this->assertEquals('mailer@appwrite.io', $response['body']['smtpSenderEmail']); + $this->assertEquals('Mailer', $response['body']['smtpSenderName']); $this->assertEquals('maildev', $response['body']['smtpHost']); $this->assertEquals(1025, $response['body']['smtpPort']); $this->assertEquals('user', $response['body']['smtpUsername']); @@ -565,31 +566,21 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertTrue($response['body']['smtpEnabled']); - $this->assertEquals('mailer@appwrite.io', $response['body']['smtpSender']); + $this->assertEquals('mailer@appwrite.io', $response['body']['smtpSenderEmail']); + $this->assertEquals('Mailer', $response['body']['smtpSenderName']); $this->assertEquals('maildev', $response['body']['smtpHost']); $this->assertEquals(1025, $response['body']['smtpPort']); $this->assertEquals('user', $response['body']['smtpUsername']); $this->assertEquals('password', $response['body']['smtpPassword']); $this->assertEquals('', $response['body']['smtpSecure']); - /** Reset */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/smtp', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'enabled' => false, - 'sender' => 'mailer@appwrite.io', - 'host' => 'maildev', - 'port' => 1025, - 'username' => 'user', - 'password' => 'password', - ]); return $data; } /** * @group smtpAndTemplates - * @depends testCreateProject */ + * @depends testUpdateProjectSMTP + */ public function testUpdateTemplates($data): array { $id = $data['projectId']; @@ -602,11 +593,9 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('Account Verification', $response['body']['subject']); - $this->assertEquals('Project Test 2 Team', $response['body']['senderName']); - $this->assertEquals('team@appwrite.io', $response['body']['senderEmail']); + $this->assertEquals('', $response['body']['senderEmail']); $this->assertEquals('verification', $response['body']['type']); $this->assertEquals('en-us', $response['body']['locale']); - $this->assertMatchesRegularExpression('//', $response['body']['message']); /** Update Email template */ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/templates/email/verification/en-us', array_merge([ @@ -641,40 +630,41 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals('en-us', $response['body']['locale']); $this->assertEquals('Please verify your email {{url}}', $response['body']['message']); - /** Get Default SMS Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); + // Temporary disabled until implemented + // /** Get Default SMS Template */ + // $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ + // 'content-type' => 'application/json', + // 'x-appwrite-project' => $this->getProject()['$id'], + // ], $this->getHeaders())); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('verification', $response['body']['type']); - $this->assertEquals('en-us', $response['body']['locale']); - $this->assertEquals('{{token}}', $response['body']['message']); + // $this->assertEquals(200, $response['headers']['status-code']); + // $this->assertEquals('verification', $response['body']['type']); + // $this->assertEquals('en-us', $response['body']['locale']); + // $this->assertEquals('{{token}}', $response['body']['message']); - /** Update SMS template */ - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'message' => 'Please verify your email {{token}}', - ]); + // /** Update SMS template */ + // $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ + // 'content-type' => 'application/json', + // 'x-appwrite-project' => $this->getProject()['$id'], + // ], $this->getHeaders()), [ + // 'message' => 'Please verify your email {{token}}', + // ]); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('verification', $response['body']['type']); - $this->assertEquals('en-us', $response['body']['locale']); - $this->assertEquals('Please verify your email {{token}}', $response['body']['message']); + // $this->assertEquals(200, $response['headers']['status-code']); + // $this->assertEquals('verification', $response['body']['type']); + // $this->assertEquals('en-us', $response['body']['locale']); + // $this->assertEquals('Please verify your email {{token}}', $response['body']['message']); - /** Get Updated SMS Template */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); + // /** Get Updated SMS Template */ + // $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/templates/sms/verification/en-us', array_merge([ + // 'content-type' => 'application/json', + // 'x-appwrite-project' => $this->getProject()['$id'], + // ], $this->getHeaders())); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('verification', $response['body']['type']); - $this->assertEquals('en-us', $response['body']['locale']); - $this->assertEquals('Please verify your email {{token}}', $response['body']['message']); + // $this->assertEquals(200, $response['headers']['status-code']); + // $this->assertEquals('verification', $response['body']['type']); + // $this->assertEquals('en-us', $response['body']['locale']); + // $this->assertEquals('Please verify your email {{token}}', $response['body']['message']); return $data; } @@ -752,7 +742,6 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); // Check session doesn't expire too soon. - sleep(30); // Get User @@ -3135,171 +3124,6 @@ class ProjectsConsoleClientTest extends Scope return $data; } - // Domains - - /** - * @depends testCreateProject - */ - public function testCreateProjectDomain($data): array - { - $id = $data['projectId'] ?? ''; - - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/domains', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'domain' => 'sub.example.com', - ]); - - $this->assertEquals(201, $response['headers']['status-code']); - $this->assertNotEmpty($response['body']['$id']); - // $this->assertIsInt($response['body']['updated']); - $this->assertEquals('sub.example.com', $response['body']['domain']); - $this->assertEquals('com', $response['body']['tld']); - $this->assertEquals('example.com', $response['body']['registerable']); - $this->assertEquals(false, $response['body']['verification']); - - $data = array_merge($data, ['domainId' => $response['body']['$id']]); - - /** - * Test for FAILURE - */ - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'domain' => '123', - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - - $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'type' => 'web', - 'name' => 'Too Long Hostname', - 'hostname' => \str_repeat("bestdomain", 25) . '.com' // 250 + 4 chars total (exactly above limit) - ]); - - return $data; - } - - /** - * @depends testCreateProjectDomain - */ - public function testListProjectDomain($data): array - { - $id = $data['projectId'] ?? ''; - - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), []); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(1, $response['body']['total']); - - /** - * Test for FAILURE - */ - - return $data; - } - - /** - * @depends testCreateProjectDomain - */ - public function testGetProjectDomain($data): array - { - $id = $data['projectId'] ?? ''; - $domainId = $data['domainId'] ?? ''; - - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/' . $domainId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), []); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertNotEmpty($response['body']['$id']); - $this->assertEquals($domainId, $response['body']['$id']); - // $this->assertIsInt($response['body']['updated']); - $this->assertEquals('sub.example.com', $response['body']['domain']); - $this->assertEquals('com', $response['body']['tld']); - $this->assertEquals('example.com', $response['body']['registerable']); - $this->assertEquals(false, $response['body']['verification']); - - /** - * Test for FAILURE - */ - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/error', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), []); - - $this->assertEquals(404, $response['headers']['status-code']); - - return $data; - } - - /** - * @depends testCreateProjectDomain - */ - public function testUpdateProjectDomain($data): array - { - $id = $data['projectId'] ?? ''; - $domainId = $data['domainId'] ?? ''; - - $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/domains/' . $domainId . '/verification', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), []); - - $this->assertEquals(401, $response['headers']['status-code']); - - /** - * Test for FAILURE - */ - - return $data; - } - - /** - * @depends testCreateProjectDomain - */ - public function testDeleteProjectDomain($data): array - { - $id = $data['projectId'] ?? ''; - $domainId = $data['domainId'] ?? ''; - - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/domains/' . $domainId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), []); - - $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEmpty($response['body']); - - $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/' . $domainId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), []); - - $this->assertEquals(404, $response['headers']['status-code']); - - /** - * Test for FAILURE - */ - $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/domains/error', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), []); - - $this->assertEquals(404, $response['headers']['status-code']); - - return $data; - } - public function testDeleteProject(): array { $data = []; diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php index 3ef258885c..9c91ac4a52 100644 --- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php @@ -438,6 +438,7 @@ class RealtimeConsoleClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'events' => [ 'users.*.create', 'users.*.delete', @@ -450,7 +451,6 @@ class RealtimeConsoleClientTest extends Scope $this->assertEquals(201, $response1['headers']['status-code']); - $projectId = 'console'; $client = $this->getWebsocket(['console'], [ diff --git a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php index 4f880338a4..56796280ad 100644 --- a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php @@ -1263,6 +1263,7 @@ class RealtimeCustomClientTest extends Scope 'name' => 'Test', 'execute' => ['users'], 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'timeout' => 10, ]); @@ -1293,8 +1294,23 @@ class RealtimeCustomClientTest extends Scope $this->assertEquals($deployment['headers']['status-code'], 202); $this->assertNotEmpty($deployment['body']['$id']); - // Wait for deployment to be built. - sleep(10); + // Poll until deployment is built + while (true) { + $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + if ( + $deployment['headers']['status-code'] >= 400 + || \in_array($deployment['body']['status'], ['ready', 'failed']) + ) { + break; + } + + \sleep(1); + } $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([ 'content-type' => 'application/json', diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index b19fe49ed0..5463740761 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -2,6 +2,7 @@ namespace Tests\E2E\Services\Storage; +use Appwrite\Extend\Exception; use CURLFile; use Tests\E2E\Client; use Utopia\Database\DateTime; @@ -262,7 +263,7 @@ trait StorageBase ]); $this->assertEquals(400, $res['headers']['status-code']); - $this->assertEquals('The value for x-appwrite-id header is invalid. Please check the value of the x-appwrite-id header is valid id and not unique().', $res['body']['message']); + $this->assertEquals(Exception::STORAGE_INVALID_APPWRITE_ID, $res['body']['type']); return ['bucketId' => $bucketId, 'fileId' => $file['body']['$id'], 'largeFileId' => $largeFile['body']['$id'], 'largeBucketId' => $bucket2['body']['$id']]; } @@ -316,6 +317,54 @@ trait StorageBase return ['bucketId' => $bucketId]; } + public function testCreateBucketFileNoCollidingId(): void + { + $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'bucketId' => ID::unique(), + 'name' => 'Test Bucket', + 'maximumFileSize' => 2000000, //2MB + 'allowedFileExtensions' => ["jpg", "png"], + 'permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + ]); + + $this->assertEquals(201, $bucket['headers']['status-code']); + $this->assertNotEmpty($bucket['body']['$id']); + + $bucketId = $bucket['body']['$id']; + + $fileId = ID::unique(); + + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'fileId' => $fileId, + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + ]); + + $this->assertEquals(201, $file['headers']['status-code']); + $this->assertEquals($fileId, $file['body']['$id']); + + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'fileId' => $fileId, + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/file.png'), 'image/png', 'file.png'), + ]); + + $this->assertEquals(409, $file['headers']['status-code']); + } + /** * @depends testCreateBucketFile */ @@ -787,7 +836,7 @@ trait StorageBase $this->assertEquals(204, $file['headers']['status-code']); $this->assertEmpty($file['body']); - $file = $this->client->call(Client::METHOD_GET, '/storage/files/' . $data['fileId'], array_merge([ + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); diff --git a/tests/e2e/Services/Storage/StorageConsoleClientTest.php b/tests/e2e/Services/Storage/StorageConsoleClientTest.php index aff055f18d..8fda8e0464 100644 --- a/tests/e2e/Services/Storage/StorageConsoleClientTest.php +++ b/tests/e2e/Services/Storage/StorageConsoleClientTest.php @@ -39,11 +39,10 @@ class StorageConsoleClientTest extends Scope ]); $this->assertEquals($response['headers']['status-code'], 200); - $this->assertEquals(4, count($response['body'])); + $this->assertEquals(12, count($response['body'])); $this->assertEquals($response['body']['range'], '24h'); - $this->assertIsArray($response['body']['bucketsTotal']); - $this->assertIsArray($response['body']['filesTotal']); - $this->assertIsArray($response['body']['filesStorage']); + $this->assertIsArray($response['body']['storage']); + $this->assertIsArray($response['body']['filesCount']); } public function testGetStorageBucketUsage() @@ -95,9 +94,13 @@ class StorageConsoleClientTest extends Scope ]); $this->assertEquals($response['headers']['status-code'], 200); - $this->assertEquals(count($response['body']), 3); + $this->assertEquals(count($response['body']), 7); $this->assertEquals($response['body']['range'], '24h'); - $this->assertIsArray($response['body']['filesTotal']); + $this->assertIsArray($response['body']['filesCount']); + $this->assertIsArray($response['body']['filesCreate']); + $this->assertIsArray($response['body']['filesRead']); + $this->assertIsArray($response['body']['filesUpdate']); + $this->assertIsArray($response['body']['filesDelete']); $this->assertIsArray($response['body']['filesStorage']); } } diff --git a/tests/e2e/Services/Users/UsersConsoleClientTest.php b/tests/e2e/Services/Users/UsersConsoleClientTest.php index 8943bfab63..9cc23e825a 100644 --- a/tests/e2e/Services/Users/UsersConsoleClientTest.php +++ b/tests/e2e/Services/Users/UsersConsoleClientTest.php @@ -23,6 +23,17 @@ class UsersConsoleClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ 'range' => '32h', + 'provider' => 'email' + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/users/usage', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'] + ], $this->getHeaders()), [ + 'range' => '24h', + 'provider' => 'some-random-provider' ]); $this->assertEquals($response['headers']['status-code'], 400); @@ -35,12 +46,38 @@ class UsersConsoleClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'] ], $this->getHeaders()), [ 'range' => '24h', + 'provider' => 'email' ]); $this->assertEquals($response['headers']['status-code'], 200); - $this->assertEquals(count($response['body']), 3); + $this->assertEquals(count($response['body']), 9); $this->assertEquals($response['body']['range'], '24h'); - $this->assertIsArray($response['body']['usersTotal']); - $this->assertIsArray($response['body']['sessionsTotal']); + $this->assertIsArray($response['body']['usersCount']); + $this->assertIsArray($response['body']['usersCreate']); + $this->assertIsArray($response['body']['usersRead']); + $this->assertIsArray($response['body']['usersUpdate']); + $this->assertIsArray($response['body']['usersDelete']); + $this->assertIsArray($response['body']['sessionsCreate']); + $this->assertIsArray($response['body']['sessionsProviderCreate']); + $this->assertIsArray($response['body']['sessionsDelete']); + + $response = $this->client->call(Client::METHOD_GET, '/users/usage', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'] + ], $this->getHeaders()), [ + 'range' => '24h' + ]); + + $this->assertEquals($response['headers']['status-code'], 200); + $this->assertEquals(count($response['body']), 9); + $this->assertEquals($response['body']['range'], '24h'); + $this->assertIsArray($response['body']['usersCount']); + $this->assertIsArray($response['body']['usersCreate']); + $this->assertIsArray($response['body']['usersRead']); + $this->assertIsArray($response['body']['usersUpdate']); + $this->assertIsArray($response['body']['usersDelete']); + $this->assertIsArray($response['body']['sessionsCreate']); + $this->assertIsArray($response['body']['sessionsProviderCreate']); + $this->assertIsArray($response['body']['sessionsDelete']); } } diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index 02c3a2dbfd..01aa00cd84 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -401,6 +401,7 @@ class WebhooksCustomServerTest extends Scope 'name' => 'Test', 'execute' => [Role::any()->toString()], 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'timeout' => 10, ]); @@ -415,18 +416,10 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['method'], 'POST'); $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); - // $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']); - // $this->assertStringContainsString('functions.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); - // $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']); - // $this->assertStringContainsString("functions.{$id}.create", $webhook['headers']['X-Appwrite-Webhook-Events']); TODO @christyjacob4 : enable test once we allow functions.* events $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']); - /** - * Test for FAILURE - */ - return [ 'functionId' => $id, ]; @@ -448,6 +441,7 @@ class WebhooksCustomServerTest extends Scope ], $this->getHeaders()), [ 'name' => 'Test', 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', 'execute' => [Role::any()->toString()], 'vars' => [ 'key1' => 'value1', diff --git a/tests/resources/docker/docker-compose.yml b/tests/resources/docker/docker-compose.yml index 6b0644c01e..3baae7316d 100644 --- a/tests/resources/docker/docker-compose.yml +++ b/tests/resources/docker/docker-compose.yml @@ -69,6 +69,7 @@ services: - _APP_OPTIONS_FORCE_HTTPS - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN + - _APP_DOMAIN_FUNCTIONS - _APP_DOMAIN_TARGET - _APP_REDIS_HOST - _APP_REDIS_PORT diff --git a/tests/resources/functions/dart/main.dart b/tests/resources/functions/dart/main.dart index 0a6cabdac7..1ed09c3485 100644 --- a/tests/resources/functions/dart/main.dart +++ b/tests/resources/functions/dart/main.dart @@ -1,29 +1,21 @@ -/* - 'req' variable has: - 'headers' - object with request headers - 'payload' - object with request body data - 'variables' - object with function variables - 'res' variable has: - 'send(text, status)' - function to return text response. Status code defaults to 200 - 'json(obj, status)' - function to return JSON response. Status code defaults to 200 - - If an error is thrown, a response with code 500 will be returned. -*/ +import 'dart:io' show Platform; + +Future main(final context) async { + context.log('Amazing Function Log'); -Future start(final request, final response) async { response.json({ - 'APPWRITE_FUNCTION_ID' : request.variables['APPWRITE_FUNCTION_ID'], - 'APPWRITE_FUNCTION_NAME' : request.variables['APPWRITE_FUNCTION_NAME'], - 'APPWRITE_FUNCTION_DEPLOYMENT' : request.variables['APPWRITE_FUNCTION_DEPLOYMENT'], - 'APPWRITE_FUNCTION_TRIGGER' : request.variables['APPWRITE_FUNCTION_TRIGGER'], - 'APPWRITE_FUNCTION_RUNTIME_NAME' : request.variables['APPWRITE_FUNCTION_RUNTIME_NAME'], - 'APPWRITE_FUNCTION_RUNTIME_VERSION' : request.variables['APPWRITE_FUNCTION_RUNTIME_VERSION'], - 'APPWRITE_FUNCTION_EVENT' : request.variables['APPWRITE_FUNCTION_EVENT'], - 'APPWRITE_FUNCTION_EVENT_DATA' : request.variables['APPWRITE_FUNCTION_EVENT_DATA'], - 'APPWRITE_FUNCTION_DATA' : request.variables['APPWRITE_FUNCTION_DATA'], - 'APPWRITE_FUNCTION_USER_ID' : request.variables['APPWRITE_FUNCTION_USER_ID'], - 'APPWRITE_FUNCTION_JWT' : request.variables['APPWRITE_FUNCTION_JWT'], - 'APPWRITE_FUNCTION_PROJECT_ID' : request.variables['APPWRITE_FUNCTION_PROJECT_ID'], + 'APPWRITE_FUNCTION_ID' : Platform.environment['APPWRITE_FUNCTION_ID'] ?? '', + 'APPWRITE_FUNCTION_NAME' : Platform.environment['APPWRITE_FUNCTION_NAME'] ?? '', + 'APPWRITE_FUNCTION_DEPLOYMENT' : Platform.environment['APPWRITE_FUNCTION_DEPLOYMENT'] ?? '', + 'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '', + 'APPWRITE_FUNCTION_RUNTIME_NAME' : Platform.environment['APPWRITE_FUNCTION_RUNTIME_NAME'] ?? '', + 'APPWRITE_FUNCTION_RUNTIME_VERSION' : Platform.environment['APPWRITE_FUNCTION_RUNTIME_VERSION'] ?? '', + 'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '', + 'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '', + 'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '', + 'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '', + 'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '', + 'APPWRITE_FUNCTION_PROJECT_ID' : Platform.environment['APPWRITE_FUNCTION_PROJECT_ID'] ?? '', 'CUSTOM_VARIABLE' : request.variables['CUSTOM_VARIABLE'] }); } \ No newline at end of file diff --git a/tests/resources/functions/node/index.js b/tests/resources/functions/node/index.js index 7f190bcaf5..041e4a8c12 100644 --- a/tests/resources/functions/node/index.js +++ b/tests/resources/functions/node/index.js @@ -1,29 +1,19 @@ -/* - 'req' variable has: - 'headers' - object with request headers - 'payload' - object with request body data - 'variables' - object with function variables - 'res' variable has: - 'send(text, status)' - function to return text response. Status code defaults to 200 - 'json(obj, status)' - function to return JSON response. Status code defaults to 200 +module.exports = async(context) => { + context.log('Amazing Function Log'); - If an error is thrown, a response with code 500 will be returned. -*/ - -module.exports = async(req, res) => { - res.json({ - 'APPWRITE_FUNCTION_ID' : req.variables.APPWRITE_FUNCTION_ID, - 'APPWRITE_FUNCTION_NAME' : req.variables.APPWRITE_FUNCTION_NAME, - 'APPWRITE_FUNCTION_DEPLOYMENT' : req.variables.APPWRITE_FUNCTION_DEPLOYMENT, - 'APPWRITE_FUNCTION_TRIGGER' : req.variables.APPWRITE_FUNCTION_TRIGGER, - 'APPWRITE_FUNCTION_RUNTIME_NAME' : req.variables.APPWRITE_FUNCTION_RUNTIME_NAME, - 'APPWRITE_FUNCTION_RUNTIME_VERSION' : req.variables.APPWRITE_FUNCTION_RUNTIME_VERSION, - 'APPWRITE_FUNCTION_EVENT' : req.variables.APPWRITE_FUNCTION_EVENT, - 'APPWRITE_FUNCTION_EVENT_DATA' : req.variables.APPWRITE_FUNCTION_EVENT_DATA, - 'APPWRITE_FUNCTION_DATA' : req.variables.APPWRITE_FUNCTION_DATA, - 'APPWRITE_FUNCTION_USER_ID' : req.variables.APPWRITE_FUNCTION_USER_ID, - 'APPWRITE_FUNCTION_JWT' : req.variables.APPWRITE_FUNCTION_JWT, - 'APPWRITE_FUNCTION_PROJECT_ID' : req.variables.APPWRITE_FUNCTION_PROJECT_ID, - 'CUSTOM_VARIABLE' : req.variables.CUSTOM_VARIABLE + return context.res.json({ + 'APPWRITE_FUNCTION_ID' : process.env.APPWRITE_FUNCTION_ID ?? '', + 'APPWRITE_FUNCTION_NAME' : process.env.APPWRITE_FUNCTION_NAME ?? '', + 'APPWRITE_FUNCTION_DEPLOYMENT' : process.env.APPWRITE_FUNCTION_DEPLOYMENT ?? '', + 'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '', + 'APPWRITE_FUNCTION_RUNTIME_NAME' : process.env.APPWRITE_FUNCTION_RUNTIME_NAME, + 'APPWRITE_FUNCTION_RUNTIME_VERSION' : process.env.APPWRITE_FUNCTION_RUNTIME_VERSION, + 'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '', + 'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '', + 'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '', + 'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '', + 'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '', + 'APPWRITE_FUNCTION_PROJECT_ID' : process.env.APPWRITE_FUNCTION_PROJECT_ID, + 'CUSTOM_VARIABLE' : process.env.CUSTOM_VARIABLE }); } \ No newline at end of file diff --git a/tests/resources/functions/php-fn/index.php b/tests/resources/functions/php-fn/index.php index 7947c4a6a6..3eea2d6fea 100644 --- a/tests/resources/functions/php-fn/index.php +++ b/tests/resources/functions/php-fn/index.php @@ -1,20 +1,21 @@ log('Amazing Function Log'); - $response->json([ - 'APPWRITE_FUNCTION_ID' => $request['variables']['APPWRITE_FUNCTION_ID'], - 'APPWRITE_FUNCTION_NAME' => $request['variables']['APPWRITE_FUNCTION_NAME'], - 'APPWRITE_FUNCTION_DEPLOYMENT' => $request['variables']['APPWRITE_FUNCTION_DEPLOYMENT'], - 'APPWRITE_FUNCTION_TRIGGER' => $request['variables']['APPWRITE_FUNCTION_TRIGGER'], - 'APPWRITE_FUNCTION_RUNTIME_NAME' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_NAME'], - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'], - 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'], - 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'], - 'APPWRITE_FUNCTION_DATA' => $request['variables']['APPWRITE_FUNCTION_DATA'], - 'APPWRITE_FUNCTION_USER_ID' => $request['variables']['APPWRITE_FUNCTION_USER_ID'], - 'APPWRITE_FUNCTION_JWT' => $request['variables']['APPWRITE_FUNCTION_JWT'], - 'APPWRITE_FUNCTION_PROJECT_ID' => $request['variables']['APPWRITE_FUNCTION_PROJECT_ID'], + return $context->res->json([ + 'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '', + 'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '', + 'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '', + 'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '', + 'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '', + 'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '', + 'APPWRITE_FUNCTION_EVENT' => $context->req->headers['x-appwrite-event'] ?? '', + 'APPWRITE_FUNCTION_EVENT_DATA' => $context->req->bodyRaw ?? '', + 'APPWRITE_FUNCTION_DATA' => $context->req->bodyRaw ?? '', + 'APPWRITE_FUNCTION_USER_ID' => $context->req->headers['x-appwrite-user-id'] ?? '', + 'APPWRITE_FUNCTION_JWT' => $context->req->headers['x-appwrite-user-jwt'] ?? '', + 'APPWRITE_FUNCTION_PROJECT_ID' => \getenv('APPWRITE_FUNCTION_PROJECT_ID') ?: '', + 'CUSTOM_VARIABLE' => \getenv('CUSTOM_VARIABLE') ?: '', ]); }; diff --git a/tests/resources/functions/php-large/index.php b/tests/resources/functions/php-large/index.php index 84b6a991fe..5a9666488e 100644 --- a/tests/resources/functions/php-large/index.php +++ b/tests/resources/functions/php-large/index.php @@ -1,15 +1,13 @@ json([ - 'APPWRITE_FUNCTION_ID' => $request['variables']['APPWRITE_FUNCTION_ID'], - 'APPWRITE_FUNCTION_NAME' => $request['variables']['APPWRITE_FUNCTION_NAME'], - 'APPWRITE_FUNCTION_DEPLOYMENT' => $request['variables']['APPWRITE_FUNCTION_DEPLOYMENT'], - 'APPWRITE_FUNCTION_TRIGGER' => $request['variables']['APPWRITE_FUNCTION_TRIGGER'], - 'APPWRITE_FUNCTION_RUNTIME_NAME' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_NAME'], - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'], - 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'], - 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'], +return function ($context) { + return $context->res->json([ + 'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '', + 'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '', + 'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '', + 'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '', + 'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '', + 'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '', 'UNICODE_TEST' => "êä" ]); }; diff --git a/tests/resources/functions/php/index.php b/tests/resources/functions/php/index.php index 84b6a991fe..5a9666488e 100644 --- a/tests/resources/functions/php/index.php +++ b/tests/resources/functions/php/index.php @@ -1,15 +1,13 @@ json([ - 'APPWRITE_FUNCTION_ID' => $request['variables']['APPWRITE_FUNCTION_ID'], - 'APPWRITE_FUNCTION_NAME' => $request['variables']['APPWRITE_FUNCTION_NAME'], - 'APPWRITE_FUNCTION_DEPLOYMENT' => $request['variables']['APPWRITE_FUNCTION_DEPLOYMENT'], - 'APPWRITE_FUNCTION_TRIGGER' => $request['variables']['APPWRITE_FUNCTION_TRIGGER'], - 'APPWRITE_FUNCTION_RUNTIME_NAME' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_NAME'], - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'], - 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'], - 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'], +return function ($context) { + return $context->res->json([ + 'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '', + 'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '', + 'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '', + 'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '', + 'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '', + 'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '', 'UNICODE_TEST' => "êä" ]); }; diff --git a/tests/resources/functions/python/main.py b/tests/resources/functions/python/main.py index ff78d6d336..fda0b36f0e 100644 --- a/tests/resources/functions/python/main.py +++ b/tests/resources/functions/python/main.py @@ -1,28 +1,21 @@ import json +import os -# 'req' variable has: -# 'headers' - object with request headers -# 'payload' - object with request body data -# 'variables' - object with function variables -# 'res' variable has: -# 'send(text, status)' - function to return text response. Status code defaults to 200 -# 'json(obj, status)' - function to return JSON response. Status code defaults to 200 -# -# If an error is thrown, a response with code 500 will be returned. +def main(context): + context.log('Amazing Function Log') -def main(request, response): - return response.json({ - 'APPWRITE_FUNCTION_ID' : request.variables['APPWRITE_FUNCTION_ID'], - 'APPWRITE_FUNCTION_NAME' : request.variables['APPWRITE_FUNCTION_NAME'], - 'APPWRITE_FUNCTION_DEPLOYMENT' : request.variables['APPWRITE_FUNCTION_DEPLOYMENT'], - 'APPWRITE_FUNCTION_TRIGGER' : request.variables['APPWRITE_FUNCTION_TRIGGER'], - 'APPWRITE_FUNCTION_RUNTIME_NAME' : request.variables['APPWRITE_FUNCTION_RUNTIME_NAME'], - 'APPWRITE_FUNCTION_RUNTIME_VERSION' : request.variables['APPWRITE_FUNCTION_RUNTIME_VERSION'], - 'APPWRITE_FUNCTION_EVENT' : request.variables['APPWRITE_FUNCTION_EVENT'], - 'APPWRITE_FUNCTION_EVENT_DATA' : request.variables['APPWRITE_FUNCTION_EVENT_DATA'], - 'APPWRITE_FUNCTION_DATA' : request.variables['APPWRITE_FUNCTION_DATA'], - 'APPWRITE_FUNCTION_USER_ID' : request.variables['APPWRITE_FUNCTION_USER_ID'], - 'APPWRITE_FUNCTION_JWT' : request.variables['APPWRITE_FUNCTION_JWT'], - 'APPWRITE_FUNCTION_PROJECT_ID' : request.variables['APPWRITE_FUNCTION_PROJECT_ID'], - 'CUSTOM_VARIABLE' : request.variables['CUSTOM_VARIABLE'], + return context.res.json({ + 'APPWRITE_FUNCTION_ID' : os.environ.get('APPWRITE_FUNCTION_ID',''), + 'APPWRITE_FUNCTION_NAME' : os.environ.get('APPWRITE_FUNCTION_NAME',''), + 'APPWRITE_FUNCTION_DEPLOYMENT' : os.environ.get('APPWRITE_FUNCTION_DEPLOYMENT',''), + 'APPWRITE_FUNCTION_TRIGGER' : context.req.headers.get('x-appwrite-trigger', ''), + 'APPWRITE_FUNCTION_RUNTIME_NAME' : os.environ.get('APPWRITE_FUNCTION_RUNTIME_NAME',''), + 'APPWRITE_FUNCTION_RUNTIME_VERSION' : os.environ.get('APPWRITE_FUNCTION_RUNTIME_VERSION',''), + 'APPWRITE_FUNCTION_EVENT' : context.req.headers.get('x-appwrite-event', ''), + 'APPWRITE_FUNCTION_EVENT_DATA' : context.req.body_raw, + 'APPWRITE_FUNCTION_DATA' : context.req.body_raw, + 'APPWRITE_FUNCTION_USER_ID' : context.req.headers.get('x-appwrite-user-id', ''), + 'APPWRITE_FUNCTION_JWT' : context.req.headers.get('x-appwrite-user-jwt', ''), + 'APPWRITE_FUNCTION_PROJECT_ID' : os.environ.get('APPWRITE_FUNCTION_PROJECT_ID',''), + 'CUSTOM_VARIABLE' : os.environ.get('CUSTOM_VARIABLE',''), }) \ No newline at end of file diff --git a/tests/resources/functions/ruby/main.rb b/tests/resources/functions/ruby/main.rb index d6ccdfb073..c14f591fa1 100644 --- a/tests/resources/functions/ruby/main.rb +++ b/tests/resources/functions/ruby/main.rb @@ -1,29 +1,19 @@ -=begin - 'req' variable has: - 'headers' - object with request headers - 'payload' - object with request body data - 'variables' - object with function variables - 'res' variable has: - 'send(text, status)' - function to return text response. Status code defaults to 200 - 'json(obj, status)' - function to return JSON response. Status code defaults to 200 - - If an error is thrown, a response with code 500 will be returned. -=end +def main(context) + context.log('Amazing Function Log') -def main(request, response) - return response.json({ - 'APPWRITE_FUNCTION_ID' => request.variables['APPWRITE_FUNCTION_ID'], - 'APPWRITE_FUNCTION_NAME' => request.variables['APPWRITE_FUNCTION_NAME'], - 'APPWRITE_FUNCTION_DEPLOYMENT' => request.variables['APPWRITE_FUNCTION_DEPLOYMENT'], - 'APPWRITE_FUNCTION_TRIGGER' => request.variables['APPWRITE_FUNCTION_TRIGGER'], - 'APPWRITE_FUNCTION_RUNTIME_NAME' => request.variables['APPWRITE_FUNCTION_RUNTIME_NAME'], - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => request.variables['APPWRITE_FUNCTION_RUNTIME_VERSION'], - 'APPWRITE_FUNCTION_EVENT' => request.variables['APPWRITE_FUNCTION_EVENT'], - 'APPWRITE_FUNCTION_EVENT_DATA' => request.variables['APPWRITE_FUNCTION_EVENT_DATA'], - 'APPWRITE_FUNCTION_DATA' => request.variables['APPWRITE_FUNCTION_DATA'], - 'APPWRITE_FUNCTION_USER_ID' => request.variables['APPWRITE_FUNCTION_USER_ID'], - 'APPWRITE_FUNCTION_JWT' => request.variables['APPWRITE_FUNCTION_JWT'], - 'APPWRITE_FUNCTION_PROJECT_ID' => request.variables['APPWRITE_FUNCTION_PROJECT_ID'], - 'CUSTOM_VARIABLE' => request.variables['CUSTOM_VARIABLE'] + return context.res.json({ + 'APPWRITE_FUNCTION_ID' => ENV['APPWRITE_FUNCTION_ID'] || '', + 'APPWRITE_FUNCTION_NAME' => ENV['APPWRITE_FUNCTION_NAME'] || '', + 'APPWRITE_FUNCTION_DEPLOYMENT' => ENV['APPWRITE_FUNCTION_DEPLOYMENT'] || '', + 'APPWRITE_FUNCTION_TRIGGER' => context.req.headers['x-appwrite-trigger'] || '', + 'APPWRITE_FUNCTION_RUNTIME_NAME' => ENV['APPWRITE_FUNCTION_RUNTIME_NAME'] || '', + 'APPWRITE_FUNCTION_RUNTIME_VERSION' => ENV['APPWRITE_FUNCTION_RUNTIME_VERSION'] || '', + 'APPWRITE_FUNCTION_EVENT' => context.req.headers['x-appwrite-event'] || '', + 'APPWRITE_FUNCTION_EVENT_DATA' => context.req.body_raw || '', + 'APPWRITE_FUNCTION_DATA' => context.req.body_raw || '', + 'APPWRITE_FUNCTION_USER_ID' => context.req.headers['x-appwrite-user-id'] || '', + 'APPWRITE_FUNCTION_JWT' => context.req.headers['x-appwrite-user-jwt'] || '', + 'APPWRITE_FUNCTION_PROJECT_ID' => ENV['APPWRITE_FUNCTION_PROJECT_ID'] || '', + 'CUSTOM_VARIABLE' => ENV['CUSTOM_VARIABLE'] || '' }) end \ No newline at end of file diff --git a/tests/resources/functions/timeout/index.php b/tests/resources/functions/timeout/index.php index c45ab5a5b8..c9aedb3a30 100644 --- a/tests/resources/functions/timeout/index.php +++ b/tests/resources/functions/timeout/index.php @@ -1,5 +1,6 @@ res->send('OK'); }; diff --git a/tests/unit/Migration/MigrationTest.php b/tests/unit/Migration/MigrationTest.php index 13f9b9a3f5..536278d55b 100644 --- a/tests/unit/Migration/MigrationTest.php +++ b/tests/unit/Migration/MigrationTest.php @@ -47,92 +47,4 @@ abstract class MigrationTest extends TestCase $this->assertArrayHasKey(APP_VERSION_STABLE, Migration::$versions); } } - - public function testHasDifference(): void - { - $this->assertFalse(Migration::hasDifference([], [])); - $this->assertFalse(Migration::hasDifference([ - 'bool' => true, - 'string' => 'abc', - 'int' => 123, - 'array' => ['a', 'b', 'c'], - 'assoc' => [ - 'a' => true, - 'b' => 'abc', - 'c' => 123, - 'd' => ['a', 'b', 'c'] - ] - ], [ - 'bool' => true, - 'string' => 'abc', - 'int' => 123, - 'array' => ['a', 'b', 'c'], - 'assoc' => [ - 'a' => true, - 'b' => 'abc', - 'c' => 123, - 'd' => ['a', 'b', 'c'] - ] - ])); - $this->assertFalse(Migration::hasDifference([ - 'bool' => true, - 'string' => 'abc', - 'int' => 123, - 'array' => ['a', 'b', 'c'], - 'assoc' => [ - 'a' => true, - 'b' => 'abc', - 'c' => 123, - 'd' => ['a', 'b', 'c'] - ] - ], [ - 'string' => 'abc', - 'assoc' => [ - 'a' => true, - 'b' => 'abc', - 'c' => 123, - 'd' => ['a', 'b', 'c'] - ], - 'int' => 123, - 'array' => ['a', 'b', 'c'], - 'bool' => true, - - ])); - $this->assertTrue(Migration::hasDifference([ - 'a' => true - ], [ - 'b' => true - ])); - $this->assertTrue(Migration::hasDifference([ - 'a' => 'true' - ], [ - 'a' => true - ])); - $this->assertTrue(Migration::hasDifference([ - 'a' => true - ], [ - 'a' => false - ])); - $this->assertTrue(Migration::hasDifference([ - 'nested' => [ - 'a' => true - ] - ], [ - 'nested' => [] - ])); - $this->assertTrue(Migration::hasDifference([ - 'assoc' => [ - 'bool' => true, - 'string' => 'abc', - 'int' => 123, - 'array' => ['a', 'b', 'c'] - ] - ], [ - 'nested' => [ - 'a' => true, - 'int' => '123', - 'array' => ['a', 'b', 'c'] - ] - ])); - } } diff --git a/tests/unit/Usage/StatsTest.php b/tests/unit/Usage/StatsTest.php index 0c9914f4bd..f021841396 100644 --- a/tests/unit/Usage/StatsTest.php +++ b/tests/unit/Usage/StatsTest.php @@ -2,53 +2,70 @@ namespace Tests\Unit\Usage; -use Appwrite\URL\URL as AppwriteURL; +use Appwrite\Usage\Stats; use PHPUnit\Framework\TestCase; use Utopia\App; -use Utopia\DSN\DSN; -use Utopia\Queue; -use Utopia\Queue\Client; -use Utopia\Queue\Connection; class StatsTest extends TestCase { - protected ?Connection $connection = null; - protected ?Client $client = null; - - protected const QUEUE_NAME = 'usage-test-q'; + /** + * @var Stats + */ + protected $object = null; public function setUp(): void { - $env = App::getEnv('_APP_CONNECTIONS_QUEUE', AppwriteURL::unparse([ - 'scheme' => 'redis', - 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), - 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), - 'user' => App::getEnv('_APP_REDIS_USER', ''), - 'pass' => App::getEnv('_APP_REDIS_PASS', ''), - ])); + $host = App::getEnv('_APP_STATSD_HOST', 'telegraf'); + $port = App::getEnv('_APP_STATSD_PORT', 8125); - $dsn = explode('=', $env); - $dsn = $dsn[1] ?? ''; - $dsn = new DSN($dsn); - $this->connection = new Queue\Connection\Redis($dsn->getHost(), $dsn->getPort()); - $this->client = new Client(self::QUEUE_NAME, $this->connection); + $connection = new \Domnikl\Statsd\Connection\UdpSocket($host, $port); + $statsd = new \Domnikl\Statsd\Client($connection); + + $this->object = new Stats($statsd); } public function tearDown(): void { } - public function testSamePayload(): void + public function testNamespace(): void { - $inToQueue = [ - 'key_1' => 'value_1', - 'key_2' => 'value_2', - ]; + $this->object->setNamespace('appwritetest.usage'); + $this->assertEquals('appwritetest.usage', $this->object->getNamespace()); + } - $result = $this->client->enqueue($inToQueue); - $this->assertTrue($result); - $outFromQueue = $this->connection->leftPopArray('utopia-queue.queue.' . self::QUEUE_NAME, 0)['payload']; - $this->assertNotEmpty($outFromQueue); - $this->assertSame($inToQueue, $outFromQueue); + public function testParams(): void + { + $this->object + ->setParam('projectId', 'appwrite_test') + ->setParam('projectInternalId', 1) + ->setParam('networkRequestSize', 100) + ; + + $this->assertEquals('appwrite_test', $this->object->getParam('projectId')); + $this->assertEquals(1, $this->object->getParam('projectInternalId')); + $this->assertEquals(100, $this->object->getParam('networkRequestSize')); + + $this->object->submit(); + + $this->assertEquals(null, $this->object->getParam('projectId')); + $this->assertEquals(null, $this->object->getParam('networkRequestSize')); + } + + public function testReset(): void + { + $this->object + ->setParam('projectId', 'appwrite_test') + ->setParam('networkRequestSize', 100) + ; + + $this->assertEquals('appwrite_test', $this->object->getParam('projectId')); + $this->assertEquals(100, $this->object->getParam('networkRequestSize')); + + $this->object->reset(); + + $this->assertEquals(null, $this->object->getParam('projectId')); + $this->assertEquals(null, $this->object->getParam('networkRequestSize')); + $this->assertEquals('appwrite.usage', $this->object->getNamespace()); } } diff --git a/tests/unit/Utopia/Request/Filters/V16Test.php b/tests/unit/Utopia/Request/Filters/V16Test.php new file mode 100644 index 0000000000..25b97a0ce4 --- /dev/null +++ b/tests/unit/Utopia/Request/Filters/V16Test.php @@ -0,0 +1,51 @@ +filter = new V16(); + } + + public function tearDown(): void + { + } + + public function createExecutionProvider(): array + { + return [ + 'data' => [ + [ + 'data' => 'Lorem ipsum' + ], + [ + 'body' => 'Lorem ipsum' + ], + ], + ]; + } + + /** + * @dataProvider createExecutionProvider + */ + public function testCreateExecution(array $content, array $expected): void + { + $model = 'functions.createExecution'; + + $result = $this->filter->parse($content, $model); + + $this->assertEquals($expected, $result); + } +} diff --git a/tests/unit/Utopia/Response/Filters/V16Test.php b/tests/unit/Utopia/Response/Filters/V16Test.php new file mode 100644 index 0000000000..fba3b69535 --- /dev/null +++ b/tests/unit/Utopia/Response/Filters/V16Test.php @@ -0,0 +1,228 @@ +filter = new V16(); + } + + public function tearDown(): void + { + } + + public function deploymentProvider(): array + { + return [ + 'buildStdout and buildStderr' => [ + [ + 'buildLogs' => 'Compiling source files...', + ], + [ + 'buildStdout' => 'Compiling source files...', + 'buildStderr' => '', + ], + ], + ]; + } + + /** + * @dataProvider deploymentProvider + */ + public function testDeployment(array $content, array $expected): void + { + $model = Response::MODEL_DEPLOYMENT; + + $result = $this->filter->parse($content, $model); + + $this->assertEquals($expected, $result); + } + + public function executionProvider(): array + { + return [ + 'statusCode' => [ + [ + 'responseStatusCode' => 200, + ], + [ + 'statusCode' => 200, + ], + ], + 'response' => [ + [ + 'responseBody' => 'Sample response.', + ], + [ + 'response' => 'Sample response.', + ], + ], + 'stdout' => [ + [ + 'logs' => 'Sample log.', + ], + [ + 'stdout' => 'Sample log.', + ], + ], + 'stderr' => [ + [ + 'errors' => 'Sample error.', + ], + [ + 'stderr' => 'Sample error.', + ], + ], + ]; + } + + /** + * @dataProvider executionProvider + */ + public function testExecution(array $content, array $expected): void + { + $model = Response::MODEL_EXECUTION; + + $result = $this->filter->parse($content, $model); + + $this->assertEquals($expected, $result); + } + + public function functionProvider(): array + { + return [ + 'empty schedule' => [ + [ + 'schedule' => '', + ], + [ + 'schedule' => '', + 'schedulePrevious' => '', + 'scheduleNext' => '', + ], + ], + ]; + } + + /** + * @dataProvider functionProvider + */ + public function testFunction(array $content, array $expected): void + { + $model = Response::MODEL_FUNCTION; + + $result = $this->filter->parse($content, $model); + + $this->assertEquals($expected, $result); + } + + public function testFunctionSchedulePreviousScheduleNext(): void + { + $model = Response::MODEL_FUNCTION; + + $content = [ + 'schedule' => '0 * * * *', + ]; + + $cron = new CronExpression($content['schedule']); + + $expected = [ + 'schedule' => '0 * * * *', + 'scheduleNext' => DateTime::formatTz(DateTime::format($cron->getNextRunDate())), + 'schedulePrevious' => DateTime::formatTz(DateTime::format($cron->getPreviousRunDate())), + ]; + + $result = $this->filter->parse($content, $model); + + $this->assertEquals($expected, $result); + } + + public function projectProvider(): array + { + return [ + 'providers' => [ + [ + 'providers' => [ + [ + 'key' => 'github', + 'name' => 'GitHub', + 'appId' => 'client_id', + 'secret' => 'client_secret', + 'enabled' => true, + ], + ], + ], + [ + 'providers' => [ + [ + 'name' => 'Github', + 'appId' => 'client_id', + 'secret' => 'client_secret', + 'enabled' => true, + ], + ], + 'domains' => [], + ], + ], + 'domains' => [ + [ + ], + [ + 'domains' => [], + ], + ], + ]; + } + + /** + * @dataProvider projectProvider + */ + public function testProject(array $content, array $expected): void + { + $model = Response::MODEL_PROJECT; + + $result = $this->filter->parse($content, $model); + + $this->assertEquals($expected, $result); + } + + public function variableProvider(): array + { + return [ + 'functionId' => [ + [ + 'resourceId' => '5e5ea5c16897e', + ], + [ + 'functionId' => '5e5ea5c16897e', + ], + ], + ]; + } + + /** + * @dataProvider variableProvider + */ + public function testVariable(array $content, array $expected): void + { + $model = Response::MODEL_VARIABLE; + + $result = $this->filter->parse($content, $model); + + $this->assertEquals($expected, $result); + } +} From b7119a2718a48512312451c84d867f5bdbd71dd6 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 12 Sep 2023 21:03:44 +0530 Subject: [PATCH 071/196] review changes --- app/config/collections.php | 111 +++++++++++++++++++++++++------------ app/config/roles.php | 16 +++++- app/config/scopes.php | 2 +- app/init.php | 41 +++++++++++++- 4 files changed, 131 insertions(+), 39 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 79f1622574..2c298e986c 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1437,22 +1437,61 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => ['json', 'encrypt'], - ] + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 65535, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ '$id' => ID::custom('_key_provider'), 'type' => Database::INDEX_KEY, 'attributes' => ['provider'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => ID::custom('_key_name'), 'type' => Database::INDEX_FULLTEXT, 'attributes' => ['name'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_type'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['type'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_default'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['default'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_default_type'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['default, type'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_search'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['search'], + 'lengths' => [], + 'orders' => [], ] ], ], @@ -1484,24 +1523,13 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], - [ - '$id' => ID::custom('type'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => 128, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('data'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 16384, + 'size' => 65535, 'signed' => true, - 'required' => false, + 'required' => true, 'default' => null, 'array' => false, 'filters' => ['json'], @@ -1510,7 +1538,7 @@ $commonCollections = [ '$id' => ID::custom('to'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 16834, + 'size' => 65535, 'signed' => true, 'required' => true, 'default' => null, @@ -1529,14 +1557,14 @@ $commonCollections = [ 'filters' => ['datetime'], ], [ - '$id' => ID::custom('deliveryError'), + '$id' => ID::custom('deliveryErrors'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 2048, + 'size' => 65535, 'signed' => true, 'required' => false, 'default' => null, - 'array' => false, + 'array' => true, 'filters' => [], ], [ @@ -1545,7 +1573,7 @@ $commonCollections = [ 'format' => '', 'size' => 0, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], @@ -1556,7 +1584,7 @@ $commonCollections = [ 'format' => '', 'size' => 0, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => false, 'array' => false, 'filters' => [], @@ -1578,14 +1606,14 @@ $commonCollections = [ '$id' => ID::custom('_key_providerId'), 'type' => Database::INDEX_KEY, 'attributes' => ['providerId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => ID::custom('_key_providerInternalId'), 'type' => Database::INDEX_KEY, 'attributes' => ['providerInternalId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ @@ -1657,21 +1685,32 @@ $commonCollections = [ 'default' => null, 'array' => false, 'filters' => ['subQueryTopicTargets'], - ] + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ '$id' => ID::custom('_key_providerId'), 'type' => Database::INDEX_KEY, 'attributes' => ['providerId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => ID::custom('_key_providerInternalId'), 'type' => Database::INDEX_KEY, 'attributes' => ['providerInternalId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ @@ -1682,12 +1721,12 @@ $commonCollections = [ 'orders' => [], ], [ - '$id' => ID::custom('_key_description'), + '$id' => ID::custom('_key_search'), 'type' => Database::INDEX_FULLTEXT, - 'attributes' => ['description'], + 'attributes' => ['name'], 'lengths' => [], - 'orders' => [], - ], + 'orders' => [Database::ORDER_ASC], + ] ], ], @@ -1823,7 +1862,7 @@ $commonCollections = [ 'filters' => [], ], [ - '$id' => ID::custom('providerType'), + '$id' => ID::custom('provider'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => Database::LENGTH_KEY, @@ -1831,7 +1870,7 @@ $commonCollections = [ 'required' => false, 'default' => null, 'array' => false, - 'filters' => ['subQueryProviderType'], + 'filters' => ['subQueryProvider'], ], [ '$id' => ID::custom('identifier'), @@ -1850,14 +1889,14 @@ $commonCollections = [ '$id' => ID::custom('_key_userId'), 'type' => Database::INDEX_KEY, 'attributes' => ['userId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => ID::custom('_key_userInternalId'), 'type' => Database::INDEX_KEY, 'attributes' => ['userInternalId'], - 'lengths' => [128], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ @@ -5516,4 +5555,4 @@ $collections = [ 'databases' => $dbCollections ]; -return $collections; +return $collections; \ No newline at end of file diff --git a/app/config/roles.php b/app/config/roles.php index abc00b55bf..3ce716d27e 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -21,6 +21,10 @@ $member = [ 'avatars.read', 'execution.read', 'execution.write', + 'targets.read', + 'targets.write', + 'subscribers.write', + 'subscribers.read' ]; $admins = [ @@ -60,6 +64,16 @@ $admins = [ 'vcs.read', 'vcs.write', 'assistant.read', + 'targets.read', + 'targets.write', + 'providers.write', + 'providers.read', + 'messages.write', + 'messages.read', + 'topics.write', + 'topics.read', + 'subscribers.write', + 'subscribers.read' ]; return [ @@ -99,4 +113,4 @@ return [ 'label' => 'Applications', 'scopes' => ['global', 'health.read', 'graphql'], ], -]; +]; \ No newline at end of file diff --git a/app/config/scopes.php b/app/config/scopes.php index ddc1de21f3..af27865b0a 100644 --- a/app/config/scopes.php +++ b/app/config/scopes.php @@ -127,4 +127,4 @@ return [ // List of publicly visible scopes 'assistant.read' => [ 'description' => 'Access to read the Assistant service', ], -]; +]; \ No newline at end of file diff --git a/app/init.php b/app/init.php index f2d7bc7db4..c10d9deaaa 100644 --- a/app/init.php +++ b/app/init.php @@ -543,6 +543,45 @@ Database::addFilter( ])); } ); + +Database::addFilter( + 'subQueryProvider', + function (mixed $value) { + return null; + }, + function (mixed $value, Document $document, Database $database) { + $provider = Authorization::skip(fn () => $database + ->getDocument( + 'providers', + $document->getAttribute('providerId'), + )); + if (!$provider->isEmpty()) { + return $provider; + } + return null; + } +); + +Database::addFilter( + 'subQueryTopicTargets', + function (mixed $value) { + return null; + }, + function (mixed $value, Document $document, Database $database) { + $targetIds = Authorization::skip(fn () => \array_map( + fn ($document) => $document->getAttribute('targetId'), + $database + ->find('subscribers', [ + Query::equal('topicInternalId', [$document->getInternalId()]), + Query::limit(APP_LIMIT_SUBQUERY), + ]) + )); + if (\count($targetIds) > 0) { + return $database->find('targets', [Query::equal('$id', $targetIds)]); + } + return []; + } +); /** * DB Formats */ @@ -1453,4 +1492,4 @@ App::setResource('requestTimestamp', function ($request) { } } return $requestTimestamp; -}, ['request']); +}, ['request']); \ No newline at end of file From 2f2875e3c0929e6d719420937ef5f2422496667e Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 12 Sep 2023 21:19:21 +0530 Subject: [PATCH 072/196] lint fix --- app/config/collections.php | 2 +- app/config/roles.php | 2 +- app/init.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 2c298e986c..fd101ac440 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -5555,4 +5555,4 @@ $collections = [ 'databases' => $dbCollections ]; -return $collections; \ No newline at end of file +return $collections; diff --git a/app/config/roles.php b/app/config/roles.php index 3ce716d27e..6e09d838de 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -113,4 +113,4 @@ return [ 'label' => 'Applications', 'scopes' => ['global', 'health.read', 'graphql'], ], -]; \ No newline at end of file +]; diff --git a/app/init.php b/app/init.php index c10d9deaaa..072384919b 100644 --- a/app/init.php +++ b/app/init.php @@ -1492,4 +1492,4 @@ App::setResource('requestTimestamp', function ($request) { } } return $requestTimestamp; -}, ['request']); \ No newline at end of file +}, ['request']); From 5136724a29fd982b9115dd864cb743d42c99c477 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 12 Sep 2023 22:02:19 +0530 Subject: [PATCH 073/196] fix default,type index --- app/config/collections.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/collections.php b/app/config/collections.php index fd101ac440..eebd6d31d5 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1482,7 +1482,7 @@ $commonCollections = [ [ '$id' => ID::custom('_key_default_type'), 'type' => Database::INDEX_KEY, - 'attributes' => ['default, type'], + 'attributes' => ['default','type'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], From 497586378f15c4ce20602aeeee9fb914ad1c44ad Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 12 Sep 2023 22:05:14 +0530 Subject: [PATCH 074/196] removes unnecessary config load --- app/init.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/init.php b/app/init.php index ea1442d2d7..6d746fbe0b 100644 --- a/app/init.php +++ b/app/init.php @@ -257,7 +257,6 @@ Config::load('storage-logos', __DIR__ . '/config/storage/logos.php'); Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php'); Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php'); Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php'); -Config::load('messagingProviders', __DIR__ . '/config/messagingProviders.php'); $user = App::getEnv('_APP_REDIS_USER', ''); $pass = App::getEnv('_APP_REDIS_PASS', ''); From 7dd25f60f30ceb4b52db9b8814ea2812eb6a5445 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 12 Sep 2023 23:30:04 +0530 Subject: [PATCH 075/196] update console submodule changes --- app/console | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/console b/app/console index 9174d8f8cb..88b6d59051 160000 --- a/app/console +++ b/app/console @@ -1 +1 @@ -Subproject commit 9174d8f8cb584744dd7a53f69d324f490ee82ee3 +Subproject commit 88b6d59051992ed86183ee83d77bf678d1cb73bf From 11a458f1df30327b88295285f0b0b102c61fe895 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 13 Sep 2023 00:06:18 +0530 Subject: [PATCH 076/196] change providers to authProviders in remaining places --- app/controllers/api/users.php | 2 +- src/Appwrite/Utopia/Response.php | 2 +- src/Appwrite/Utopia/Response/Filters/V16.php | 6 +++--- src/Appwrite/Utopia/Response/Model/Project.php | 2 +- tests/e2e/Services/Projects/ProjectsConsoleClientTest.php | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index c6d9b2d4e3..5dd1ab44d8 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1255,7 +1255,7 @@ App::get('/v1/users/usage') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_USAGE_USERS) ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true) - ->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('providers', [])))), true), 'Provider Name.', true) + ->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('authProviders', [])))), true), 'Provider Name.', true) ->inject('response') ->inject('dbForProject') ->inject('register') diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 7a2a040d94..85db23b385 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -333,7 +333,7 @@ class Response extends SwooleResponse ->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT, true, false)) ->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK, true, false)) ->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false)) - ->setModel(new BaseList('Providers List', self::MODEL_AUTH_PROVIDER_LIST, 'platforms', self::MODEL_AUTH_PROVIDER, true, false)) + ->setModel(new BaseList('Auth Providers List', self::MODEL_AUTH_PROVIDER_LIST, 'platforms', self::MODEL_AUTH_PROVIDER, true, false)) ->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM, true, false)) ->setModel(new BaseList('Countries List', self::MODEL_COUNTRY_LIST, 'countries', self::MODEL_COUNTRY)) ->setModel(new BaseList('Continents List', self::MODEL_CONTINENT_LIST, 'continents', self::MODEL_CONTINENT)) diff --git a/src/Appwrite/Utopia/Response/Filters/V16.php b/src/Appwrite/Utopia/Response/Filters/V16.php index 6943bd8f4d..66cf650a78 100644 --- a/src/Appwrite/Utopia/Response/Filters/V16.php +++ b/src/Appwrite/Utopia/Response/Filters/V16.php @@ -88,9 +88,9 @@ class V16 extends Filter protected function parseProject(array $content) { - foreach ($content['providers'] ?? [] as $i => $provider) { - $content['providers'][$i]['name'] = \ucfirst($provider['key']); - unset($content['providers'][$i]['key']); + foreach ($content['authProviders'] ?? [] as $i => $provider) { + $content['authProviders'][$i]['name'] = \ucfirst($provider['key']); + unset($content['authProviders'][$i]['key']); } $content['domains'] = []; diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 5f78ff82cc..ae199d77f7 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -348,7 +348,7 @@ class Project extends Model ]); } - $document->setAttribute("providers", $projectProviders); + $document->setAttribute("authProviders", $projectProviders); return $document; } diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index d26d226dd3..eefc766b94 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -825,7 +825,7 @@ class ProjectsConsoleClientTest extends Scope foreach ($providers as $key => $provider) { $asserted = false; - foreach ($response['body']['providers'] as $responseProvider) { + foreach ($response['body']['authProviders'] as $responseProvider) { if ($responseProvider['key'] === $key) { $this->assertEquals('AppId-' . ucfirst($key), $responseProvider['appId']); $this->assertEquals('Secret-' . ucfirst($key), $responseProvider['secret']); @@ -867,7 +867,7 @@ class ProjectsConsoleClientTest extends Scope $i = 0; foreach ($providers as $key => $provider) { $asserted = false; - foreach ($response['body']['providers'] as $responseProvider) { + foreach ($response['body']['authProviders'] as $responseProvider) { if ($responseProvider['key'] === $key) { // On first provider, test enabled=false $this->assertEquals($i !== 0, $responseProvider['enabled']); From d14fbde9e70cc79e835c3e1a0d5b3bff4bc330ca Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 13 Sep 2023 00:40:51 +0530 Subject: [PATCH 077/196] removes provider sub query --- app/config/collections.php | 11 ----------- app/init.php | 18 ------------------ 2 files changed, 29 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index eebd6d31d5..3deb29636a 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1861,17 +1861,6 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], - [ - '$id' => ID::custom('provider'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => ['subQueryProvider'], - ], [ '$id' => ID::custom('identifier'), 'type' => Database::VAR_STRING, diff --git a/app/init.php b/app/init.php index 072384919b..dde6d2a199 100644 --- a/app/init.php +++ b/app/init.php @@ -544,24 +544,6 @@ Database::addFilter( } ); -Database::addFilter( - 'subQueryProvider', - function (mixed $value) { - return null; - }, - function (mixed $value, Document $document, Database $database) { - $provider = Authorization::skip(fn () => $database - ->getDocument( - 'providers', - $document->getAttribute('providerId'), - )); - if (!$provider->isEmpty()) { - return $provider; - } - return null; - } -); - Database::addFilter( 'subQueryTopicTargets', function (mixed $value) { From 851afae29a2d2054cf701d311b270aa2b6271e04 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 13 Sep 2023 00:50:16 +0530 Subject: [PATCH 078/196] change test provider to authProviders --- tests/unit/Utopia/Response/Filters/V16Test.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/Utopia/Response/Filters/V16Test.php b/tests/unit/Utopia/Response/Filters/V16Test.php index fba3b69535..96c615f452 100644 --- a/tests/unit/Utopia/Response/Filters/V16Test.php +++ b/tests/unit/Utopia/Response/Filters/V16Test.php @@ -154,9 +154,9 @@ class V16Test extends TestCase public function projectProvider(): array { return [ - 'providers' => [ + 'authProviders' => [ [ - 'providers' => [ + 'authProviders' => [ [ 'key' => 'github', 'name' => 'GitHub', @@ -167,7 +167,7 @@ class V16Test extends TestCase ], ], [ - 'providers' => [ + 'authProviders' => [ [ 'name' => 'Github', 'appId' => 'client_id', From d742b0c0a9dc2522c0b6d73a35b49b699d1d3901 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 13 Sep 2023 00:53:25 +0530 Subject: [PATCH 079/196] removes provider type from create user target --- app/controllers/api/users.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 2618941ba2..78a0e086d4 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -430,7 +430,6 @@ App::post('/v1/users/:userId/targets') ], 'providerId' => $providerId, 'providerInternalId' => $provider->getInternalId(), - 'providerType' => null, 'userId' => $userId, 'userInternalId' => $user->getInternalId(), 'identifier' => $identifier, From 9b6fc440d944016d7102b10cfc485eafce07ffa4 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 13 Sep 2023 16:57:59 +0530 Subject: [PATCH 080/196] Review changes and adds enabled in providers collection --- app/config/collections.php | 11 +++++++++++ src/Appwrite/Utopia/Response/Model/Message.php | 14 +++++++------- src/Appwrite/Utopia/Response/Model/Project.php | 2 +- src/Appwrite/Utopia/Response/Model/Provider.php | 11 +++++++---- src/Appwrite/Utopia/Response/Model/Subscriber.php | 5 ----- src/Appwrite/Utopia/Response/Model/Target.php | 11 ----------- src/Appwrite/Utopia/Response/Model/Topic.php | 5 ----- 7 files changed, 26 insertions(+), 33 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 6050afd95f..ed73c222a7 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1427,6 +1427,17 @@ $commonCollections = [ 'default' => false, 'array' => false, ], + [ + '$id' => ID::custom('enabled'), + 'type' => Database::VAR_BOOLEAN, + 'signed' => true, + 'size' => 0, + 'format' => '', + 'filters' => [], + 'required' => true, + 'default' => true, + 'array' => false, + ], [ '$id' => ID::custom('credentials'), 'type' => Database::VAR_STRING, diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 150e837853..08d8af55ff 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -24,7 +24,7 @@ class Message extends Any ]) ->addRule('providerId', [ 'type' => self::TYPE_STRING, - 'description' => 'Provider Id for the message.', + 'description' => 'Provider ID for the message.', 'default' => '', 'example' => '5e5ea5c16897e', ]) @@ -40,26 +40,26 @@ class Message extends Any 'description' => 'Recipient of message.', 'required' => false, 'default' => DateTime::now(), - 'example' => DateTime::now(), + 'example' => self::TYPE_DATETIME_EXAMPLE, ]) - ->addRule('deliveryError', [ + ->addRule('deliveryErrors', [ 'type' => self::TYPE_STRING, - 'description' => 'Delivery error if any.', + 'description' => 'Delivery errors if any.', 'required' => false, 'default' => '', 'array' => true, - 'example' => 'Provider not valid.', + 'example' => 'Credentials not valid.', ]) ->addRule('deliveredTo', [ 'type' => self::TYPE_INTEGER, 'description' => 'Number of recipients the message was delivered to.', - 'default' => '', + 'default' => 0, 'example' => 1, ]) ->addRule('delivered', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Status of delivery.', - 'default' => '', + 'default' => false, 'example' => true, ]); } diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index ae199d77f7..807c1fb574 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -348,7 +348,7 @@ class Project extends Model ]); } - $document->setAttribute("authProviders", $projectProviders); + $document->setAttribute('authProviders', $projectProviders); return $document; } diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index 668db553fc..7921786394 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -7,9 +7,6 @@ use Appwrite\Utopia\Response\Model; class Provider extends Model { - /** - * @var bool - */ protected bool $public = false; public function __construct() @@ -36,7 +33,13 @@ class Provider extends Model ->addRule('default', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Is this a pre-configured provider instance?', - 'default' => '', + 'default' => false, + 'example' => true, + ]) + ->addRule('enabled', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is provider enabled?', + 'default' => true, 'example' => true, ]) ->addRule('type', [ diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index 8e4ef74d74..2f34619cb4 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -7,11 +7,6 @@ use Appwrite\Utopia\Response\Model; class Subscriber extends Model { - /** - * @var bool - */ - protected bool $public = false; - public function __construct() { $this diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php index 272c929e11..5750f57eba 100644 --- a/src/Appwrite/Utopia/Response/Model/Target.php +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -7,11 +7,6 @@ use Appwrite\Utopia\Response\Model; class Target extends Model { - /** - * @var bool - */ - protected bool $public = false; - public function __construct() { $this @@ -34,12 +29,6 @@ class Target extends Model 'default' => '', 'example' => '259125845563242502', ]) - ->addRule('providerType', [ - 'type' => self::TYPE_STRING, - 'description' => 'The type of provider supported by this target.', - 'default' => '', - 'example' => 'sms', - ]) ->addRule('identifier', [ 'type' => self::TYPE_STRING, 'description' => 'The target identifier.', diff --git a/src/Appwrite/Utopia/Response/Model/Topic.php b/src/Appwrite/Utopia/Response/Model/Topic.php index c0996fcf55..3a6e832f5c 100644 --- a/src/Appwrite/Utopia/Response/Model/Topic.php +++ b/src/Appwrite/Utopia/Response/Model/Topic.php @@ -7,11 +7,6 @@ use Appwrite\Utopia\Response\Model; class Topic extends Model { - /** - * @var bool - */ - protected bool $public = false; - public function __construct() { $this From 0066216bef1757562282fe6852094e80e3ad3c7c Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 13 Sep 2023 17:47:38 +0530 Subject: [PATCH 081/196] adds enabled param for provider endpoints and review changes --- app/controllers/api/messaging.php | 124 +++++++++++++++++++++++------- 1 file changed, 97 insertions(+), 27 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 5355b56721..dbf149fd31 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -107,11 +107,12 @@ App::post('/v1/messaging/providers/mailgun') ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.') ->param('domain', '', new Text(0), 'Mailgun Domain.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, string $domain, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ @@ -120,6 +121,7 @@ App::post('/v1/messaging/providers/mailgun') 'provider' => 'mailgun', 'type' => 'email', 'default' => $default, + 'enabled' => $enabled, 'credentials' => [ 'apiKey' => $apiKey, 'domain' => $domain, @@ -161,11 +163,12 @@ App::patch('/v1/messaging/providers/:id/mailgun') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, string $apiKey, string $domain, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -181,8 +184,12 @@ App::patch('/v1/messaging/providers/:id/mailgun') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if ($apiKey || $domain) { - // Check if all five variables are present + // Check if all credential variables are present if ($apiKey && $domain) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, @@ -217,10 +224,11 @@ App::post('/v1/messaging/providers/sendgrid') ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -228,6 +236,7 @@ App::post('/v1/messaging/providers/sendgrid') 'provider' => 'sendgrid', 'type' => 'email', 'default' => $default, + 'enabled' => $enabled, 'credentials' => [ 'apiKey' => $apiKey, ], @@ -268,10 +277,11 @@ App::patch('/v1/messaging/providers/:id/sendgrid') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -287,6 +297,10 @@ App::patch('/v1/messaging/providers/:id/sendgrid') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if ($apiKey) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, @@ -319,11 +333,12 @@ App::post('/v1/messaging/providers/msg91') ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, string $senderId, string $authKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $senderId, string $authKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -331,6 +346,7 @@ App::post('/v1/messaging/providers/msg91') 'provider' => 'msg91', 'type' => 'sms', 'default' => $default, + 'enabled' => $enabled, 'credentials' => [ 'senderId' => $senderId, 'authKey' => $authKey, @@ -372,11 +388,12 @@ App::patch('/v1/messaging/providers/:id/msg91') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, string $senderId, string $authKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -392,8 +409,12 @@ App::patch('/v1/messaging/providers/:id/msg91') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if ($senderId || $authKey) { - // Check if all five variables are present + // Check if all credential variables are present if ($senderId && $authKey) { $provider->setAttribute('credentials', [ 'senderId' => $senderId, @@ -428,11 +449,12 @@ App::post('/v1/messaging/providers/telesign') ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, string $username, string $password, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -440,6 +462,7 @@ App::post('/v1/messaging/providers/telesign') 'provider' => 'telesign', 'type' => 'sms', 'default' => $default, + 'enabled' => $enabled, 'credentials' => [ 'username' => $username, 'password' => $password, @@ -481,11 +504,12 @@ App::patch('/v1/messaging/providers/:id/telesign') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Telesign username.', true) ->param('password', '', new Text(0), 'Telesign password.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $username, string $password, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -501,8 +525,12 @@ App::patch('/v1/messaging/providers/:id/telesign') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if ($username || $password) { - // Check if all five variables are present + // Check if all credential variables are present if ($username && $password) { $provider->setAttribute('credentials', [ 'username' => $username, @@ -537,11 +565,12 @@ App::post('/v1/messaging/providers/textmagic') ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Textmagic username.') ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, string $username, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -549,6 +578,7 @@ App::post('/v1/messaging/providers/textmagic') 'provider' => 'text-magic', 'type' => 'sms', 'default' => $default, + 'enabled' => $enabled, 'credentials' => [ 'username' => $username, 'apiKey' => $apiKey, @@ -590,11 +620,12 @@ App::patch('/v1/messaging/providers/:id/textmagic') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -610,8 +641,12 @@ App::patch('/v1/messaging/providers/:id/textmagic') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if ($username || $apiKey) { - // Check if all five variables are present + // Check if all credential variables are present if ($username && $apiKey) { $provider->setAttribute('credentials', [ 'username' => $username, @@ -646,11 +681,12 @@ App::post('/v1/messaging/providers/twilio') ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -658,6 +694,7 @@ App::post('/v1/messaging/providers/twilio') 'provider' => 'twilio', 'type' => 'sms', 'default' => $default, + 'enabled' => $enabled, 'credentials' => [ 'accountSid' => $accountSid, 'authToken' => $authToken, @@ -699,11 +736,12 @@ App::patch('/v1/messaging/providers/:id/twilio') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -719,8 +757,12 @@ App::patch('/v1/messaging/providers/:id/twilio') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if ($accountSid || $authToken) { - // Check if all five variables are present + // Check if all credential variables are present if ($accountSid && $authToken) { $provider->setAttribute('credentials', [ 'accountSid' => $accountSid, @@ -755,11 +797,12 @@ App::post('/v1/messaging/providers/vonage') ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -767,6 +810,7 @@ App::post('/v1/messaging/providers/vonage') 'provider' => 'vonage', 'type' => 'sms', 'default' => $default, + 'enabled' => $enabled, 'credentials' => [ 'apiKey' => $apiKey, 'apiSecret' => $apiSecret, @@ -808,11 +852,12 @@ App::patch('/v1/messaging/providers/:id/vonage') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -828,8 +873,12 @@ App::patch('/v1/messaging/providers/:id/vonage') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if ($apiKey || $apiSecret) { - // Check if all five variables are present + // Check if all credential variables are present if ($apiKey && $apiSecret) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, @@ -867,10 +916,11 @@ App::post('/v1/messaging/providers/fcm') ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('serverKey', '', new Text(0), 'FCM Server Key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -878,6 +928,7 @@ App::post('/v1/messaging/providers/fcm') 'provider' => 'fcm', 'type' => 'push', 'default' => $default, + 'enabled' => $enabled, 'credentials' => [ 'serverKey' => $serverKey, ], @@ -918,10 +969,11 @@ App::patch('/v1/messaging/providers/:id/fcm') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -937,6 +989,10 @@ App::patch('/v1/messaging/providers/:id/fcm') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if ($serverKey) { $provider->setAttribute('credentials', ['serverKey' => $serverKey]); } @@ -964,6 +1020,7 @@ App::post('/v1/messaging/providers/apns') ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('authKey', '', new Text(0), 'APNS authentication key.') ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') ->param('teamId', '', new Text(0), 'APNS team ID.') @@ -971,7 +1028,7 @@ App::post('/v1/messaging/providers/apns') ->param('endpoint', '', new Text(0), 'APNS endpoint.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -979,6 +1036,7 @@ App::post('/v1/messaging/providers/apns') 'provider' => 'apns', 'type' => 'push', 'default' => $default, + 'enabled' => $enabled, 'credentials' => [ 'authKey' => $authKey, 'authKeyId' => $authKeyId, @@ -1023,6 +1081,7 @@ App::patch('/v1/messaging/providers/:id/apns') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('authKey', '', new Text(0), 'APNS authentication key.', true) ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) ->param('teamId', '', new Text(0), 'APNS team ID.', true) @@ -1030,7 +1089,7 @@ App::patch('/v1/messaging/providers/:id/apns') ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -1046,8 +1105,12 @@ App::patch('/v1/messaging/providers/:id/apns') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { - // Check if all five variables are present + // Check if all credential variables are present if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { $provider->setAttribute('credentials', [ 'authKey' => $authKey, @@ -1090,10 +1153,11 @@ App::post('/v1/messaging/providers/general') ->param('name', '', new Text(128), 'Provider name.') ->param('type', '', new WhiteList(['push', 'email', 'sms']), 'Provider type.') ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('credentials', '', new JSON(), 'Provider credentials object.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $provider, string $name, string $type, bool $default, array $credentials, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $provider, string $name, string $type, bool $default, bool $enabled, array $credentials, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -1101,6 +1165,7 @@ App::post('/v1/messaging/providers/general') 'provider' => $provider, 'type' => $type, 'default' => $default, + 'enabled' => $enabled, 'credentials' => $credentials, ]); @@ -1139,10 +1204,11 @@ App::patch('/v1/messaging/providers/:id/general') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('credentials', '', new JSON(), 'Provider credentials.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, array $credentials, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, array $credentials, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -1153,6 +1219,10 @@ App::patch('/v1/messaging/providers/:id/general') $provider->setAttribute('name', $name); } + if ($enabled === false) { + $provider->setAttribute('enabled', $enabled); + } + if (!empty($credentials)) { $provider->setAttribute('credentials', $credentials); } From 2fe94be4c183570a84aa2a62c782f0b94e8883fb Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 14 Sep 2023 16:34:53 +0530 Subject: [PATCH 082/196] review changes --- src/Appwrite/Utopia/Response/Model/Message.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 08d8af55ff..971f148f7e 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -8,11 +8,6 @@ use Utopia\Database\DateTime; class Message extends Any { - /** - * @var bool - */ - protected bool $public = false; - public function __construct() { $this @@ -30,14 +25,14 @@ class Message extends Any ]) ->addRule('to', [ 'type' => self::TYPE_STRING, - 'description' => 'Recipient of message.', + 'description' => 'Message recipients.', 'default' => '', 'array' => true, 'example' => ['user-1'], ]) ->addRule('deliveryTime', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Recipient of message.', + 'description' => 'Time the message is delivered at.', 'required' => false, 'default' => DateTime::now(), 'example' => self::TYPE_DATETIME_EXAMPLE, From 7d51da2e69e0e8b0d4751076457b1a23f64b43e4 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 14 Sep 2023 16:43:38 +0530 Subject: [PATCH 083/196] review changes --- src/Appwrite/Utopia/Response/Model/Message.php | 2 +- src/Appwrite/Utopia/Response/Model/Provider.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 971f148f7e..6eebbcd793 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -43,7 +43,7 @@ class Message extends Any 'required' => false, 'default' => '', 'array' => true, - 'example' => 'Credentials not valid.', + 'example' => ['Failed to send message to target 5e5ea5c16897e: Credentials not valid.'], ]) ->addRule('deliveredTo', [ 'type' => self::TYPE_INTEGER, diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index 7921786394..e33e5a253d 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -7,8 +7,6 @@ use Appwrite\Utopia\Response\Model; class Provider extends Model { - protected bool $public = false; - public function __construct() { $this From 25fc64c4ab2ca4c90ee3397ea527f96e9d43264e Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 15 Sep 2023 02:28:32 +0530 Subject: [PATCH 084/196] moves provider to top level in events config --- app/config/events.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/config/events.php b/app/config/events.php index 4eed1257de..4aaa324e9c 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -258,20 +258,6 @@ return [ 'create' => [ '$description' => 'This event triggers when a message is created.', ], - 'providers' => [ - '$model' => Response::MODEL_PROVIDER, - '$resource' => true, - '$description' => 'This event triggers on any provider event.', - 'create' => [ - '$description' => 'This event triggers when a provider is created.', - ], - 'update' => [ - '$description' => 'This event triggers when a provider is updated.', - ], - 'delete' => [ - '$description' => 'This event triggers when a provider is deleted.' - ], - ], 'topics' => [ '$model' => Response::MODEL_TOPIC, '$resource' => true, @@ -296,6 +282,20 @@ return [ ], ], + 'providers' => [ + '$model' => Response::MODEL_PROVIDER, + '$resource' => true, + '$description' => 'This event triggers on any provider event.', + 'create' => [ + '$description' => 'This event triggers when a provider is created.', + ], + 'update' => [ + '$description' => 'This event triggers when a provider is updated.', + ], + 'delete' => [ + '$description' => 'This event triggers when a provider is deleted.' + ], + ], 'rules' => [ '$model' => Response::MODEL_PROXY_RULE, '$resource' => true, From bd36a09473087b5a3cb715ce6c0127e508620f0f Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 19 Sep 2023 15:36:40 +0530 Subject: [PATCH 085/196] adds search in messaging controllers, updated mailgun endpoint with isEu param --- app/controllers/api/messaging.php | 63 +++++++++++++++------- composer.lock | 86 +++++++++++++++---------------- 2 files changed, 87 insertions(+), 62 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index dbf149fd31..a3a0c48b8c 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -108,11 +108,12 @@ App::post('/v1/messaging/providers/mailgun') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('isEuRegion', false, new Boolean(), 'Set as eu region.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.') ->param('domain', '', new Text(0), 'Mailgun Domain.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, bool $isEuRegion, string $apiKey, string $domain, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ @@ -122,9 +123,11 @@ App::post('/v1/messaging/providers/mailgun') 'type' => 'email', 'default' => $default, 'enabled' => $enabled, + 'search' => $providerId . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email', 'credentials' => [ 'apiKey' => $apiKey, 'domain' => $domain, + 'isEuRegion' => $isEuRegion, ], ]); @@ -164,11 +167,12 @@ App::patch('/v1/messaging/providers/:id/mailgun') ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('isEuRegion', false, new Boolean(), 'Set as eu region.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, bool $enabled, bool $isEuRegion, string $apiKey, string $domain, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -182,9 +186,19 @@ App::patch('/v1/messaging/providers/:id/mailgun') if ($name) { $provider->setAttribute('name', $name); + $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email'); } - if ($enabled === false) { + if ($isEuRegion === true || $isEuRegion === false) { + $credentials = $provider->getAttribute('credentials'); + $provider->setAttribute('credentials', [ + 'isEuRegion' => $isEuRegion, + 'apiKey' => $credentials['apiKey'], + 'domain' => $credentials['domain'], + ]); + } + + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -237,6 +251,7 @@ App::post('/v1/messaging/providers/sendgrid') 'type' => 'email', 'default' => $default, 'enabled' => $enabled, + 'search' => $providerId . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email', 'credentials' => [ 'apiKey' => $apiKey, ], @@ -295,9 +310,10 @@ App::patch('/v1/messaging/providers/:id/sendgrid') if ($name) { $provider->setAttribute('name', $name); + $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email'); } - if ($enabled === false) { + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -345,6 +361,7 @@ App::post('/v1/messaging/providers/msg91') 'name' => $name, 'provider' => 'msg91', 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms', 'default' => $default, 'enabled' => $enabled, 'credentials' => [ @@ -407,9 +424,10 @@ App::patch('/v1/messaging/providers/:id/msg91') if ($name) { $provider->setAttribute('name', $name); + $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms'); } - if ($enabled === false) { + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -461,6 +479,7 @@ App::post('/v1/messaging/providers/telesign') 'name' => $name, 'provider' => 'telesign', 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms', 'default' => $default, 'enabled' => $enabled, 'credentials' => [ @@ -523,9 +542,10 @@ App::patch('/v1/messaging/providers/:id/telesign') if ($name) { $provider->setAttribute('name', $name); + $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms'); } - if ($enabled === false) { + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -577,6 +597,7 @@ App::post('/v1/messaging/providers/textmagic') 'name' => $name, 'provider' => 'text-magic', 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'text-magic' . ' ' . 'sms', 'default' => $default, 'enabled' => $enabled, 'credentials' => [ @@ -639,9 +660,10 @@ App::patch('/v1/messaging/providers/:id/textmagic') if ($name) { $provider->setAttribute('name', $name); + $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'textmagic' . ' ' . 'sms'); } - if ($enabled === false) { + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -693,6 +715,7 @@ App::post('/v1/messaging/providers/twilio') 'name' => $name, 'provider' => 'twilio', 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms', 'default' => $default, 'enabled' => $enabled, 'credentials' => [ @@ -755,9 +778,10 @@ App::patch('/v1/messaging/providers/:id/twilio') if ($name) { $provider->setAttribute('name', $name); + $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms'); } - if ($enabled === false) { + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -809,6 +833,7 @@ App::post('/v1/messaging/providers/vonage') 'name' => $name, 'provider' => 'vonage', 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms', 'default' => $default, 'enabled' => $enabled, 'credentials' => [ @@ -871,9 +896,10 @@ App::patch('/v1/messaging/providers/:id/vonage') if ($name) { $provider->setAttribute('name', $name); + $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms'); } - if ($enabled === false) { + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -927,6 +953,7 @@ App::post('/v1/messaging/providers/fcm') 'name' => $name, 'provider' => 'fcm', 'type' => 'push', + 'search' => $providerId . ' ' . $name . ' ' . 'fcm' . ' ' . 'push', 'default' => $default, 'enabled' => $enabled, 'credentials' => [ @@ -987,9 +1014,10 @@ App::patch('/v1/messaging/providers/:id/fcm') if ($name) { $provider->setAttribute('name', $name); + $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'fcm' . ' ' . 'push'); } - if ($enabled === false) { + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -1035,6 +1063,7 @@ App::post('/v1/messaging/providers/apns') 'name' => $name, 'provider' => 'apns', 'type' => 'push', + 'search' => $providerId . ' ' . $name . ' ' . 'apns' . ' ' . 'push', 'default' => $default, 'enabled' => $enabled, 'credentials' => [ @@ -1103,9 +1132,10 @@ App::patch('/v1/messaging/providers/:id/apns') if ($name) { $provider->setAttribute('name', $name); + $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'apns' . ' ' . 'push'); } - if ($enabled === false) { + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -1219,7 +1249,7 @@ App::patch('/v1/messaging/providers/:id/general') $provider->setAttribute('name', $name); } - if ($enabled === false) { + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -1280,9 +1310,8 @@ App::post('/v1/messaging/messages/email') ->param('to', [], new ArrayList(new Text(0)), 'Email Recepient.') ->param('subject', '', new Text(0), 'Email Subject.') ->param('content', '', new Text(0), 'Email Content.') - ->param('from', '', new Text(0), 'Email from.') + ->param('from', '', new Text(0), 'Email from.', true) ->param('html', false, new Boolean(false), 'Is content of type HTML', true) - ->param('deliveryTime', '', new DatetimeValidator(), 'Delivery time of the message', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') @@ -1304,11 +1333,7 @@ App::post('/v1/messaging/messages/email') 'from' => $from, 'html' => $html ], - 'deliveryTime' => $deliveryTime, - 'deliveryErrors' => null, - 'deliveredTo' => null, - 'delivered' => false, - 'search' => null, + 'search' => $subject . ' ' . $from, ])); $messaging diff --git a/composer.lock b/composer.lock index 8eb26d06d7..279847dedc 100644 --- a/composer.lock +++ b/composer.lock @@ -65,16 +65,16 @@ }, { "name": "appwrite/appwrite", - "version": "8.0.0", + "version": "10.0.0", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-for-php.git", - "reference": "2b9e966edf35c4061179ed98ea364698ab30de8b" + "reference": "461eedf4efd502dc905c3055f36f0e3583f67390" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/2b9e966edf35c4061179ed98ea364698ab30de8b", - "reference": "2b9e966edf35c4061179ed98ea364698ab30de8b", + "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/461eedf4efd502dc905c3055f36f0e3583f67390", + "reference": "461eedf4efd502dc905c3055f36f0e3583f67390", "shasum": "" }, "require": { @@ -99,10 +99,10 @@ "support": { "email": "team@appwrite.io", "issues": "https://github.com/appwrite/sdk-for-php/issues", - "source": "https://github.com/appwrite/sdk-for-php/tree/8.0.0", + "source": "https://github.com/appwrite/sdk-for-php/tree/10.0.0", "url": "https://appwrite.io/support" }, - "time": "2023-04-12T10:16:28+00:00" + "time": "2023-09-07T23:28:31+00:00" }, { "name": "appwrite/php-clamav", @@ -2152,16 +2152,16 @@ }, { "name": "utopia-php/database", - "version": "0.43.1", + "version": "0.43.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "cc0247f4f0c402b39f663bf9f77b29d69b95f9d6" + "reference": "f2626acd42665a9987c94af1c93bf20c28d55c9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/cc0247f4f0c402b39f663bf9f77b29d69b95f9d6", - "reference": "cc0247f4f0c402b39f663bf9f77b29d69b95f9d6", + "url": "https://api.github.com/repos/utopia-php/database/zipball/f2626acd42665a9987c94af1c93bf20c28d55c9d", + "reference": "f2626acd42665a9987c94af1c93bf20c28d55c9d", "shasum": "" }, "require": { @@ -2202,9 +2202,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.43.1" + "source": "https://github.com/utopia-php/database/tree/0.43.2" }, - "time": "2023-09-01T20:38:36+00:00" + "time": "2023-09-07T19:04:33+00:00" }, { "name": "utopia-php/domains", @@ -2520,12 +2520,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "4ebebe97d80bb1de10d362c2464ba28717d333ac" + "reference": "2bb09220d0993a9f8f0afc63ff51382b13d93e18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/4ebebe97d80bb1de10d362c2464ba28717d333ac", - "reference": "4ebebe97d80bb1de10d362c2464ba28717d333ac", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/2bb09220d0993a9f8f0afc63ff51382b13d93e18", + "reference": "2bb09220d0993a9f8f0afc63ff51382b13d93e18", "shasum": "" }, "require": { @@ -2534,8 +2534,8 @@ }, "require-dev": { "laravel/pint": "^1.2", - "phpmailer/phpmailer": "^6.8", - "phpunit/phpunit": "^9.6" + "phpmailer/phpmailer": "6.8.*", + "phpunit/phpunit": "9.6.*" }, "type": "library", "autoload": { @@ -2560,31 +2560,31 @@ "issues": "https://github.com/utopia-php/messaging/issues", "source": "https://github.com/utopia-php/messaging/tree/feat-push" }, - "time": "2023-09-01T14:13:03+00:00" + "time": "2023-09-14T20:29:49+00:00" }, { "name": "utopia-php/migration", - "version": "0.3.2", + "version": "0.3.4", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "49a28adfbb781f0c08f1eaf459a8fbb8ab9fcc70" + "reference": "ade836d61b3e1547bc9f0dc300ee75b24ab49f7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/49a28adfbb781f0c08f1eaf459a8fbb8ab9fcc70", - "reference": "49a28adfbb781f0c08f1eaf459a8fbb8ab9fcc70", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/ade836d61b3e1547bc9f0dc300ee75b24ab49f7a", + "reference": "ade836d61b3e1547bc9f0dc300ee75b24ab49f7a", "shasum": "" }, "require": { - "appwrite/appwrite": "^8.0", - "php": ">=8.0", - "utopia-php/cli": "^0.15.0" + "appwrite/appwrite": "10.0.*", + "php": "8.*", + "utopia-php/cli": "0.*" }, "require-dev": { - "laravel/pint": "^1.10", - "phpunit/phpunit": "^9.3", - "vlucas/phpdotenv": "^5.5" + "laravel/pint": "1.*", + "phpunit/phpunit": "9.*", + "vlucas/phpdotenv": "5.*" }, "type": "library", "autoload": { @@ -2616,9 +2616,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.3.2" + "source": "https://github.com/utopia-php/migration/tree/0.3.4" }, - "time": "2023-08-31T04:11:35+00:00" + "time": "2023-09-14T17:17:55+00:00" }, { "name": "utopia-php/mongo", @@ -4145,16 +4145,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.23.1", + "version": "1.24.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26" + "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/846ae76eef31c6d7790fac9bc399ecee45160b26", - "reference": "846ae76eef31c6d7790fac9bc399ecee45160b26", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6", + "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6", "shasum": "" }, "require": { @@ -4186,22 +4186,22 @@ "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.23.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.0" }, - "time": "2023-08-03T16:32:59+00:00" + "time": "2023-09-07T20:46:32+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.27", + "version": "9.2.28", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" + "reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", - "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef", + "reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef", "shasum": "" }, "require": { @@ -4258,7 +4258,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.28" }, "funding": [ { @@ -4266,7 +4266,7 @@ "type": "github" } ], - "time": "2023-07-26T13:44:30+00:00" + "time": "2023-09-12T14:36:20+00:00" }, { "name": "phpunit/php-file-iterator", @@ -6036,5 +6036,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } From 67397cd763d5bab07788153418507bb0d90c5ef6 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 20 Sep 2023 15:55:22 +0530 Subject: [PATCH 086/196] fix tests and code changes --- app/controllers/api/messaging.php | 60 +++++++++---------- composer.lock | 24 ++++---- .../e2e/Services/Messaging/MessagingBase.php | 15 +++++ 3 files changed, 57 insertions(+), 42 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index a3a0c48b8c..b2585418eb 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -166,13 +166,13 @@ App::patch('/v1/messaging/providers/:id/mailgun') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('isEuRegion', false, new Boolean(), 'Set as eu region.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, bool $isEuRegion, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, bool $isEuRegion, string $apiKey, string $domain, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -184,7 +184,7 @@ App::patch('/v1/messaging/providers/:id/mailgun') throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email'); } @@ -292,11 +292,11 @@ App::patch('/v1/messaging/providers/:id/sendgrid') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, string $apiKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -308,7 +308,7 @@ App::patch('/v1/messaging/providers/:id/sendgrid') throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email'); } @@ -405,12 +405,12 @@ App::patch('/v1/messaging/providers/:id/msg91') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, string $senderId, string $authKey, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, string $senderId, string $authKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -422,7 +422,7 @@ App::patch('/v1/messaging/providers/:id/msg91') throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms'); } @@ -523,12 +523,12 @@ App::patch('/v1/messaging/providers/:id/telesign') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Telesign username.', true) ->param('password', '', new Text(0), 'Telesign password.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -540,7 +540,7 @@ App::patch('/v1/messaging/providers/:id/telesign') throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms'); } @@ -641,12 +641,12 @@ App::patch('/v1/messaging/providers/:id/textmagic') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -658,7 +658,7 @@ App::patch('/v1/messaging/providers/:id/textmagic') throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'textmagic' . ' ' . 'sms'); } @@ -759,12 +759,12 @@ App::patch('/v1/messaging/providers/:id/twilio') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -776,7 +776,7 @@ App::patch('/v1/messaging/providers/:id/twilio') throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms'); } @@ -877,12 +877,12 @@ App::patch('/v1/messaging/providers/:id/vonage') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -894,7 +894,7 @@ App::patch('/v1/messaging/providers/:id/vonage') throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms'); } @@ -996,11 +996,11 @@ App::patch('/v1/messaging/providers/:id/fcm') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, string $serverKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -1012,7 +1012,7 @@ App::patch('/v1/messaging/providers/:id/fcm') throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'fcm' . ' ' . 'push'); } @@ -1110,7 +1110,7 @@ App::patch('/v1/messaging/providers/:id/apns') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('authKey', '', new Text(0), 'APNS authentication key.', true) ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) ->param('teamId', '', new Text(0), 'APNS team ID.', true) @@ -1118,7 +1118,7 @@ App::patch('/v1/messaging/providers/:id/apns') ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -1130,7 +1130,7 @@ App::patch('/v1/messaging/providers/:id/apns') throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'apns' . ' ' . 'push'); } @@ -1234,18 +1234,18 @@ App::patch('/v1/messaging/providers/:id/general') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('credentials', '', new JSON(), 'Provider credentials.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, bool $enabled, array $credentials, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, array $credentials, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } - if ($name) { + if (!empty($name)) { $provider->setAttribute('name', $name); } diff --git a/composer.lock b/composer.lock index 279847dedc..539c284fff 100644 --- a/composer.lock +++ b/composer.lock @@ -4145,16 +4145,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.0", + "version": "1.24.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6" + "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6", - "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01", + "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01", "shasum": "" }, "require": { @@ -4186,22 +4186,22 @@ "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.24.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.1" }, - "time": "2023-09-07T20:46:32+00:00" + "time": "2023-09-18T12:18:02+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.28", + "version": "9.2.29", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef" + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef", - "reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", "shasum": "" }, "require": { @@ -4258,7 +4258,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.28" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" }, "funding": [ { @@ -4266,7 +4266,7 @@ "type": "github" } ], - "time": "2023-09-12T14:36:20+00:00" + "time": "2023-09-19T04:57:46+00:00" }, { "name": "phpunit/php-file-iterator", diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index c460d2b5d3..65def00b48 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -145,6 +145,21 @@ trait MessagingBase $this->assertEquals($providersParams[$key]['name'], $response['body']['name']); } + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/' . $providers[1]['$id'] . '/mailgun', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'name' => 'Mailgun2', + 'apiKey' => 'my-apikey', + 'domain' => 'my-domain', + 'isEuRegion' => true, + 'enabled' => false, + ]); + $providers[1] = $response['body']; + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('Mailgun2', $response['body']['name']); + $this->assertEquals(false, $response['body']['enabled']); return $providers; } From f9030132a513f5a413944ec772c470ead3f5122c Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 20 Sep 2023 17:38:29 +0530 Subject: [PATCH 087/196] messaging worker logic to send message to providers batch limit --- app/config/collections.php | 22 ++--- app/controllers/api/messaging.php | 3 +- app/init.php | 2 - app/workers/messaging.php | 87 +++++++++++++++---- composer.lock | 38 ++++---- .../Utopia/Response/Model/Message.php | 8 +- 6 files changed, 107 insertions(+), 53 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 7cc9db49cc..fb7548e260 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1534,6 +1534,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('status'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => 'processing', + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('data'), 'type' => Database::VAR_STRING, @@ -1589,17 +1600,6 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], - [ - '$id' => ID::custom('delivered'), - 'type' => Database::VAR_BOOLEAN, - 'format' => '', - 'size' => 0, - 'signed' => true, - 'required' => false, - 'default' => false, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('search'), 'type' => Database::VAR_STRING, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index b2585418eb..ef17149aa4 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1307,7 +1307,7 @@ App::post('/v1/messaging/messages/email') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('providerId', '', new Text(128), 'Email Provider ID.') - ->param('to', [], new ArrayList(new Text(0)), 'Email Recepient.') + ->param('to', [], new ArrayList(new Text(0)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(0), 'Email Subject.') ->param('content', '', new Text(0), 'Email Content.') ->param('from', '', new Text(0), 'Email from.', true) @@ -1333,6 +1333,7 @@ App::post('/v1/messaging/messages/email') 'from' => $from, 'html' => $html ], + 'status' => 'processing', 'search' => $subject . ' ' . $from, ])); diff --git a/app/init.php b/app/init.php index fd4117e799..ea01751be5 100644 --- a/app/init.php +++ b/app/init.php @@ -539,7 +539,6 @@ Database::addFilter( return Authorization::skip(fn() => $database ->find('targets', [ Query::equal('userInternalId', [$document->getInternalId()]), - Query::limit(APP_LIMIT_SUBQUERY), ])); } ); @@ -555,7 +554,6 @@ Database::addFilter( $database ->find('subscribers', [ Query::equal('topicInternalId', [$document->getInternalId()]), - Query::limit(APP_LIMIT_SUBQUERY), ]) )); if (\count($targetIds) > 0) { diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 079ff3397b..65a519a98a 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -2,7 +2,10 @@ use Appwrite\Resque\Worker; use Utopia\CLI\Console; +use Utopia\Database\Database; +use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\Query; use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Adapters\SMS\Mock; use Utopia\Messaging\Adapters\SMS\Msg91; @@ -31,8 +34,8 @@ class MessagingV1 extends Worker protected ?PushAdapter $push = null; protected ?EmailAdapter $email = null; + protected ?Database $dbForProject = null; - protected ?string $from = null; public function getName(): string { @@ -86,33 +89,85 @@ class MessagingV1 extends Worker public function run(): void { $project = new Document($this->args['project']); + $this->dbForProject = $this->getProjectDB($project); - $dbForProject = $this->getProjectDB($project); - $message = new Document($this->args['message']); + $messageRecord = new Document($this->args['message']); - $providerId = $message->getAttribute('providerId'); - $providerRecord = $dbForProject->getDocument('providers', $providerId); + $providerId = $messageRecord->getAttribute('providerId'); + $providerRecord = $this->dbForProject->getDocument('providers', $providerId); - $provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed. + $this->processMessage($messageRecord, $providerRecord); + } + + private function processMessage(Document $messageRecord, Document $providerRecord): void + { + $provider = match ($providerRecord->getAttribute('type')) { 'sms' => $this->sms($providerRecord), 'push' => $this->push($providerRecord), 'email' => $this->email($providerRecord), default => null }; - // Query for the provider - // switch on provider name - // call function passing needed credentials returns required provider. + $recipientsId = $messageRecord->getAttribute('to'); - $message = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($message->getArrayCopy()), - 'push' => $this->buildPushMessage($message->getArrayCopy()), - 'email' => $this->buildEmailMessage($message->getArrayCopy()), - default => null - }; + /** + * @var Document[] $recipients + */ + $recipients = []; - $provider->send($message); + $topics = $this->dbForProject->find('topics', [Query::equal('$id', $recipientsId)]); + foreach ($topics as $topic) { + $recipients = \array_merge($recipients, $topic->getAttribute('targets')); + } + + $users = $this->dbForProject->find('users', [Query::equal('$id', $recipientsId)]); + foreach ($users as $user) { + $recipients = \array_merge($recipients, $user->getAttribute('targets')); + } + + $targets = $this->dbForProject->find('targets', [Query::equal('$id', $recipientsId)]); + \array_merge($recipients, $targets); + + $identifiers = \array_map(function (Document $recipient) { + return $recipient->getAttribute('identifier'); + }, $recipients); + + $maxBatchSize = $provider->getMaxMessagesPerRequest(); + $batches = \array_chunk($identifiers, $maxBatchSize); + $message = $messageRecord->getArrayCopy(); + $deliveredTo = 0; + + foreach ($batches as $batch) { + $message['to'] = $batch; + $message = match ($providerRecord->getAttribute('type')) { + 'sms' => $this->buildSMSMessage($message), + 'push' => $this->buildPushMessage($message), + 'email' => $this->buildEmailMessage($message), + default => null + }; + try { + $provider->send($message); + $deliveredTo += \count($batch); + } catch (Exception $e) { + $deliveryErrors = $messageRecord->getAttribute('deliveryErrors'); + foreach ($batch as $identifier) { + $deliveryErrors[] = 'Failed to send message to target' . $identifier . ': ' . $e->getMessage(); + } + $messageRecord->setAttribute('deliveryErrors', $deliveryErrors); + } + } + + if (\count($messageRecord->getAttribute('deliveryErrors')) > 0) { + $messageRecord->setAttribute('status', 'failed'); + } else { + $messageRecord->setAttribute('status', 'sent'); + } + + $messageRecord->setAttribute('deliveredTo', $deliveredTo); + $messageRecord->setAttribute('deliveryTime', DateTime::now()); + + $this->dbForProject->updateDocument('messages', $messageRecord->getId(), $messageRecord); } public function shutdown(): void diff --git a/composer.lock b/composer.lock index a22f86efdd..14b07bdce7 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": "ce37f32b5c3c12e85d8d67bad35f57d7", + "content-hash": "6431be75373bf2e1bdbe2c638188d15f", "packages": [ { "name": "adhocore/jwt", @@ -2564,16 +2564,16 @@ }, { "name": "utopia-php/migration", - "version": "0.3.3", + "version": "0.3.4", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "45bd831ed9819994f05cb3b467c58f8155e27692" + "reference": "ade836d61b3e1547bc9f0dc300ee75b24ab49f7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/45bd831ed9819994f05cb3b467c58f8155e27692", - "reference": "45bd831ed9819994f05cb3b467c58f8155e27692", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/ade836d61b3e1547bc9f0dc300ee75b24ab49f7a", + "reference": "ade836d61b3e1547bc9f0dc300ee75b24ab49f7a", "shasum": "" }, "require": { @@ -2616,9 +2616,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.3.3" + "source": "https://github.com/utopia-php/migration/tree/0.3.4" }, - "time": "2023-09-06T03:54:54+00:00" + "time": "2023-09-14T17:17:55+00:00" }, { "name": "utopia-php/mongo", @@ -4145,16 +4145,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.0", + "version": "1.24.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6" + "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6", - "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01", + "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01", "shasum": "" }, "require": { @@ -4186,22 +4186,22 @@ "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.24.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.1" }, - "time": "2023-09-07T20:46:32+00:00" + "time": "2023-09-18T12:18:02+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.28", + "version": "9.2.29", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef" + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef", - "reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", "shasum": "" }, "require": { @@ -4258,7 +4258,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.28" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" }, "funding": [ { @@ -4266,7 +4266,7 @@ "type": "github" } ], - "time": "2023-09-12T14:36:20+00:00" + "time": "2023-09-19T04:57:46+00:00" }, { "name": "phpunit/php-file-iterator", diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 6eebbcd793..96c8c9b989 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -51,11 +51,11 @@ class Message extends Any 'default' => 0, 'example' => 1, ]) - ->addRule('delivered', [ - 'type' => self::TYPE_BOOLEAN, + ->addRule('status', [ + 'type' => self::TYPE_STRING, 'description' => 'Status of delivery.', - 'default' => false, - 'example' => true, + 'default' => 'processing', + 'example' => 'Message status can be one of the following: processing, sent, failed.', ]); } From 3456ad4e8cc3081ee3b7ec78e2d73f59d448b0df Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 20 Sep 2023 17:52:25 +0530 Subject: [PATCH 088/196] fixes merge conflict issue --- app/controllers/api/teams.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index b4f14c9dbc..23d0d14c2a 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -389,7 +389,7 @@ App::post('/v1/teams/:teamId/memberships') ->inject('mails') ->inject('messaging') ->inject('events') - ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, string $from, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, EventPhone $messaging, Event $events) { + ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, string $from, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, Messaging $messaging, Event $events) { $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); From 975b444761bc9affb901ae5941f65ee6ce08303a Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 20 Sep 2023 20:51:03 +0530 Subject: [PATCH 089/196] fix test cases and bug fix in messaging worker --- app/controllers/api/account.php | 22 ++++++++++++++++++---- app/workers/messaging.php | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index cda5c030ed..8cce5a57f8 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1330,15 +1330,22 @@ App::post('/v1/account/sessions/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); + $target = $dbForProject->createDocument('targets', new Document([ + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'identifier' => $phone, + ])); + $messageDoc = $dbForProject->createDocument('messages', new Document([ - 'to' => [$phone], + 'to' => [$target->getId()], 'data' => [ 'content' => $message, 'from' => $from, ], 'providerId' => $provider->getId(), 'providerInternalId' => $provider->getInternalId(), - 'deliveryTime' => Datetime::now(), ])); $messaging @@ -2952,15 +2959,22 @@ App::post('/v1/account/verification/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); + $target = $dbForProject->createDocument('targets', new Document([ + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'identifier' => $user->getAttribute('phone'), + ])); + $messageDoc = $dbForProject->createDocument('messages', new Document([ - 'to' => [$user->getAttribute('phone')], + 'to' => [$target->getId()], 'data' => [ 'content' => $message, 'from' => $from, ], 'providerId' => $provider->getId(), 'providerInternalId' => $provider->getInternalId(), - 'deliveryTime' => Datetime::now(), ])); $messaging diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 65a519a98a..6fb1f42dc6 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -127,7 +127,7 @@ class MessagingV1 extends Worker } $targets = $this->dbForProject->find('targets', [Query::equal('$id', $recipientsId)]); - \array_merge($recipients, $targets); + $recipients = \array_merge($recipients, $targets); $identifiers = \array_map(function (Document $recipient) { return $recipient->getAttribute('identifier'); From 2fd7467e2ae463abdec8ec1bfe1a9b082c1a3b05 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 20 Sep 2023 22:59:47 +0530 Subject: [PATCH 090/196] fix graphQL test --- app/config/services.php | 2 +- tests/e2e/Services/GraphQL/AccountTest.php | 22 ++++++++++++++++ tests/e2e/Services/GraphQL/Base.php | 29 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/app/config/services.php b/app/config/services.php index 6b57c01bff..cfefd60c8b 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -260,7 +260,7 @@ return [ 'sdk' => true, 'docs' => true, 'docsUrl' => 'https://appwrite.io/docs/server/messaging', - 'tests' => false, + 'tests' => true, 'optional' => true, 'icon' => '/images/services/messaging.png', ] diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 7fd70b5015..93c6b007ee 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -123,6 +123,28 @@ class AccountTest extends Scope public function testCreatePhoneVerification(): array { $projectId = $this->getProject()['$id']; + $query = $this->getQuery(self::$CREATE_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => 'unique()', + 'name' => 'Mock', + 'provider' => 'mock', + 'type' => 'sms', + 'credentials' => [ + 'username' => 'username', + 'password' => 'password', + ], + 'default' => true, + ], + ]; + + $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], $graphQLPayload); + $query = $this->getQuery(self::$CREATE_PHONE_VERIFICATION); $graphQLPayload = [ 'query' => $query, diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 3a4b88e2c2..bed34d4455 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -296,6 +296,8 @@ trait Base } '; + public static string $CREATE_PROVIDER = 'create_provider'; + public function getQuery(string $name): string { switch ($name) { @@ -1929,6 +1931,33 @@ trait Base } } }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; + case self::$CREATE_PROVIDER: + return 'mutation CreateGeneralProvider( + $providerId: String!, + $provider: String!, + $name: String!, + $type: String!, + $default: Boolean, + $enabled: Boolean, + $credentials: Json! + ) { + messagingCreateGeneralProvider( + providerId: $providerId, + provider: $provider, + name: $name, + type: $type, + default: $default, + enabled: $enabled, + credentials: $credentials + ) { + _id + name + provider + type + default + enabled + } + }'; } throw new \InvalidArgumentException('Invalid query type'); From dd14bbf785a0e4c3d663a69739d57393681e1dd7 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 20 Sep 2023 23:02:53 +0530 Subject: [PATCH 091/196] lint fix --- tests/e2e/Services/GraphQL/Base.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index bed34d4455..44cb0a0c55 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1931,7 +1931,7 @@ trait Base } } }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; - case self::$CREATE_PROVIDER: + case self::$CREATE_PROVIDER: return 'mutation CreateGeneralProvider( $providerId: String!, $provider: String!, From 35d842171c2c0c9a92df697b137aae81f531d3a5 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 20 Sep 2023 23:37:10 +0530 Subject: [PATCH 092/196] review changes --- app/config/roles.php | 6 ---- app/controllers/api/teams.php | 10 +++++- app/controllers/api/users.php | 32 ++++--------------- app/init.php | 1 - .../Database/Validator/Queries/Providers.php | 2 ++ tests/e2e/Services/Account/AccountBase.php | 1 + .../Account/AccountCustomClientTest.php | 2 +- 7 files changed, 19 insertions(+), 35 deletions(-) diff --git a/app/config/roles.php b/app/config/roles.php index 579e13dfca..944fcf3577 100644 --- a/app/config/roles.php +++ b/app/config/roles.php @@ -62,12 +62,6 @@ $admins = [ 'rules.write', 'migrations.read', 'migrations.write', - 'targets.read', - 'targets.write', - 'providers.write', - 'providers.read', - 'messages.write', - 'messages.read', 'vcs.read', 'vcs.write', 'targets.read', diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 23d0d14c2a..08759cf39f 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -652,8 +652,16 @@ App::post('/v1/teams/:teamId/memberships') $message = $message->setParam('{{token}}', $url); $message = $message->render(); + $target = $dbForProject->createDocument('targets', new Document([ + 'userId' => $invitee->getId(), + 'userInternalId' => $invitee->getInternalId(), + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'identifier' => $phone, + ])); + $messageDoc = $dbForProject->createDocument('messages', new Document([ - 'to' => [$phone], + 'to' => [$target->getId()], 'data' => [ 'content' => $message, 'from' => $from, diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 1d88a04d11..9b2dc516cb 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -383,9 +383,8 @@ App::post('/v1/users/scrypt-modified') App::post('/v1/users/:userId/targets') ->desc('Create User Target') ->groups(['api', 'users']) - ->label('event', 'users.[userId].targets.[targetId].create') - ->label('audits.event', 'targets.create') - ->label('audits.resource', 'user/{response.userId}') + ->label('audits.event', 'users.targets.create') + ->label('audits.resource', 'target/response.$id') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -422,11 +421,6 @@ App::post('/v1/users/:userId/targets') $target = $dbForProject->createDocument('targets', new Document([ '$id' => $targetId, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($userId)), - Permission::delete(Role::user($userId)), - ], 'providerId' => $providerId, 'providerInternalId' => $provider->getInternalId(), 'userId' => $userId, @@ -434,9 +428,6 @@ App::post('/v1/users/:userId/targets') 'identifier' => $identifier, ])); $dbForProject->deleteCachedDocument('users', $user->getId()); - $events - ->setParam('userId', $userId) - ->setParam('targetId', $targetId); $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($target, Response::MODEL_TARGET); @@ -1207,9 +1198,8 @@ App::patch('/v1/users/:userId/prefs') App::patch('/v1/users/:userId/targets/:targetId/identifier') ->desc('Update user target\'s identifier') ->groups(['api', 'users']) - ->label('event', 'users.[userId].targets.[targetId].update') - ->label('audits.event', 'targets.update') - ->label('audits.resource', 'user/{response.userId}') + ->label('audits.event', 'users.targets.update') + ->label('audits.resource', 'target/{response.$id}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -1385,9 +1375,8 @@ App::delete('/v1/users/:userId') App::delete('/v1/users/:userId/targets/:targetId') ->desc('Delete user target') ->groups(['api', 'users']) - ->label('event', 'users.[userId].targets.[targetId].delete') - ->label('audits.event', 'targets.delete') - ->label('audits.resource', 'user/{response.userId}') + ->label('audits.event', 'users.targets.delete') + ->label('audits.resource', 'target/{request.$targetId}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -1417,15 +1406,6 @@ App::delete('/v1/users/:userId/targets/:targetId') $target = $dbForProject->deleteDocument('targets', $target->getId()); $dbForProject->deleteCachedDocument('users', $user->getId()); - $user = $dbForProject->getDocument('users', $userId); - - // clone user object to send to workers - $clone = clone $user; - - $events - ->setParam('userId', $userId) - ->setParam('targetId', $targetId) - ->setPayload($response->output($clone, Response::MODEL_USER)); $response->noContent(); }); diff --git a/app/init.php b/app/init.php index ea01751be5..a094acc7df 100644 --- a/app/init.php +++ b/app/init.php @@ -562,7 +562,6 @@ Database::addFilter( return []; } ); - /** * DB Formats */ diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php index 83dbf665f1..e72153734c 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php @@ -8,6 +8,8 @@ class Providers extends Base 'name', 'provider', 'type', + 'default', + 'enabled' ]; /** diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index b0959a3b0a..e64cf2c4ca 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -359,6 +359,7 @@ trait AccountBase 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ])); + $this->assertEquals($response['headers']['status-code'], 200); $this->assertIsArray($response['body']['logs']); $this->assertNotEmpty($response['body']['logs']); diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 9f922d63e2..5a177146a1 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -1013,7 +1013,7 @@ class AccountCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), ['from' => 'Appwrite']); + ]), ['from' => '+123456789']); $this->assertEquals(201, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); From 39854239fb7202f6d7932714189ab682ecf58b38 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 21 Sep 2023 02:29:57 +0530 Subject: [PATCH 093/196] skip authorization in adding subscriber on targets --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 17e7d18d5b..13710bca0a 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1568,7 +1568,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') throw new Exception(Exception::TOPIC_NOT_FOUND); } - $target = $dbForProject->getDocument('targets', $targetId); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); From b4de44c905f1a4ad33a5946d90406771410510ec Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 21 Sep 2023 16:12:56 +0530 Subject: [PATCH 094/196] fix small bug in worker and send email endpoint --- app/controllers/api/messaging.php | 10 +++++----- app/workers/messaging.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index ef17149aa4..101ceb66dd 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1307,16 +1307,16 @@ App::post('/v1/messaging/messages/email') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('providerId', '', new Text(128), 'Email Provider ID.') - ->param('to', [], new ArrayList(new Text(0)), 'List of Topic IDs or List of User IDs or List of Target IDs.') - ->param('subject', '', new Text(0), 'Email Subject.') - ->param('content', '', new Text(0), 'Email Content.') - ->param('from', '', new Text(0), 'Email from.', true) + ->param('to', [], new ArrayList(new Text(65535)), 'List of Topic IDs or List of User IDs or List of Target IDs.') + ->param('subject', '', new Text(128), 'Email Subject.') + ->param('content', '', new Text(65407), 'Email Content.') + ->param('from', '', new Text(128), 'Email from.', true) ->param('html', false, new Boolean(false), 'Is content of type HTML', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $providerId, array $to, string $subject, string $content, string $from, string $html, string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $providerId, array $to, string $subject, string $content, string $from, string $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 6fb1f42dc6..5b92bf59a0 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -76,7 +76,7 @@ class MessagingV1 extends Worker { $credentials = $record->getAttribute('credentials'); return match ($record->getAttribute('provider')) { - 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain']), + 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain'], $credentials['isEuRegion']), 'sendgrid' => new SendGrid($credentials['apiKey']), default => null }; From 342f1223655c10413571a7dfc8bc2db7b2b07d78 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 21 Sep 2023 16:18:20 +0530 Subject: [PATCH 095/196] adds key auth to providers endpoint --- app/controllers/api/messaging.php | 46 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 101ceb66dd..d9a57e03b3 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -26,7 +26,7 @@ App::get('/v1/messaging/providers') ->desc('List Providers') ->groups(['api', 'messaging']) ->label('scope', 'providers.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'listProviders') ->label('sdk.description', '/docs/references/messaging/list-providers.md') @@ -68,7 +68,7 @@ App::get('/v1/messaging/providers/:id') ->desc('Get Provider') ->groups(['api', 'messaging']) ->label('scope', 'providers.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'getProvider') ->label('sdk.description', '/docs/references/messaging/get-provider.md') @@ -97,7 +97,7 @@ App::post('/v1/messaging/providers/mailgun') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createProviderMailgun') ->label('sdk.description', '/docs/references/messaging/create-provider-mailgun.md') @@ -157,7 +157,7 @@ App::patch('/v1/messaging/providers/:id/mailgun') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderMailgun') ->label('sdk.description', '/docs/references/messaging/update-provider-mailgun.md') @@ -228,7 +228,7 @@ App::post('/v1/messaging/providers/sendgrid') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createProviderSendgrid') ->label('sdk.description', '/docs/references/messaging/create-provider-sendgrid.md') @@ -283,7 +283,7 @@ App::patch('/v1/messaging/providers/:id/sendgrid') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderSendgrid') ->label('sdk.description', '/docs/references/messaging/update-provider-sendgrid.md') @@ -339,7 +339,7 @@ App::post('/v1/messaging/providers/msg91') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createProviderMsg91') ->label('sdk.description', '/docs/references/messaging/create-provider-msg91.md') @@ -396,7 +396,7 @@ App::patch('/v1/messaging/providers/:id/msg91') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderMsg91') ->label('sdk.description', '/docs/references/messaging/update-provider-msg91.md') @@ -457,7 +457,7 @@ App::post('/v1/messaging/providers/telesign') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createProviderTelesign') ->label('sdk.description', '/docs/references/messaging/create-provider-telesign.md') @@ -514,7 +514,7 @@ App::patch('/v1/messaging/providers/:id/telesign') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderTelesign') ->label('sdk.description', '/docs/references/messaging/update-provider-telesign.md') @@ -575,7 +575,7 @@ App::post('/v1/messaging/providers/textmagic') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createProviderTextmagic') ->label('sdk.description', '/docs/references/messaging/create-provider-textmagic.md') @@ -632,7 +632,7 @@ App::patch('/v1/messaging/providers/:id/textmagic') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderTextmagic') ->label('sdk.description', '/docs/references/messaging/update-provider-textmagic.md') @@ -693,7 +693,7 @@ App::post('/v1/messaging/providers/twilio') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createProviderTwilio') ->label('sdk.description', '/docs/references/messaging/create-provider-twilio.md') @@ -750,7 +750,7 @@ App::patch('/v1/messaging/providers/:id/twilio') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderTwilio') ->label('sdk.description', '/docs/references/messaging/update-provider-twilio.md') @@ -811,7 +811,7 @@ App::post('/v1/messaging/providers/vonage') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createProviderVonage') ->label('sdk.description', '/docs/references/messaging/create-provider-vonage.md') @@ -868,7 +868,7 @@ App::patch('/v1/messaging/providers/:id/vonage') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderVonage') ->label('sdk.description', '/docs/references/messaging/update-provider-vonage.md') @@ -932,7 +932,7 @@ App::post('/v1/messaging/providers/fcm') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createProviderFCM') ->label('sdk.description', '/docs/references/messaging/create-provider-fcm.md') @@ -987,7 +987,7 @@ App::patch('/v1/messaging/providers/:id/fcm') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderFCM') ->label('sdk.description', '/docs/references/messaging/update-provider-fcm.md') @@ -1038,7 +1038,7 @@ App::post('/v1/messaging/providers/apns') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createProviderAPNS') ->label('sdk.description', '/docs/references/messaging/create-provider-apns.md') @@ -1101,7 +1101,7 @@ App::patch('/v1/messaging/providers/:id/apns') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderAPNS') ->label('sdk.description', '/docs/references/messaging/update-provider-apns.md') @@ -1171,7 +1171,7 @@ App::post('/v1/messaging/providers/general') ->label('audits.event', 'providers.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createGeneralProvider') ->label('sdk.description', '/docs/references/messaging/create-general-provider.md') @@ -1225,7 +1225,7 @@ App::patch('/v1/messaging/providers/:id/general') ->label('audits.event', 'providers.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateProviderGeneral') ->label('sdk.description', '/docs/references/messaging/update-provider-general.md') @@ -1270,7 +1270,7 @@ App::delete('/v1/messaging/providers/:id') ->label('audits.event', 'providers.delete') ->label('audits.resource', 'providers/{request.id}') ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'deleteProvider') ->label('sdk.description', '/docs/references/messaging/delete-provider.md') From 3ebcfe548d56183c2c38989dab41405237686d23 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 21 Sep 2023 16:26:53 +0530 Subject: [PATCH 096/196] Adds get message endpoint --- app/config/errors.php | 7 +++++++ app/controllers/api/messaging.php | 26 +++++++++++++++++++++++++- src/Appwrite/Extend/Exception.php | 3 +++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/app/config/errors.php b/app/config/errors.php index 8b2ccf810e..8001517d78 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -754,5 +754,12 @@ return [ 'name' => Exception::PROVIDER_INCORRECT_TYPE, 'description' => 'Provider with the requested ID is of incorrect type: ', 'code' => 400, + ], + + /** Message Errors */ + Exception::MESSAGE_NOT_FOUND => [ + 'name' => Exception::MESSAGE_NOT_FOUND, + 'description' => 'Message with the requested ID could not be found.', + 'code' => 404, ] ]; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index d9a57e03b3..6c50578312 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -75,7 +75,7 @@ App::get('/v1/messaging/providers/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', null, new UID(), 'Provider ID.') + ->param('id', '', new UID(), 'Provider ID.') ->inject('dbForProject') ->inject('response') ->action(function (string $id, Database $dbForProject, Response $response) { @@ -1293,6 +1293,30 @@ App::delete('/v1/messaging/providers/:id') $response->noContent(); }); +App::get('/v1/messaging/messages/:id') + ->desc('Get Message') + ->groups(['api', 'messaging']) + ->label('scope', 'messages.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'getMessage') + ->label('sdk.description', '/docs/references/messaging/get-message.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('id', '', new UID(), 'Message ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, Database $dbForProject, Response $response) { + $message = $dbForProject->getDocument('message', $id); + + if ($message->isEmpty()) { + throw new Exception(Exception::MESSAGE_NOT_FOUND); + } + + $response->dynamic($message, Response::MODEL_MESSAGE); + }); + App::post('/v1/messaging/messages/email') ->desc('Send an email.') ->groups(['api', 'messaging']) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 2b10b0cb51..cdd2538abb 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -230,6 +230,9 @@ class Exception extends \Exception public const PROVIDER_ALREADY_EXISTS = 'provider_already_exists'; public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; + /** Message */ + public const MESSAGE_NOT_FOUND = 'message_not_found'; + protected $type = ''; protected $errors = []; From 06a05a3358bfd2e2aa73dd5f6dbfd58f8dc6ea16 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 21 Sep 2023 21:17:15 +0530 Subject: [PATCH 097/196] adds param messageId in send an email endpoint, tokenId as messageId in create phone session, membershipId as messageId in create team membership --- app/controllers/api/account.php | 2 ++ app/controllers/api/messaging.php | 6 +++++- app/controllers/api/teams.php | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 8cce5a57f8..e4ef089005 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1339,6 +1339,7 @@ App::post('/v1/account/sessions/phone') ])); $messageDoc = $dbForProject->createDocument('messages', new Document([ + '$id' => $token->getId(), 'to' => [$target->getId()], 'data' => [ 'content' => $message, @@ -2968,6 +2969,7 @@ App::post('/v1/account/verification/phone') ])); $messageDoc = $dbForProject->createDocument('messages', new Document([ + '$id' => $verification->getId(), 'to' => [$target->getId()], 'data' => [ 'content' => $message, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 6c50578312..8014bb3f92 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1330,6 +1330,7 @@ App::post('/v1/messaging/messages/email') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('providerId', '', new Text(128), 'Email Provider ID.') ->param('to', [], new ArrayList(new Text(65535)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(128), 'Email Subject.') @@ -1340,7 +1341,9 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $providerId, array $to, string $subject, string $content, string $from, string $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $subject, string $content, string $from, string $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1348,6 +1351,7 @@ App::post('/v1/messaging/messages/email') } $message = $dbForProject->createDocument('messages', new Document([ + '$id' => $messageId, 'providerId' => $provider->getId(), 'providerInternalId' => $provider->getInternalId(), 'to' => $to, diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 08759cf39f..4a697bedbb 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -661,6 +661,8 @@ App::post('/v1/teams/:teamId/memberships') ])); $messageDoc = $dbForProject->createDocument('messages', new Document([ + // Here membership ID is used as message ID so that it can be used in test cases to verify the message + '$id' => $membership->getId(), 'to' => [$target->getId()], 'data' => [ 'content' => $message, From d63eaf3ef010bbec9501ab86cba04e97eca8d900 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 21 Sep 2023 21:49:40 +0530 Subject: [PATCH 098/196] fixes get message endpoint --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 8014bb3f92..64da3919db 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1308,7 +1308,7 @@ App::get('/v1/messaging/messages/:id') ->inject('dbForProject') ->inject('response') ->action(function (string $id, Database $dbForProject, Response $response) { - $message = $dbForProject->getDocument('message', $id); + $message = $dbForProject->getDocument('messages', $id); if ($message->isEmpty()) { throw new Exception(Exception::MESSAGE_NOT_FOUND); From e2acb608fa7280e337f1fa91a31e5e8dca88eebf Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 21 Sep 2023 22:16:02 +0530 Subject: [PATCH 099/196] fix tests with real sms providers --- .env | 6 +- app/controllers/api/messaging.php | 102 ------------------ docker-compose.yml | 4 + .../Account/AccountCustomClientTest.php | 62 +++++++---- tests/e2e/Services/GraphQL/AccountTest.php | 22 ++-- tests/e2e/Services/GraphQL/Base.php | 14 ++- 6 files changed, 71 insertions(+), 139 deletions(-) diff --git a/.env b/.env index 189095e9e5..9117fe9f3b 100644 --- a/.env +++ b/.env @@ -96,4 +96,8 @@ _APP_VCS_GITHUB_CLIENT_SECRET= _APP_VCS_GITHUB_WEBHOOK_SECRET= _APP_MIGRATIONS_FIREBASE_CLIENT_ID= _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET= -_APP_ASSISTANT_OPENAI_API_KEY= \ No newline at end of file +_APP_ASSISTANT_OPENAI_API_KEY= +_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID= +_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY= +_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM= +_APP_MESSAGE_SMS_PROVIDER_MSG91_TO= \ No newline at end of file diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 64da3919db..275051ecb0 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1162,108 +1162,6 @@ App::patch('/v1/messaging/providers/:id/apns') ->dynamic($provider, Response::MODEL_PROVIDER); }); -/** - * General Purpose Provider - */ -App::post('/v1/messaging/providers/general') - ->desc('Create General Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createGeneralProvider') - ->label('sdk.description', '/docs/references/messaging/create-general-provider.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('provider', '', new Text(128), 'Provider Internal Name') - ->param('name', '', new Text(128), 'Provider name.') - ->param('type', '', new WhiteList(['push', 'email', 'sms']), 'Provider type.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('credentials', '', new JSON(), 'Provider credentials object.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $provider, string $name, string $type, bool $default, bool $enabled, array $credentials, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => $provider, - 'type' => $type, - 'default' => $default, - 'enabled' => $enabled, - 'credentials' => $credentials, - ]); - - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/general') - ->desc('Update General Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderGeneral') - ->label('sdk.description', '/docs/references/messaging/update-provider-general.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') - ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('credentials', '', new JSON(), 'Provider credentials.', true) - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, array $credentials, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); - - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - - if (!empty($name)) { - $provider->setAttribute('name', $name); - } - - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - - if (!empty($credentials)) { - $provider->setAttribute('credentials', $credentials); - } - - $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); - - $response - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - App::delete('/v1/messaging/providers/:id') ->desc('Delete Provider') ->groups(['api', 'messaging']) diff --git a/docker-compose.yml b/docker-compose.yml index ac0fcabc8a..053042f81d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -186,6 +186,10 @@ services: - _APP_MIGRATIONS_FIREBASE_CLIENT_ID - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET - _APP_ASSISTANT_OPENAI_API_KEY + - _APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID + - _APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY + - _APP_MESSAGE_SMS_PROVIDER_MSG91_FROM + - _APP_MESSAGE_SMS_PROVIDER_MSG91_TO appwrite-realtime: entrypoint: realtime diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 5a177146a1..96f9b3774c 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -7,6 +7,7 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideClient; +use Utopia\App; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; @@ -742,20 +743,27 @@ class AccountCustomClientTest extends Scope public function testCreatePhone(): array { - $number = '+123456789'; - $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/general', \array_merge([ + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + + if($to === '' || $from === '' || $authKey === '' || $senderId === '') { + $this->markTestSkipped('SMS provider not configured'); + } + + $number = $to; + $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/msg91', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'providerId' => 'unique()', - 'name' => 'Mock', - 'provider' => 'mock', + 'name' => 'Sms provider', + 'provider' => 'msg91', 'type' => 'sms', - 'credentials' => [ - 'username' => 'username', - 'password' => 'password', - ], + 'senderId' => $senderId, + 'authKey' => $authKey, 'default' => true, ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -769,7 +777,7 @@ class AccountCustomClientTest extends Scope ]), [ 'userId' => ID::unique(), 'phone' => $number, - 'from' => $number, + 'from' => $from, ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -778,6 +786,7 @@ class AccountCustomClientTest extends Scope $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['expire'])); $userId = $response['body']['userId']; + $messageId = $response['body']['$id']; /** * Test for FAILURE @@ -794,17 +803,19 @@ class AccountCustomClientTest extends Scope \sleep(5); - $smsRequest = $this->getLastRequest(); + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $messageId, [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); - $this->assertEquals('http://request-catcher:5000/mock-sms', $smsRequest['url']); - $this->assertEquals('Appwrite Mock Message Sender', $smsRequest['headers']['User-Agent']); - $this->assertEquals('username', $smsRequest['headers']['X-Username']); - $this->assertEquals('password', $smsRequest['headers']['X-Key']); - $this->assertEquals('POST', $smsRequest['method']); - $this->assertEquals('+123456789', $smsRequest['data']['from']); - $this->assertEquals($number, $smsRequest['data']['to']); + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); - $data['token'] = $smsRequest['data']['message']; + + $data['token'] = $message['body']['data']['content']; $data['id'] = $userId; $data['number'] = $number; @@ -1013,7 +1024,7 @@ class AccountCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), ['from' => '+123456789']); + ]), ['from' => App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM')]); $this->assertEquals(201, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); @@ -1022,10 +1033,19 @@ class AccountCustomClientTest extends Scope \sleep(2); - $smsRequest = $this->getLastRequest(); + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $response['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); return \array_merge($data, [ - 'token' => $smsRequest['data']['message'] + 'token' => $message['body']['data']['content'] ]); } diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 93c6b007ee..0366c2f359 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -6,6 +6,7 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; +use Utopia\App; use Utopia\Database\Helpers\ID; class AccountTest extends Scope @@ -122,24 +123,31 @@ class AccountTest extends Scope */ public function testCreatePhoneVerification(): array { + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + + if($to === '' || $from === '' || $authKey === '' || $senderId === '') { + $this->markTestSkipped('SMS provider not configured'); + } + $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_PROVIDER); $graphQLPayload = [ 'query' => $query, 'variables' => [ 'providerId' => 'unique()', - 'name' => 'Mock', - 'provider' => 'mock', + 'name' => 'Sms Provider', + 'provider' => 'msg91', 'type' => 'sms', - 'credentials' => [ - 'username' => 'username', - 'password' => 'password', - ], + 'senderId' => $senderId, + 'authKey' => $authKey, 'default' => true, ], ]; - $this->client->call(Client::METHOD_POST, '/graphql', [ + $response = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $this->getProject()['apiKey'], diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 44cb0a0c55..7f163fdffb 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1932,23 +1932,21 @@ trait Base } }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; case self::$CREATE_PROVIDER: - return 'mutation CreateGeneralProvider( + return 'mutation createProviderMsg91( $providerId: String!, - $provider: String!, $name: String!, - $type: String!, + $senderId: String!, + $authKey: String! $default: Boolean, $enabled: Boolean, - $credentials: Json! ) { - messagingCreateGeneralProvider( + messagingCreateProviderMsg91( providerId: $providerId, - provider: $provider, name: $name, - type: $type, + senderId: $senderId, + authKey: $authKey default: $default, enabled: $enabled, - credentials: $credentials ) { _id name From df6466a1d35d00678644cf06c2e52bc5131a662d Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 21 Sep 2023 22:20:56 +0530 Subject: [PATCH 100/196] lint fix --- tests/e2e/Services/Account/AccountCustomClientTest.php | 2 +- tests/e2e/Services/GraphQL/AccountTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 96f9b3774c..77d8662ba4 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -748,7 +748,7 @@ class AccountCustomClientTest extends Scope $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); - if($to === '' || $from === '' || $authKey === '' || $senderId === '') { + if ($to === '' || $from === '' || $authKey === '' || $senderId === '') { $this->markTestSkipped('SMS provider not configured'); } diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 0366c2f359..aa60d2d81b 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -128,10 +128,10 @@ class AccountTest extends Scope $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); - if($to === '' || $from === '' || $authKey === '' || $senderId === '') { + if ($to === '' || $from === '' || $authKey === '' || $senderId === '') { $this->markTestSkipped('SMS provider not configured'); } - + $projectId = $this->getProject()['$id']; $query = $this->getQuery(self::$CREATE_PROVIDER); $graphQLPayload = [ From a0858ccc4ec493e88b5f9bf27b1240632f3e409b Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 26 Sep 2023 13:12:44 +0530 Subject: [PATCH 101/196] adds message description, options to mailgun provider --- app/config/collections.php | 22 ++++++++++++++++ app/controllers/api/messaging.php | 25 ++++++++++++++----- composer.lock | 12 ++++----- .../Utopia/Response/Model/Message.php | 7 ++++++ .../Utopia/Response/Model/Provider.php | 17 +++++++++++++ .../e2e/Services/Messaging/MessagingBase.php | 1 + 6 files changed, 72 insertions(+), 12 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index fb7548e260..5506467cc4 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1449,6 +1449,17 @@ $commonCollections = [ 'array' => false, 'filters' => ['json', 'encrypt'], ], + [ + '$id' => ID::custom('options'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['json'], + ], [ '$id' => ID::custom('search'), 'type' => Database::VAR_STRING, @@ -1534,6 +1545,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('description'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 256, + 'signed' => true, + 'required' => false, + 'default' => '', + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('status'), 'type' => Database::VAR_STRING, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 275051ecb0..45c2760aba 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -108,12 +108,13 @@ App::post('/v1/messaging/providers/mailgun') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('isEuRegion', false, new Boolean(), 'Set as eu region.', true) + ->param('isEuRegion', false, new Boolean(), 'Set as EU region.', true) + ->param('from', '', new Text(256), 'Sender Email Address.') ->param('apiKey', '', new Text(0), 'Mailgun API Key.') ->param('domain', '', new Text(0), 'Mailgun Domain.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, bool $isEuRegion, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ @@ -129,6 +130,9 @@ App::post('/v1/messaging/providers/mailgun') 'domain' => $domain, 'isEuRegion' => $isEuRegion, ], + 'options' => [ + 'from' => $from, + ] ]); // Check if a default provider exists, if not, set this one as default @@ -167,12 +171,13 @@ App::patch('/v1/messaging/providers/:id/mailgun') ->param('id', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('isEuRegion', false, new Boolean(), 'Set as eu region.', true) + ->param('isEuRegion', null, new Boolean(), 'Set as eu region.', true) + ->param('from', '', new Text(256), 'Sender Email Address.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, bool $isEuRegion, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $id, string $name, ?bool $enabled, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $id); if ($provider->isEmpty()) { @@ -198,6 +203,12 @@ App::patch('/v1/messaging/providers/:id/mailgun') ]); } + if (!empty($from)) { + $provider->setAttribute('options', [ + 'from' => $from, + ]); + } + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -1232,6 +1243,7 @@ App::post('/v1/messaging/messages/email') ->param('providerId', '', new Text(128), 'Email Provider ID.') ->param('to', [], new ArrayList(new Text(65535)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(128), 'Email Subject.') + ->param('description', '', new Text(256), 'Description for Message.') ->param('content', '', new Text(65407), 'Email Content.') ->param('from', '', new Text(128), 'Email from.', true) ->param('html', false, new Boolean(false), 'Is content of type HTML', true) @@ -1239,7 +1251,7 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $subject, string $content, string $from, string $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $from, string $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); @@ -1257,7 +1269,8 @@ App::post('/v1/messaging/messages/email') 'subject' => $subject, 'content' => $content, 'from' => $from, - 'html' => $html + 'html' => $html, + 'description' => $description, ], 'status' => 'processing', 'search' => $subject . ' ' . $from, diff --git a/composer.lock b/composer.lock index 14b07bdce7..e739e122c9 100644 --- a/composer.lock +++ b/composer.lock @@ -1318,16 +1318,16 @@ }, { "name": "psr/http-client", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", "shasum": "" }, "require": { @@ -1364,9 +1364,9 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/1.0.2" + "source": "https://github.com/php-fig/http-client" }, - "time": "2023-04-10T20:12:12+00:00" + "time": "2023-09-23T14:17:50+00:00" }, { "name": "psr/http-factory", diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 96c8c9b989..2f75997048 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -56,6 +56,13 @@ class Message extends Any 'description' => 'Status of delivery.', 'default' => 'processing', 'example' => 'Message status can be one of the following: processing, sent, failed.', + ]) + ->addRule('description', [ + 'type' => self::TYPE_STRING, + 'description' => 'Message description.', + 'required' => false, + 'default' => '', + 'example' => 'Welcome Email.', ]); } diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index e33e5a253d..552e9783e8 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -45,6 +45,23 @@ class Provider extends Model 'description' => 'Type of provider.', 'default' => '', 'example' => 'sms', + ]) + ->addRule('credentials', [ + 'type' => self::TYPE_JSON, + 'description' => 'Provider credentials.', + 'default' => [], + 'example' => [ + 'key' => '123456789' + ], + ]) + ->addRule('options', [ + 'type' => self::TYPE_JSON, + 'description' => 'Provider options.', + 'default' => [], + 'required' => false, + 'example' => [ + 'from' => 'sender-email@mydomain' + ], ]); } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 65def00b48..59007cce15 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -19,6 +19,7 @@ trait MessagingBase 'name' => 'Mailgun1', 'apiKey' => 'my-apikey', 'domain' => 'my-domain', + 'from' => 'sender-email@my-domain', ], 'twilio' => [ 'providerId' => 'unique()', From 234f7f003be046fb8c18696c1c84f1c00e339364 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 27 Sep 2023 18:58:00 +0530 Subject: [PATCH 102/196] updated test cases for msg91 provider, moves worker to use provider from settings --- .env | 7 ++- app/config/collections.php | 2 +- app/controllers/api/account.php | 6 +- app/controllers/api/messaging.php | 17 +++--- app/controllers/api/teams.php | 3 +- app/workers/messaging.php | 55 +++++++++---------- docker-compose.yml | 5 ++ src/Appwrite/Event/Messaging.php | 20 +++---- .../Account/AccountCustomClientTest.php | 1 + tests/e2e/Services/GraphQL/AccountTest.php | 1 + tests/e2e/Services/GraphQL/Base.php | 2 + .../e2e/Services/Messaging/MessagingBase.php | 1 + 12 files changed, 67 insertions(+), 53 deletions(-) diff --git a/.env b/.env index 9117fe9f3b..7f41937b89 100644 --- a/.env +++ b/.env @@ -100,4 +100,9 @@ _APP_ASSISTANT_OPENAI_API_KEY= _APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID= _APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY= _APP_MESSAGE_SMS_PROVIDER_MSG91_FROM= -_APP_MESSAGE_SMS_PROVIDER_MSG91_TO= \ No newline at end of file +_APP_MESSAGE_SMS_PROVIDER_MSG91_TO= +_APP_MESSAGE_SMS_PROVIDER_MAILGUN_API_KEY= +_APP_MESSAGE_SMS_PROVIDER_MAILGUN_DOMAIN= +_APP_MESSAGE_SMS_PROVIDER_MAILGUN_FROM= +_APP_MESSAGE_SMS_PROVIDER_MAILGUN_RECEIVER_EMAIL= +_APP_MESSAGE_SMS_PROVIDER_MAILGUN_IS_EU_REGION= diff --git a/app/config/collections.php b/app/config/collections.php index 5506467cc4..9aec38a3d9 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1456,7 +1456,7 @@ $commonCollections = [ 'size' => 16384, 'signed' => true, 'required' => false, - 'default' => null, + 'default' => [], 'array' => false, 'filters' => ['json'], ], diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index e4ef089005..7115bf5686 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1343,14 +1343,13 @@ App::post('/v1/account/sessions/phone') 'to' => [$target->getId()], 'data' => [ 'content' => $message, - 'from' => $from, ], 'providerId' => $provider->getId(), 'providerInternalId' => $provider->getInternalId(), ])); $messaging - ->setMessage($messageDoc) + ->setMessageId($messageDoc->getId()) ->setProject($project) ->trigger(); @@ -2973,14 +2972,13 @@ App::post('/v1/account/verification/phone') 'to' => [$target->getId()], 'data' => [ 'content' => $message, - 'from' => $from, ], 'providerId' => $provider->getId(), 'providerInternalId' => $provider->getInternalId(), ])); $messaging - ->setMessage($messageDoc) + ->setMessageId($messageDoc->getId()) ->setProject($project) ->trigger(); diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 45c2760aba..9abf1d492f 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -262,6 +262,7 @@ App::post('/v1/messaging/providers/sendgrid') 'type' => 'email', 'default' => $default, 'enabled' => $enabled, + 'options' => [], 'search' => $providerId . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email', 'credentials' => [ 'apiKey' => $apiKey, @@ -361,11 +362,12 @@ App::post('/v1/messaging/providers/msg91') ->param('name', '', new Text(128), 'Provider name.') ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Text(256), 'Sender Number.') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $senderId, string $authKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $from, string $senderId, string $authKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -379,6 +381,9 @@ App::post('/v1/messaging/providers/msg91') 'senderId' => $senderId, 'authKey' => $authKey, ], + 'options' => [ + 'from' => $from, + ] ]); // Check if a default provider exists, if not, set this one as default @@ -1243,15 +1248,14 @@ App::post('/v1/messaging/messages/email') ->param('providerId', '', new Text(128), 'Email Provider ID.') ->param('to', [], new ArrayList(new Text(65535)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(128), 'Email Subject.') - ->param('description', '', new Text(256), 'Description for Message.') + ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(65407), 'Email Content.') - ->param('from', '', new Text(128), 'Email from.', true) ->param('html', false, new Boolean(false), 'Is content of type HTML', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $from, string $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); @@ -1268,16 +1272,15 @@ App::post('/v1/messaging/messages/email') 'data' => [ 'subject' => $subject, 'content' => $content, - 'from' => $from, 'html' => $html, 'description' => $description, ], 'status' => 'processing', - 'search' => $subject . ' ' . $from, + 'search' => $messageId . ' ' . $description . ' ' . $subject, ])); $messaging - ->setMessage($message) + ->setMessageId($message->getId()) ->setProject($project) ->trigger(); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 4a697bedbb..18c8118cb6 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -666,7 +666,6 @@ App::post('/v1/teams/:teamId/memberships') 'to' => [$target->getId()], 'data' => [ 'content' => $message, - 'from' => $from, ], 'providerId' => $provider->getId(), 'providerInternalId' => $provider->getInternalId(), @@ -674,7 +673,7 @@ App::post('/v1/teams/:teamId/memberships') ])); $messaging - ->setMessage($messageDoc) + ->setMessageId($messageDoc->getId()) ->setProject($project) ->trigger(); } diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 5b92bf59a0..b5dc79917d 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -91,7 +91,7 @@ class MessagingV1 extends Worker $project = new Document($this->args['project']); $this->dbForProject = $this->getProjectDB($project); - $messageRecord = new Document($this->args['message']); + $messageRecord = $this->dbForProject->getDocument('messages', $this->args['messageId']); $providerId = $messageRecord->getAttribute('providerId'); $providerRecord = $this->dbForProject->getDocument('providers', $providerId); @@ -135,15 +135,14 @@ class MessagingV1 extends Worker $maxBatchSize = $provider->getMaxMessagesPerRequest(); $batches = \array_chunk($identifiers, $maxBatchSize); - $message = $messageRecord->getArrayCopy(); $deliveredTo = 0; foreach ($batches as $batch) { - $message['to'] = $batch; + $messageRecord->setAttribute('to', $batch); $message = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($message), - 'push' => $this->buildPushMessage($message), - 'email' => $this->buildEmailMessage($message), + 'sms' => $this->buildSMSMessage($messageRecord, $providerRecord), + 'push' => $this->buildPushMessage($messageRecord), + 'email' => $this->buildEmailMessage($messageRecord, $providerRecord), default => null }; try { @@ -163,7 +162,7 @@ class MessagingV1 extends Worker } else { $messageRecord->setAttribute('status', 'sent'); } - + $messageRecord->setAttribute('to', $recipientsId); $messageRecord->setAttribute('deliveredTo', $deliveredTo); $messageRecord->setAttribute('deliveryTime', DateTime::now()); @@ -174,37 +173,37 @@ class MessagingV1 extends Worker { } - private function buildEmailMessage($data): Email + private function buildEmailMessage($message, $provider): Email { - $from = $data['data']['from']; - $to = $data['to']; - $subject = $data['data']['subject']; - $content = $data['data']['content']; - $html = $data['data']['html']; + $from = $provider['options']['from']; + $to = $message['to']; + $subject = $message['data']['subject']; + $content = $message['data']['content']; + $html = $message['data']['html']; return new Email(to: $to, subject: $subject, content: $content, from: $from, html: $html); } - private function buildSMSMessage($data): SMS + private function buildSMSMessage($message, $provider): SMS { - $to = $data['to']; - $content = $data['data']['content']; - $from = $data['data']['from']; + $to = $message['to']; + $content = $message['data']['content']; + $from = $provider['options']['from']; return new SMS($to, $content, $from); } - private function buildPushMessage($data): Push + private function buildPushMessage($message): Push { - $to = $data['to']; - $title = $data['data']['title']; - $body = $data['data']['body']; - $data = $data['data']['data']; - $action = $data['data']['action']; - $sound = $data['data']['sound']; - $icon = $data['data']['icon']; - $color = $data['data']['color']; - $tag = $data['data']['tag']; - $badge = $data['data']['badge']; + $to = $message['to']; + $title = $message['data']['title']; + $body = $message['data']['body']; + $data = $message['data']['data']; + $action = $message['data']['action']; + $sound = $message['data']['sound']; + $icon = $message['data']['icon']; + $color = $message['data']['color']; + $tag = $message['data']['tag']; + $badge = $message['data']['badge']; return new Push($to, $title, $body, $data, $action, $sound, $icon, $color, $tag, $badge); } } diff --git a/docker-compose.yml b/docker-compose.yml index 053042f81d..b60406369b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -190,6 +190,11 @@ services: - _APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY - _APP_MESSAGE_SMS_PROVIDER_MSG91_FROM - _APP_MESSAGE_SMS_PROVIDER_MSG91_TO + - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_API_KEY + - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_DOMAIN + - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_FROM + - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_RECEIVER_EMAIL + - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_IS_EU_REGION appwrite-realtime: entrypoint: realtime diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index 9616f93a21..1df75dfedf 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -7,7 +7,7 @@ use Utopia\Database\Document; class Messaging extends Event { - protected ?Document $message = null; + protected ?string $messageId = null; public function __construct() { @@ -17,26 +17,26 @@ class Messaging extends Event /** - * Sets message record for the messaging event. + * Sets message ID for the messaging event. * - * @param Document $message + * @param string $message * @return self */ - public function setMessage(Document $message): self + public function setMessageId(string $messageId): self { - $this->message = $message; + $this->messageId = $messageId; return $this; } /** - * Returns set message for the messaging event. + * Returns set message ID for the messaging event. * - * @return Document + * @return string */ - public function getMessage(): Document + public function getMessageId(): string { - return $this->message; + return $this->messageId; } /** @@ -50,7 +50,7 @@ class Messaging extends Event return Resque::enqueue($this->queue, $this->class, [ 'project' => $this->project, 'user' => $this->user, - 'message' => $this->message, + 'messageId' => $this->messageId, ]); } } diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 77d8662ba4..96f2b12308 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -765,6 +765,7 @@ class AccountCustomClientTest extends Scope 'senderId' => $senderId, 'authKey' => $authKey, 'default' => true, + 'from' => $from, ]); $this->assertEquals(201, $response['headers']['status-code']); /** diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index aa60d2d81b..5970883dbe 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -141,6 +141,7 @@ class AccountTest extends Scope 'name' => 'Sms Provider', 'provider' => 'msg91', 'type' => 'sms', + 'from' => $from, 'senderId' => $senderId, 'authKey' => $authKey, 'default' => true, diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 7f163fdffb..c670f8e17c 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1935,6 +1935,7 @@ trait Base return 'mutation createProviderMsg91( $providerId: String!, $name: String!, + $from: String!, $senderId: String!, $authKey: String! $default: Boolean, @@ -1943,6 +1944,7 @@ trait Base messagingCreateProviderMsg91( providerId: $providerId, name: $name, + from: $from, senderId: $senderId, authKey: $authKey default: $default, diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 59007cce15..bbc8b56693 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -44,6 +44,7 @@ trait MessagingBase 'name' => 'Ms91-1', 'senderId' => 'my-senderid', 'authKey' => 'my-authkey', + 'from' => '+123456789' ], 'vonage' => [ 'providerId' => 'unique()', From 7708779ef15965f4e30231e45251d5e38ce0cee0 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 27 Sep 2023 19:08:35 +0530 Subject: [PATCH 103/196] adds email endpoint test --- .../e2e/Services/Messaging/MessagingBase.php | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 3a131845a6..5654f01257 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -3,6 +3,7 @@ namespace Tests\E2E\Services\Messaging; use Tests\E2E\Client; +use Utopia\App; use Utopia\Database\Helpers\ID; trait MessagingBase @@ -366,4 +367,99 @@ trait MessagingBase ]); $this->assertEquals(204, $response['headers']['status-code']); } + + public function testSendEmail() + { + + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_RECEIVER_EMAIL'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_FROM'); + $apiKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_API_KEY'); + $domain = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_DOMAIN'); + $isEuRegion = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_IS_EU_REGION'); + if ($to === '' || $from === '' || $apiKey === '' || $domain === '' || $isEuRegion === '') { + $this->markTestSkipped('Email provider not configured'); + } + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/mailgun', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => 'unique()', + 'name' => 'Mailgun-provider', + 'apiKey' => $apiKey, + 'domain' => $domain, + 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), + 'from' => $from + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => 'unique()', + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::custom('test-user'), + 'email' => 'prateekbanga12@gmail.com', + 'password' => 'password', + 'name' => 'Messaging User', + ], false); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/test-user/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => 'unique()', + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create Email + $email = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => 'unique()', + 'providerId' => $provider['body']['$id'], + 'to' => [$target['body']['$id']], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ]); + + $this->assertEquals(201, $email['headers']['status-code']); + + } } From 1a50b2948f9a9026bd29620df78d6bd3046e5799 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 27 Sep 2023 19:10:56 +0530 Subject: [PATCH 104/196] lint fix --- tests/e2e/Services/Messaging/MessagingBase.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 5654f01257..97a5ad7d1d 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -370,7 +370,7 @@ trait MessagingBase public function testSendEmail() { - + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_RECEIVER_EMAIL'); $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_FROM'); $apiKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_API_KEY'); @@ -460,6 +460,5 @@ trait MessagingBase ]); $this->assertEquals(201, $email['headers']['status-code']); - } } From 48b91e39a81ef6a54ef7a8d4127090065911cd0d Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 4 Oct 2023 16:15:59 +0530 Subject: [PATCH 105/196] review changes --- app/config/collections.php | 7 + app/controllers/api/account.php | 49 +- app/controllers/api/messaging.php | 1376 ++++++++--------- app/controllers/api/users.php | 1 - app/workers/messaging.php | 156 +- composer.json | 2 +- composer.lock | 95 +- src/Appwrite/Event/Messaging.php | 1 - .../Account/AccountCustomClientTest.php | 8 +- tests/e2e/Services/GraphQL/AccountTest.php | 6 +- .../e2e/Services/Messaging/MessagingBase.php | 4 +- 11 files changed, 851 insertions(+), 854 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 9aec38a3d9..1a56b160c6 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1934,6 +1934,13 @@ $commonCollections = [ 'attributes' => ['providerInternalId'], 'lengths' => [], 'orders' => [], + ], + [ + '$id' => ID::custom('_key_identifier'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['identifier'], + 'lengths' => [], + 'orders' => [], ] ], ], diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 7115bf5686..228a0621cd 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1230,7 +1230,6 @@ App::post('/v1/account/sessions/phone') ->label('abuse-key', 'url:{url},phone:{param-phone}') ->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('request') ->inject('response') ->inject('user') @@ -1239,9 +1238,9 @@ App::post('/v1/account/sessions/phone') ->inject('events') ->inject('messaging') ->inject('locale') - ->action(function (string $userId, string $phone, string $from, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, Messaging $messaging, Locale $locale) { + ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, Messaging $messaging, Locale $locale) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true, false]), + Query::equal('default', [true]), Query::equal('type', ['sms']) ])); if ($provider === false || $provider->isEmpty()) { @@ -1330,13 +1329,20 @@ App::post('/v1/account/sessions/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); - $target = $dbForProject->createDocument('targets', new Document([ - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), - 'identifier' => $phone, - ])); + $target = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$phone]), + Query::equal('providerInternalId', [$provider->getInternalId()]) + ]); + + if (!$target) { + $target = $dbForProject->createDocument('targets', new Document([ + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'identifier' => $phone, + ])); + } $messageDoc = $dbForProject->createDocument('messages', new Document([ '$id' => $token->getId(), @@ -2899,7 +2905,6 @@ App::post('/v1/account/verification/phone') ->label('sdk.response.model', Response::MODEL_TOKEN) ->label('abuse-limit', 10) ->label('abuse-key', 'userId:{userId}') - ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('request') ->inject('response') ->inject('user') @@ -2908,9 +2913,9 @@ App::post('/v1/account/verification/phone') ->inject('messaging') ->inject('project') ->inject('locale') - ->action(function (string $from, Request $request, Response $response, Document $user, Database $dbForProject, Event $events, Messaging $messaging, Document $project, Locale $locale) { + ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events, Messaging $messaging, Document $project, Locale $locale) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true, false]), + Query::equal('default', [true]), Query::equal('type', ['sms']) ])); if ($provider === false || $provider->isEmpty()) { @@ -2959,13 +2964,17 @@ App::post('/v1/account/verification/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); - $target = $dbForProject->createDocument('targets', new Document([ - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), - 'identifier' => $user->getAttribute('phone'), - ])); + $target = $dbForProject->findOne('targets', [Query::equal('identifier', [$user->getAttribute('phone')]), Query::equal('providerInternalId', [$provider->getInternalId()])]); + + if (!$target) { + $target = $dbForProject->createDocument('targets', new Document([ + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'identifier' => $user->getAttribute('phone'), + ])); + } $messageDoc = $dbForProject->createDocument('messages', new Document([ '$id' => $verification->getId(), diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 9abf1d492f..f2a61cde36 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -22,6 +22,541 @@ use Utopia\Validator\JSON; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; +App::post('/v1/messaging/providers/mailgun') + ->desc('Create Mailgun Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createMailgunProvider') + ->label('sdk.description', '/docs/references/messaging/create-mailgun-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('isEuRegion', false, new Boolean(), 'Set as EU region.', true) + ->param('from', '', new Text(256), 'Sender Email Address.') + ->param('apiKey', '', new Text(0), 'Mailgun API Key.') + ->param('domain', '', new Text(0), 'Mailgun Domain.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $name, bool $default, bool $enabled, bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => 'mailgun', + 'type' => 'email', + 'default' => $default, + 'enabled' => $enabled, + 'search' => $providerId . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + 'domain' => $domain, + 'isEuRegion' => $isEuRegion, + ], + 'options' => [ + 'from' => $from, + ] + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + Query::equal('type', ['email']) + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/sendgrid') + ->desc('Create Sendgrid Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createSendgridProvider') + ->label('sdk.description', '/docs/references/messaging/create-sengrid-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('apiKey', '', new Text(0), 'Sendgrid API key.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => 'sendgrid', + 'type' => 'email', + 'default' => $default, + 'enabled' => $enabled, + 'options' => [], + 'search' => $providerId . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email', + 'credentials' => [ + 'apiKey' => $apiKey, + ], + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + Query::equal('type', ['sms']) + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/msg91') + ->desc('Create Msg91 Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createMsg91Provider') + ->label('sdk.description', '/docs/references/messaging/create-msg91-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Text(256), 'Sender Number.') + ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') + ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $from, string $senderId, string $authKey, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => 'msg91', + 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms', + 'default' => $default, + 'enabled' => $enabled, + 'credentials' => [ + 'senderId' => $senderId, + 'authKey' => $authKey, + ], + 'options' => [ + 'from' => $from, + ] + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + Query::equal('type', ['sms']) + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); +App::post('/v1/messaging/providers/telesign') + ->desc('Create Telesign Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createTelesignProvider') + ->label('sdk.description', '/docs/references/messaging/create-telesign-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('username', '', new Text(0), 'Telesign username.') + ->param('password', '', new Text(0), 'Telesign password.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => 'telesign', + 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms', + 'default' => $default, + 'enabled' => $enabled, + 'credentials' => [ + 'username' => $username, + 'password' => $password, + ], + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + Query::equal('type', ['sms']) + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/textmagic') + ->desc('Create Textmagic Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createTextmagicProvider') + ->label('sdk.description', '/docs/references/messaging/create-textmagic-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('username', '', new Text(0), 'Textmagic username.') + ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => 'text-magic', + 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'text-magic' . ' ' . 'sms', + 'default' => $default, + 'enabled' => $enabled, + 'credentials' => [ + 'username' => $username, + 'apiKey' => $apiKey, + ], + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + Query::equal('type', ['sms']) + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/twilio') + ->desc('Create Twilio Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createTwilioProvider') + ->label('sdk.description', '/docs/references/messaging/create-twilio-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') + ->param('authToken', '', new Text(0), 'Twilio authentication token.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => 'twilio', + 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms', + 'default' => $default, + 'enabled' => $enabled, + 'credentials' => [ + 'accountSid' => $accountSid, + 'authToken' => $authToken, + ], + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + Query::equal('type', ['sms']) + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/vonage') + ->desc('Create Vonage Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createVonageProvider') + ->label('sdk.description', '/docs/references/messaging/create-vonage-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('apiKey', '', new Text(0), 'Vonage API key.') + ->param('apiSecret', '', new Text(0), 'Vonage API secret.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => 'vonage', + 'type' => 'sms', + 'search' => $providerId . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms', + 'default' => $default, + 'enabled' => $enabled, + 'credentials' => [ + 'apiKey' => $apiKey, + 'apiSecret' => $apiSecret, + ], + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + Query::equal('type', ['sms']) + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/fcm') + ->desc('Create FCM Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createFCMProvider') + ->label('sdk.description', '/docs/references/messaging/create-fcm-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('serverKey', '', new Text(0), 'FCM Server Key.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => 'fcm', + 'type' => 'push', + 'search' => $providerId . ' ' . $name . ' ' . 'fcm' . ' ' . 'push', + 'default' => $default, + 'enabled' => $enabled, + 'credentials' => [ + 'serverKey' => $serverKey, + ], + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + Query::equal('type', ['pushq']) + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::post('/v1/messaging/providers/apns') + ->desc('Create APNS Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createAPNSProvider') + ->label('sdk.description', '/docs/references/messaging/create-apns-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('name', '', new Text(128), 'Provider name.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('authKey', '', new Text(0), 'APNS authentication key.') + ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') + ->param('teamId', '', new Text(0), 'APNS team ID.') + ->param('bundleId', '', new Text(0), 'APNS bundle ID.') + ->param('endpoint', '', new Text(0), 'APNS endpoint.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => 'apns', + 'type' => 'push', + 'search' => $providerId . ' ' . $name . ' ' . 'apns' . ' ' . 'push', + 'default' => $default, + 'enabled' => $enabled, + 'credentials' => [ + 'authKey' => $authKey, + 'authKeyId' => $authKeyId, + 'teamId' => $teamId, + 'bundleId' => $bundleId, + 'endpoint' => $endpoint, + ], + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + Query::equal('type', ['push']) + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + App::get('/v1/messaging/providers') ->desc('List Providers') ->groups(['api', 'messaging']) @@ -45,9 +580,8 @@ App::get('/v1/messaging/providers') if ($cursor) { $providerId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [ + $cursorDocument = Authorization::skip(fn () => $dbForProject->findOne('providers', [ Query::equal('$id', [$providerId]), - Query::limit(1), ])); if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { @@ -88,74 +622,7 @@ App::get('/v1/messaging/providers/:id') $response->dynamic($provider, Response::MODEL_PROVIDER); }); -/** - * Email Providers - */ -App::post('/v1/messaging/providers/mailgun') - ->desc('Create Mailgun Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderMailgun') - ->label('sdk.description', '/docs/references/messaging/create-provider-mailgun.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('isEuRegion', false, new Boolean(), 'Set as EU region.', true) - ->param('from', '', new Text(256), 'Sender Email Address.') - ->param('apiKey', '', new Text(0), 'Mailgun API Key.') - ->param('domain', '', new Text(0), 'Mailgun Domain.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => 'mailgun', - 'type' => 'email', - 'default' => $default, - 'enabled' => $enabled, - 'search' => $providerId . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email', - 'credentials' => [ - 'apiKey' => $apiKey, - 'domain' => $domain, - 'isEuRegion' => $isEuRegion, - ], - 'options' => [ - 'from' => $from, - ] - ]); - - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/mailgun') +App::patch('/v1/messaging/providers/mailgun/:id') ->desc('Update Mailgun Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -163,8 +630,8 @@ App::patch('/v1/messaging/providers/:id/mailgun') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderMailgun') - ->label('sdk.description', '/docs/references/messaging/update-provider-mailgun.md') + ->label('sdk.method', 'updateMailgunProvider') + ->label('sdk.description', '/docs/references/messaging/update-mailgun-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) @@ -194,15 +661,6 @@ App::patch('/v1/messaging/providers/:id/mailgun') $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email'); } - if ($isEuRegion === true || $isEuRegion === false) { - $credentials = $provider->getAttribute('credentials'); - $provider->setAttribute('credentials', [ - 'isEuRegion' => $isEuRegion, - 'apiKey' => $credentials['apiKey'], - 'domain' => $credentials['domain'], - ]); - } - if (!empty($from)) { $provider->setAttribute('options', [ 'from' => $from, @@ -213,83 +671,29 @@ App::patch('/v1/messaging/providers/:id/mailgun') $provider->setAttribute('enabled', $enabled); } - if ($apiKey || $domain) { - // Check if all credential variables are present - if ($apiKey && $domain) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'domain' => $domain, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + $credentials = $provider->getAttribute('credentials'); + + if ($isEuRegion === true || $isEuRegion === false) { + $credentials['isEuRegion'] = $isEuRegion; } + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + if (!empty($domain)) { + $credentials['domain'] = $domain; + } + + $provider->setAttribute('credentials', $credentials); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::post('/v1/messaging/providers/sendgrid') - ->desc('Create Sendgrid Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderSendgrid') - ->label('sdk.description', '/docs/references/messaging/create-provider-sendgrid.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('apiKey', '', new Text(0), 'Sendgrid API key.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => 'sendgrid', - 'type' => 'email', - 'default' => $default, - 'enabled' => $enabled, - 'options' => [], - 'search' => $providerId . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email', - 'credentials' => [ - 'apiKey' => $apiKey, - ], - ]); - - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/sendgrid') +App::patch('/v1/messaging/providers/sendgrid/:id') ->desc('Update Sendgrid Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -297,8 +701,8 @@ App::patch('/v1/messaging/providers/:id/sendgrid') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderSendgrid') - ->label('sdk.description', '/docs/references/messaging/update-provider-sendgrid.md') + ->label('sdk.method', 'updateSendgridProvider') + ->label('sdk.description', '/docs/references/messaging/update-sendgrid-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) @@ -329,84 +733,19 @@ App::patch('/v1/messaging/providers/:id/sendgrid') $provider->setAttribute('enabled', $enabled); } - if ($apiKey) { + if (!empty($apiKey)) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, ]); } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response ->dynamic($provider, Response::MODEL_PROVIDER); }); -/** - * SMS Providers - */ -App::post('/v1/messaging/providers/msg91') - ->desc('Create Msg91 Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderMsg91') - ->label('sdk.description', '/docs/references/messaging/create-provider-msg91.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('from', '', new Text(256), 'Sender Number.') - ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') - ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $from, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => 'msg91', - 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms', - 'default' => $default, - 'enabled' => $enabled, - 'credentials' => [ - 'senderId' => $senderId, - 'authKey' => $authKey, - ], - 'options' => [ - 'from' => $from, - ] - ]); - - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/msg91') +App::patch('/v1/messaging/providers/msg91/:id') ->desc('Update Msg91 Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -414,8 +753,8 @@ App::patch('/v1/messaging/providers/:id/msg91') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderMsg91') - ->label('sdk.description', '/docs/references/messaging/update-provider-msg91.md') + ->label('sdk.method', 'updateMsg91Provider') + ->label('sdk.description', '/docs/references/messaging/update-msg91-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) @@ -447,84 +786,25 @@ App::patch('/v1/messaging/providers/:id/msg91') $provider->setAttribute('enabled', $enabled); } - if ($senderId || $authKey) { - // Check if all credential variables are present - if ($senderId && $authKey) { - $provider->setAttribute('credentials', [ - 'senderId' => $senderId, - 'authKey' => $authKey, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + $credentials = $provider->getAttribute('credentials'); + + if (!empty($senderId)) { + $credentials['senderId'] = $senderId; } + if (!empty($authKey)) { + $credentials['authKey'] = $authKey; + } + + $provider->setAttribute('credentials', $credentials); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::post('/v1/messaging/providers/telesign') - ->desc('Create Telesign Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderTelesign') - ->label('sdk.description', '/docs/references/messaging/create-provider-telesign.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('username', '', new Text(0), 'Telesign username.') - ->param('password', '', new Text(0), 'Telesign password.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => 'telesign', - 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms', - 'default' => $default, - 'enabled' => $enabled, - 'credentials' => [ - 'username' => $username, - 'password' => $password, - ], - ]); - - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/telesign') +App::patch('/v1/messaging/providers/telesign/:id') ->desc('Update Telesign Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -532,8 +812,8 @@ App::patch('/v1/messaging/providers/:id/telesign') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderTelesign') - ->label('sdk.description', '/docs/references/messaging/update-provider-telesign.md') + ->label('sdk.method', 'updateTelesignProvider') + ->label('sdk.description', '/docs/references/messaging/update-telesign-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) @@ -565,84 +845,25 @@ App::patch('/v1/messaging/providers/:id/telesign') $provider->setAttribute('enabled', $enabled); } - if ($username || $password) { - // Check if all credential variables are present - if ($username && $password) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'password' => $password, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + $credentials = $provider->getAttribute('credentials'); + + if (!empty($username)) { + $credentials['username'] = $username; } + if (!empty($password)) { + $credentials['password'] = $password; + } + + $provider->setAttribute('credentials', $credentials); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::post('/v1/messaging/providers/textmagic') - ->desc('Create Textmagic Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderTextmagic') - ->label('sdk.description', '/docs/references/messaging/create-provider-textmagic.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('username', '', new Text(0), 'Textmagic username.') - ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => 'text-magic', - 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'text-magic' . ' ' . 'sms', - 'default' => $default, - 'enabled' => $enabled, - 'credentials' => [ - 'username' => $username, - 'apiKey' => $apiKey, - ], - ]); - - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/textmagic') +App::patch('/v1/messaging/providers/textmagic/:id') ->desc('Update Textmagic Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -650,8 +871,8 @@ App::patch('/v1/messaging/providers/:id/textmagic') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderTextmagic') - ->label('sdk.description', '/docs/references/messaging/update-provider-textmagic.md') + ->label('sdk.method', 'updateTextmagicProvider') + ->label('sdk.description', '/docs/references/messaging/update-textmagic-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) @@ -683,84 +904,25 @@ App::patch('/v1/messaging/providers/:id/textmagic') $provider->setAttribute('enabled', $enabled); } - if ($username || $apiKey) { - // Check if all credential variables are present - if ($username && $apiKey) { - $provider->setAttribute('credentials', [ - 'username' => $username, - 'apiKey' => $apiKey, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + $credentials = $provider->getAttribute('credentials'); + + if (!empty($username)) { + $credentials['username'] = $username; } + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + $provider->setAttribute('credentials', $credentials); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::post('/v1/messaging/providers/twilio') - ->desc('Create Twilio Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderTwilio') - ->label('sdk.description', '/docs/references/messaging/create-provider-twilio.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') - ->param('authToken', '', new Text(0), 'Twilio authentication token.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => 'twilio', - 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms', - 'default' => $default, - 'enabled' => $enabled, - 'credentials' => [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ], - ]); - - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/twilio') +App::patch('/v1/messaging/providers/twilio/:id') ->desc('Update Twilio Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -768,8 +930,8 @@ App::patch('/v1/messaging/providers/:id/twilio') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderTwilio') - ->label('sdk.description', '/docs/references/messaging/update-provider-twilio.md') + ->label('sdk.method', 'updateTwilioProvider') + ->label('sdk.description', '/docs/references/messaging/update-twilio-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) @@ -801,84 +963,25 @@ App::patch('/v1/messaging/providers/:id/twilio') $provider->setAttribute('enabled', $enabled); } - if ($accountSid || $authToken) { - // Check if all credential variables are present - if ($accountSid && $authToken) { - $provider->setAttribute('credentials', [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + $credentials = $provider->getAttribute('credentials'); + + if (!empty($accountSid)) { + $credentials['accountSid'] = $accountSid; } + if (!empty($authToken)) { + $credentials['authToken'] = $authToken; + } + + $provider->setAttribute('credentials', $credentials); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::post('/v1/messaging/providers/vonage') - ->desc('Create Vonage Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderVonage') - ->label('sdk.description', '/docs/references/messaging/create-provider-vonage.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('apiKey', '', new Text(0), 'Vonage API key.') - ->param('apiSecret', '', new Text(0), 'Vonage API secret.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => 'vonage', - 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms', - 'default' => $default, - 'enabled' => $enabled, - 'credentials' => [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ], - ]); - - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/vonage') +App::patch('/v1/messaging/providers/vonage/:id') ->desc('Update Vonage Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -886,8 +989,8 @@ App::patch('/v1/messaging/providers/:id/vonage') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderVonage') - ->label('sdk.description', '/docs/references/messaging/update-provider-vonage.md') + ->label('sdk.method', 'updateVonageProvider') + ->label('sdk.description', '/docs/references/messaging/update-vonage-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) @@ -919,85 +1022,25 @@ App::patch('/v1/messaging/providers/:id/vonage') $provider->setAttribute('enabled', $enabled); } - if ($apiKey || $apiSecret) { - // Check if all credential variables are present - if ($apiKey && $apiSecret) { - $provider->setAttribute('credentials', [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + $credentials = $provider->getAttribute('credentials'); + + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; } + if (!empty($apiSecret)) { + $credentials['apiSecret'] = $apiSecret; + } + + $provider->setAttribute('credentials', $credentials); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response ->dynamic($provider, Response::MODEL_PROVIDER); }); -/** - * Push Providers - */ -App::post('/v1/messaging/providers/fcm') - ->desc('Create FCM Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderFCM') - ->label('sdk.description', '/docs/references/messaging/create-provider-fcm.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('serverKey', '', new Text(0), 'FCM Server Key.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => 'fcm', - 'type' => 'push', - 'search' => $providerId . ' ' . $name . ' ' . 'fcm' . ' ' . 'push', - 'default' => $default, - 'enabled' => $enabled, - 'credentials' => [ - 'serverKey' => $serverKey, - ], - ]); - - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/fcm') +App::patch('/v1/messaging/providers/fcm/:id') ->desc('Update FCM Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -1005,8 +1048,8 @@ App::patch('/v1/messaging/providers/:id/fcm') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderFCM') - ->label('sdk.description', '/docs/references/messaging/update-provider-fcm.md') + ->label('sdk.method', 'updateFCMProvider') + ->label('sdk.description', '/docs/references/messaging/update-fcm-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) @@ -1037,81 +1080,18 @@ App::patch('/v1/messaging/providers/:id/fcm') $provider->setAttribute('enabled', $enabled); } - if ($serverKey) { + if (!empty($serverKey)) { $provider->setAttribute('credentials', ['serverKey' => $serverKey]); } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::post('/v1/messaging/providers/apns') - ->desc('Create APNS Provider') - ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') - ->label('audits.resource', 'providers/{response.$id}') - ->label('scope', 'providers.write') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createProviderAPNS') - ->label('sdk.description', '/docs/references/messaging/create-provider-apns.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('authKey', '', new Text(0), 'APNS authentication key.') - ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') - ->param('teamId', '', new Text(0), 'APNS team ID.') - ->param('bundleId', '', new Text(0), 'APNS bundle ID.') - ->param('endpoint', '', new Text(0), 'APNS endpoint.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $provider = new Document([ - '$id' => $providerId, - 'name' => $name, - 'provider' => 'apns', - 'type' => 'push', - 'search' => $providerId . ' ' . $name . ' ' . 'apns' . ' ' . 'push', - 'default' => $default, - 'enabled' => $enabled, - 'credentials' => [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ], - ]); - // Check if a default provider exists, if not, set this one as default - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - ])) - ) { - $provider->setAttribute('default', true); - } - - try { - $provider = $dbForProject->createDocument('providers', $provider); - } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($provider, Response::MODEL_PROVIDER); - }); - -App::patch('/v1/messaging/providers/:id/apns') +App::patch('/v1/messaging/providers/apns/:id') ->desc('Update APNS Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -1119,8 +1099,8 @@ App::patch('/v1/messaging/providers/:id/apns') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateProviderAPNS') - ->label('sdk.description', '/docs/references/messaging/update-provider-apns.md') + ->label('sdk.method', 'updateAPNSProvider') + ->label('sdk.description', '/docs/references/messaging/update-apns-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) @@ -1155,24 +1135,31 @@ App::patch('/v1/messaging/providers/:id/apns') $provider->setAttribute('enabled', $enabled); } - if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) { - // Check if all credential variables are present - if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) { - $provider->setAttribute('credentials', [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ]); - } else { - // Not all credential params are present - throw new Exception(Exception::DOCUMENT_MISSING_DATA); - } + $credentials = $provider->getAttribute('credentials'); + + if (!empty($authKey)) { + $credentials['authKey'] = $authKey; } + if (!empty($authKeyId)) { + $credentials['authKeyId'] = $authKeyId; + } + + if (!empty($teamId)) { + $credentials['teamId'] = $teamId; + } + + if (!empty($bundleId)) { + $credentials['bundle'] = $bundleId; + } + + if (!empty($endpoint)) { + $credentials['endpoint'] = $endpoint; + } + + $provider->setAttribute('credentials', $credentials); + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $response ->dynamic($provider, Response::MODEL_PROVIDER); @@ -1201,36 +1188,11 @@ App::delete('/v1/messaging/providers/:id') throw new Exception(Exception::PROVIDER_NOT_FOUND); } - $dbForProject->deleteCachedDocument('providers', $provider->getId()); $dbForProject->deleteDocument('providers', $provider->getId()); $response->noContent(); }); -App::get('/v1/messaging/messages/:id') - ->desc('Get Message') - ->groups(['api', 'messaging']) - ->label('scope', 'messages.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'getMessage') - ->label('sdk.description', '/docs/references/messaging/get-message.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_MESSAGE) - ->param('id', '', new UID(), 'Message ID.') - ->inject('dbForProject') - ->inject('response') - ->action(function (string $id, Database $dbForProject, Response $response) { - $message = $dbForProject->getDocument('messages', $id); - - if ($message->isEmpty()) { - throw new Exception(Exception::MESSAGE_NOT_FOUND); - } - - $response->dynamic($message, Response::MODEL_MESSAGE); - }); - App::post('/v1/messaging/messages/email') ->desc('Send an email.') ->groups(['api', 'messaging']) @@ -1245,12 +1207,12 @@ App::post('/v1/messaging/messages/email') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('providerId', '', new Text(128), 'Email Provider ID.') + ->param('providerId', '', new UID(), 'Email Provider ID.') ->param('to', [], new ArrayList(new Text(65535)), 'List of Topic IDs or List of User IDs or List of Target IDs.') - ->param('subject', '', new Text(128), 'Email Subject.') + ->param('subject', '', new Text(998), 'Email Subject.') ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(65407), 'Email Content.') - ->param('html', false, new Boolean(false), 'Is content of type HTML', true) + ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') @@ -1280,11 +1242,35 @@ App::post('/v1/messaging/messages/email') ])); $messaging - ->setMessageId($message->getId()) - ->setProject($project) - ->trigger(); + ->setMessageId($message->getId()) + ->setProject($project) + ->trigger(); $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($message, Response::MODEL_MESSAGE); }); + +App::get('/v1/messaging/messages/:id') + ->desc('Get Message') + ->groups(['api', 'messaging']) + ->label('scope', 'messages.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'getMessage') + ->label('sdk.description', '/docs/references/messaging/get-message.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('id', '', new UID(), 'Message ID.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, Database $dbForProject, Response $response) { + $message = $dbForProject->getDocument('messages', $id); + + if ($message->isEmpty()) { + throw new Exception(Exception::MESSAGE_NOT_FOUND); + } + + $response->dynamic($message, Response::MODEL_MESSAGE); + }); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 9b2dc516cb..244bc1150b 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1228,7 +1228,6 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - // Update the target identifier here $target->setAttribute('identifier', $identifier); $target = $dbForProject->updateDocument('targets', $target->getId(), $target); diff --git a/app/workers/messaging.php b/app/workers/messaging.php index b5dc79917d..8e25a8210c 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -22,6 +22,9 @@ use Utopia\Messaging\Adapters\Email\SendGrid; use Utopia\Messaging\Messages\Email; use Utopia\Messaging\Messages\Push; use Utopia\Messaging\Messages\SMS; +use Appwrite\Extend\Exception; + +use function Swoole\Coroutine\batch; require_once __DIR__ . '/../init.php'; @@ -39,48 +42,9 @@ class MessagingV1 extends Worker public function getName(): string { - return "mails"; + return "messaging"; } - public function sms($record): ?SMSAdapter - { - $credentials = $record->getAttribute('credentials'); - return match ($record->getAttribute('provider')) { - 'mock' => new Mock('username', 'password'), - 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), - 'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']), - 'telesign' => new Telesign($credentials['username'], $credentials['password']), - 'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']), - 'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']), - default => null - }; - } - - public function push($record): ?PushAdapter - { - $credentials = $record->getAttribute('credentials'); - return match ($record->getAttribute('provider')) { - 'apns' => new APNS( - $credentials['authKey'], - $credentials['authKeyId'], - $credentials['teamId'], - $credentials['bundleId'], - $credentials['endpoint'] - ), - 'fcm' => new FCM($credentials['serverKey']), - default => null - }; - } - - public function email($record): ?EmailAdapter - { - $credentials = $record->getAttribute('credentials'); - return match ($record->getAttribute('provider')) { - 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain'], $credentials['isEuRegion']), - 'sendgrid' => new SendGrid($credentials['apiKey']), - default => null - }; - } public function init(): void { @@ -91,12 +55,11 @@ class MessagingV1 extends Worker $project = new Document($this->args['project']); $this->dbForProject = $this->getProjectDB($project); - $messageRecord = $this->dbForProject->getDocument('messages', $this->args['messageId']); + $message = $this->dbForProject->getDocument('messages', $this->args['messageId']); - $providerId = $messageRecord->getAttribute('providerId'); - $providerRecord = $this->dbForProject->getDocument('providers', $providerId); + $provider = $this->dbForProject->getDocument('providers', $message->getAttribute('providerId')); - $this->processMessage($messageRecord, $providerRecord); + $this->processMessage($message, $provider); } private function processMessage(Document $messageRecord, Document $providerRecord): void @@ -105,7 +68,7 @@ class MessagingV1 extends Worker 'sms' => $this->sms($providerRecord), 'push' => $this->push($providerRecord), 'email' => $this->email($providerRecord), - default => null + default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; $recipientsId = $messageRecord->getAttribute('to'); @@ -115,7 +78,6 @@ class MessagingV1 extends Worker */ $recipients = []; - $topics = $this->dbForProject->find('topics', [Query::equal('$id', $recipientsId)]); foreach ($topics as $topic) { $recipients = \array_merge($recipients, $topic->getAttribute('targets')); @@ -128,6 +90,7 @@ class MessagingV1 extends Worker $targets = $this->dbForProject->find('targets', [Query::equal('$id', $recipientsId)]); $recipients = \array_merge($recipients, $targets); + $recipients = \array_filter($recipients, fn (Document $recipient) => $recipient->getAttribute('providerId') === $providerRecord->getId()); $identifiers = \array_map(function (Document $recipient) { return $recipient->getAttribute('identifier'); @@ -135,27 +98,42 @@ class MessagingV1 extends Worker $maxBatchSize = $provider->getMaxMessagesPerRequest(); $batches = \array_chunk($identifiers, $maxBatchSize); - $deliveredTo = 0; - foreach ($batches as $batch) { - $messageRecord->setAttribute('to', $batch); - $message = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($messageRecord, $providerRecord), - 'push' => $this->buildPushMessage($messageRecord), - 'email' => $this->buildEmailMessage($messageRecord, $providerRecord), - default => null - }; - try { - $provider->send($message); - $deliveredTo += \count($batch); - } catch (Exception $e) { - $deliveryErrors = $messageRecord->getAttribute('deliveryErrors'); - foreach ($batch as $identifier) { - $deliveryErrors[] = 'Failed to send message to target' . $identifier . ': ' . $e->getMessage(); + $results = batch(\array_map(function ($batch) use ($messageRecord, $providerRecord, $provider) { + return function () use ($batch, $messageRecord, $providerRecord, $provider) { + $deliveredTo = 0; + $deliveryErrors = []; + $messageData = clone $messageRecord; + $messageData->setAttribute('to', $batch); + $message = match ($providerRecord->getAttribute('type')) { + 'sms' => $this->buildSMSMessage($messageRecord, $providerRecord), + 'push' => $this->buildPushMessage($messageRecord), + 'email' => $this->buildEmailMessage($messageRecord, $providerRecord), + default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) + }; + try { + $provider->send($message); + $deliveredTo += \count($batch); + } catch (Exception $e) { + foreach ($batch as $identifier) { + $deliveryErrors[] = 'Failed to send message to target' . $identifier . ': ' . $e->getMessage(); + } + } finally { + return [ + 'deliveredTo' => $deliveredTo, + 'deliveryErrors' => $deliveryErrors, + ]; } - $messageRecord->setAttribute('deliveryErrors', $deliveryErrors); - } + }; + }, $batches)); + + $deliveredTo = 0; + $deliveryErrors = []; + foreach ($results as $result) { + $deliveredTo += $result['deliveredTo']; + $deliveryErrors = \array_merge($deliveryErrors, $result['deliveryErrors']); } + $messageRecord->setAttribute('deliveryErrors', $deliveryErrors); if (\count($messageRecord->getAttribute('deliveryErrors')) > 0) { $messageRecord->setAttribute('status', 'failed'); @@ -173,17 +151,58 @@ class MessagingV1 extends Worker { } - private function buildEmailMessage($message, $provider): Email + private function sms(Document $document): ?SMSAdapter + { + $credentials = $document->getAttribute('credentials'); + return match ($document->getAttribute('provider')) { + 'mock' => new Mock('username', 'password'), + 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), + 'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']), + 'telesign' => new Telesign($credentials['username'], $credentials['password']), + 'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']), + 'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']), + default => null + }; + } + + private function push(Document $document): ?PushAdapter + { + $credentials = $document->getAttribute('credentials'); + return match ($document->getAttribute('provider')) { + 'apns' => new APNS( + $credentials['authKey'], + $credentials['authKeyId'], + $credentials['teamId'], + $credentials['bundleId'], + $credentials['endpoint'] + ), + 'fcm' => new FCM($credentials['serverKey']), + default => null + }; + } + + private function email(Document $document): ?EmailAdapter + { + $credentials = $document->getAttribute('credentials'); + return match ($document->getAttribute('provider')) { + 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain'], $credentials['isEuRegion']), + 'sendgrid' => new SendGrid($credentials['apiKey']), + default => null + }; + } + + private function buildEmailMessage(Document $message, Document $provider): Email { $from = $provider['options']['from']; $to = $message['to']; $subject = $message['data']['subject']; $content = $message['data']['content']; $html = $message['data']['html']; - return new Email(to: $to, subject: $subject, content: $content, from: $from, html: $html); + + return new Email($to, $subject, $content, $from, null, $html); } - private function buildSMSMessage($message, $provider): SMS + private function buildSMSMessage(Document $message, Document $provider): SMS { $to = $message['to']; $content = $message['data']['content']; @@ -192,7 +211,7 @@ class MessagingV1 extends Worker return new SMS($to, $content, $from); } - private function buildPushMessage($message): Push + private function buildPushMessage(Document $message): Push { $to = $message['to']; $title = $message['data']['title']; @@ -204,6 +223,7 @@ class MessagingV1 extends Worker $color = $message['data']['color']; $tag = $message['data']['tag']; $badge = $message['data']['badge']; + return new Push($to, $title, $body, $data, $action, $sound, $icon, $color, $tag, $badge); } } diff --git a/composer.json b/composer.json index 3425c98419..efa0179f3b 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ "utopia-php/image": "0.5.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.3.*", - "utopia-php/messaging": "dev-feat-push as 0.1.1", + "utopia-php/messaging": "0.2.*", "utopia-php/migration": "0.3.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.4.*", diff --git a/composer.lock b/composer.lock index e739e122c9..13040c831d 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": "6431be75373bf2e1bdbe2c638188d15f", + "content-hash": "237609b7e9fb20d807aa6e773bf72de6", "packages": [ { "name": "adhocore/jwt", @@ -1050,16 +1050,16 @@ }, { "name": "matomo/device-detector", - "version": "6.1.5", + "version": "6.1.6", "source": { "type": "git", "url": "https://github.com/matomo-org/device-detector.git", - "reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4" + "reference": "5cbea85106e561c7138d03603eb6e05128480409" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/40ca2990dba2c1719e5c62168e822e0b86c167d4", - "reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4", + "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/5cbea85106e561c7138d03603eb6e05128480409", + "reference": "5cbea85106e561c7138d03603eb6e05128480409", "shasum": "" }, "require": { @@ -1115,7 +1115,7 @@ "source": "https://github.com/matomo-org/matomo", "wiki": "https://dev.matomo.org/" }, - "time": "2023-08-17T16:17:41+00:00" + "time": "2023-10-02T10:01:54+00:00" }, { "name": "mongodb/mongodb", @@ -2152,16 +2152,16 @@ }, { "name": "utopia-php/database", - "version": "0.43.2", + "version": "0.43.4", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "f2626acd42665a9987c94af1c93bf20c28d55c9d" + "reference": "cabdd02e8dc1732eb0b22007c511e7bb3caa5c8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/f2626acd42665a9987c94af1c93bf20c28d55c9d", - "reference": "f2626acd42665a9987c94af1c93bf20c28d55c9d", + "url": "https://api.github.com/repos/utopia-php/database/zipball/cabdd02e8dc1732eb0b22007c511e7bb3caa5c8c", + "reference": "cabdd02e8dc1732eb0b22007c511e7bb3caa5c8c", "shasum": "" }, "require": { @@ -2202,9 +2202,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.43.2" + "source": "https://github.com/utopia-php/database/tree/0.43.4" }, - "time": "2023-09-07T19:04:33+00:00" + "time": "2023-09-28T09:00:05+00:00" }, { "name": "utopia-php/domains", @@ -2516,16 +2516,16 @@ }, { "name": "utopia-php/messaging", - "version": "dev-feat-push", + "version": "0.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "2bb09220d0993a9f8f0afc63ff51382b13d93e18" + "reference": "2d0f474a106bb1da285f85e105c29b46085d3a43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/2bb09220d0993a9f8f0afc63ff51382b13d93e18", - "reference": "2bb09220d0993a9f8f0afc63ff51382b13d93e18", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/2d0f474a106bb1da285f85e105c29b46085d3a43", + "reference": "2d0f474a106bb1da285f85e105c29b46085d3a43", "shasum": "" }, "require": { @@ -2558,22 +2558,22 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/feat-push" + "source": "https://github.com/utopia-php/messaging/tree/0.2.0" }, - "time": "2023-09-14T20:29:49+00:00" + "time": "2023-09-14T20:48:42+00:00" }, { "name": "utopia-php/migration", - "version": "0.3.4", + "version": "0.3.5", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "ade836d61b3e1547bc9f0dc300ee75b24ab49f7a" + "reference": "b2fd3a8310296f4e44ff0e85b0eb0230ad9a2f83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/ade836d61b3e1547bc9f0dc300ee75b24ab49f7a", - "reference": "ade836d61b3e1547bc9f0dc300ee75b24ab49f7a", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/b2fd3a8310296f4e44ff0e85b0eb0230ad9a2f83", + "reference": "b2fd3a8310296f4e44ff0e85b0eb0230ad9a2f83", "shasum": "" }, "require": { @@ -2596,16 +2596,6 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - }, - { - "name": "Bradley Schofield", - "email": "bradley@appwrite.io" - } - ], "description": "A simple library to migrate resources between services.", "keywords": [ "framework", @@ -2616,9 +2606,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.3.4" + "source": "https://github.com/utopia-php/migration/tree/0.3.5" }, - "time": "2023-09-14T17:17:55+00:00" + "time": "2023-09-25T16:51:47+00:00" }, { "name": "utopia-php/mongo", @@ -3442,16 +3432,16 @@ }, { "name": "doctrine/deprecations", - "version": "v1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", "shasum": "" }, "require": { @@ -3483,9 +3473,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" + "source": "https://github.com/doctrine/deprecations/tree/1.1.2" }, - "time": "2023-06-03T09:27:29+00:00" + "time": "2023-09-27T20:04:15+00:00" }, { "name": "doctrine/instantiator", @@ -4145,16 +4135,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.1", + "version": "1.24.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01" + "reference": "bcad8d995980440892759db0c32acae7c8e79442" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01", - "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442", + "reference": "bcad8d995980440892759db0c32acae7c8e79442", "shasum": "" }, "require": { @@ -4186,9 +4176,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.24.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.2" }, - "time": "2023-09-18T12:18:02+00:00" + "time": "2023-09-26T12:28:12+00:00" }, { "name": "phpunit/php-code-coverage", @@ -6001,18 +5991,9 @@ "time": "2023-08-28T11:09:02+00:00" } ], - "aliases": [ - { - "package": "utopia-php/messaging", - "version": "dev-feat-push", - "alias": "0.1.1", - "alias_normalized": "0.1.1.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/messaging": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index 1df75dfedf..cbfb7981ac 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -15,7 +15,6 @@ class Messaging extends Event } - /** * Sets message ID for the messaging event. * diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 96f2b12308..7f4cb84b05 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -748,7 +748,7 @@ class AccountCustomClientTest extends Scope $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); - if ($to === '' || $from === '' || $authKey === '' || $senderId === '') { + if (empty($to) || empty($from) || empty($authKey) || empty($senderId)) { $this->markTestSkipped('SMS provider not configured'); } @@ -758,10 +758,8 @@ class AccountCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Sms provider', - 'provider' => 'msg91', - 'type' => 'sms', 'senderId' => $senderId, 'authKey' => $authKey, 'default' => true, @@ -1032,7 +1030,7 @@ class AccountCustomClientTest extends Scope $this->assertEmpty($response['body']['secret']); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['expire'])); - \sleep(2); + \sleep(3); $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $response['body']['$id'], [ 'origin' => 'http://localhost', diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 5970883dbe..dc399cf2b3 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -128,7 +128,7 @@ class AccountTest extends Scope $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); - if ($to === '' || $from === '' || $authKey === '' || $senderId === '') { + if (empty($to) || empty($from) || empty($authKey) || empty($senderId)) { $this->markTestSkipped('SMS provider not configured'); } @@ -137,10 +137,8 @@ class AccountTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Sms Provider', - 'provider' => 'msg91', - 'type' => 'sms', 'from' => $from, 'senderId' => $senderId, 'authKey' => $authKey, diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index bbc8b56693..05092fdd2e 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -137,7 +137,7 @@ trait MessagingBase ], ]; foreach (\array_keys($providersParams) as $index => $key) { - $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/' . $providers[$index]['$id'] . '/' . $key, [ + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/' . $key . '/' . $providers[$index]['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -147,7 +147,7 @@ trait MessagingBase $this->assertEquals($providersParams[$key]['name'], $response['body']['name']); } - $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/' . $providers[1]['$id'] . '/mailgun', [ + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/mailgun/' . $providers[1]['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], From 61785ab35a25d7ccec44f67836a259b4e61635a7 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 4 Oct 2023 16:19:05 +0530 Subject: [PATCH 106/196] typo fix --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index f2a61cde36..3fc88791c2 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -476,7 +476,7 @@ App::post('/v1/messaging/providers/fcm') if ( empty($dbForProject->findOne('providers', [ Query::equal('default', [true]), - Query::equal('type', ['pushq']) + Query::equal('type', ['push']) ])) ) { $provider->setAttribute('default', true); From c9c49158a3acaa130ef21c7328999bd3aefe74a6 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 4 Oct 2023 16:24:29 +0530 Subject: [PATCH 107/196] changes to validator length --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 3fc88791c2..d9b5543e5c 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1208,7 +1208,7 @@ App::post('/v1/messaging/messages/email') ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('providerId', '', new UID(), 'Email Provider ID.') - ->param('to', [], new ArrayList(new Text(65535)), 'List of Topic IDs or List of User IDs or List of Target IDs.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(998), 'Email Subject.') ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(65407), 'Email Content.') From abab68f1a14c55ae3b8643bd5de46a07186a4659 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 4 Oct 2023 17:28:38 +0530 Subject: [PATCH 108/196] fixes catching in messaging worker --- app/workers/messaging.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 8e25a8210c..1a1a4fad4b 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -106,15 +106,15 @@ class MessagingV1 extends Worker $messageData = clone $messageRecord; $messageData->setAttribute('to', $batch); $message = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($messageRecord, $providerRecord), - 'push' => $this->buildPushMessage($messageRecord), - 'email' => $this->buildEmailMessage($messageRecord, $providerRecord), + 'sms' => $this->buildSMSMessage($messageData, $providerRecord), + 'push' => $this->buildPushMessage($messageData), + 'email' => $this->buildEmailMessage($messageData, $providerRecord), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; try { $provider->send($message); $deliveredTo += \count($batch); - } catch (Exception $e) { + } catch (\Exception $e) { foreach ($batch as $identifier) { $deliveryErrors[] = 'Failed to send message to target' . $identifier . ': ' . $e->getMessage(); } From 80a19f9862536b3d4a3b4fa8c7ded7895888ef70 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 4 Oct 2023 17:30:40 +0530 Subject: [PATCH 109/196] unique to ID::unique --- .../e2e/Services/Messaging/MessagingBase.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 05092fdd2e..e9225b93d6 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -3,6 +3,7 @@ namespace Tests\E2E\Services\Messaging; use Tests\E2E\Client; +use Utopia\Database\Helpers\ID; trait MessagingBase { @@ -10,55 +11,55 @@ trait MessagingBase { $providersParams = [ 'sendgrid' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', ], 'mailgun' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Mailgun1', 'apiKey' => 'my-apikey', 'domain' => 'my-domain', 'from' => 'sender-email@my-domain', ], 'twilio' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Twilio1', 'accountSid' => 'my-accountSid', 'authToken' => 'my-authToken', ], 'telesign' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Telesign1', 'username' => 'my-username', 'password' => 'my-password', ], 'textmagic' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Textmagic1', 'username' => 'my-username', 'apiKey' => 'my-apikey', ], 'msg91' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Ms91-1', 'senderId' => 'my-senderid', 'authKey' => 'my-authkey', 'from' => '+123456789' ], 'vonage' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Vonage1', 'apiKey' => 'my-apikey', 'apiSecret' => 'my-apisecret', ], 'fcm' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'FCM1', 'serverKey' => 'my-serverkey', ], 'apns' => [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'APNS1', 'authKey' => 'my-authkey', 'authKeyId' => 'my-authkeyid', From fb98d21ae5f7fc64bbea70b570e895556c2df0ea Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 5 Oct 2023 02:12:04 +0530 Subject: [PATCH 110/196] adds graphql test cases for provider endpoints --- app/controllers/api/messaging.php | 8 +- tests/e2e/Services/GraphQL/AccountTest.php | 2 +- tests/e2e/Services/GraphQL/Base.php | 281 ++++++++++++++++-- tests/e2e/Services/GraphQL/MessagingTest.php | 260 ++++++++++++++++ .../e2e/Services/Messaging/MessagingBase.php | 6 +- 5 files changed, 520 insertions(+), 37 deletions(-) create mode 100644 tests/e2e/Services/GraphQL/MessagingTest.php diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index d9b5543e5c..396d81c06b 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -445,7 +445,7 @@ App::post('/v1/messaging/providers/fcm') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createFCMProvider') + ->label('sdk.method', 'createFcmProvider') ->label('sdk.description', '/docs/references/messaging/create-fcm-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -501,7 +501,7 @@ App::post('/v1/messaging/providers/apns') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createAPNSProvider') + ->label('sdk.method', 'createApnsProvider') ->label('sdk.description', '/docs/references/messaging/create-apns-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -1048,7 +1048,7 @@ App::patch('/v1/messaging/providers/fcm/:id') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateFCMProvider') + ->label('sdk.method', 'updateFcmProvider') ->label('sdk.description', '/docs/references/messaging/update-fcm-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -1099,7 +1099,7 @@ App::patch('/v1/messaging/providers/apns/:id') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateAPNSProvider') + ->label('sdk.method', 'updateApnsProvider') ->label('sdk.description', '/docs/references/messaging/update-apns-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index dc399cf2b3..801be808c9 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -133,7 +133,7 @@ class AccountTest extends Scope } $projectId = $this->getProject()['$id']; - $query = $this->getQuery(self::$CREATE_PROVIDER); + $query = $this->getQuery(self::$CREATE_MSG91_PROVIDER); $graphQLPayload = [ 'query' => $query, 'variables' => [ diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index c670f8e17c..3a7859662a 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -197,6 +197,29 @@ trait Base public static string $GET_QRCODE = 'get_qrcode'; public static string $GET_USER_INITIALS = 'get_user_initials'; + // Providers + public static string $CREATE_MAILGUN_PROVIDER = 'create_mailgun_provider'; + public static string $CREATE_SENDGRID_PROVIDER = 'create_sendgrid_provider'; + public static string $CREATE_TWILIO_PROVIDER = 'create_twilio_provider'; + public static string $CREATE_TELESIGN_PROVIDER = 'create_telesign_provider'; + public static string $CREATE_TEXTMAGIC_PROVIDER = 'create_textmagic_provider'; + public static string $CREATE_MSG91_PROVIDER = 'create_msg91_provider'; + public static string $CREATE_VONAGE_PROVIDER = 'create_vonage_provider'; + public static string $CREATE_FCM_PROVIDER = 'create_fcm_provider'; + public static string $CREATE_APNS_PROVIDER = 'create_apns_provider'; + public static string $LIST_PROVIDERS = 'list_providers'; + public static string $GET_PROVIDER = 'get_provider'; + public static string $UPDATE_MAILGUN_PROVIDER = 'update_mailgun_provider'; + public static string $UPDATE_SENDGRID_PROVIDER = 'update_sendgrid_provider'; + public static string $UPDATE_TWILIO_PROVIDER = 'update_twilio_provider'; + public static string $UPDATE_TELESIGN_PROVIDER = 'update_telesign_provider'; + public static string $UPDATE_TEXTMAGIC_PROVIDER = 'update_textmagic_provider'; + public static string $UPDATE_MSG91_PROVIDER = 'update_msg91_provider'; + public static string $UPDATE_VONAGE_PROVIDER = 'update_vonage_provider'; + public static string $UPDATE_FCM_PROVIDER = 'update_fcm_provider'; + public static string $UPDATE_APNS_PROVIDER = 'update_apns_provider'; + public static string $DELETE_PROVIDER = 'delete_provider'; + // Complex queries public static string $COMPLEX_QUERY = 'complex_query'; @@ -296,8 +319,6 @@ trait Base } '; - public static string $CREATE_PROVIDER = 'create_provider'; - public function getQuery(string $name): string { switch ($name) { @@ -1688,6 +1709,235 @@ trait Base status } }'; + case self::$CREATE_MAILGUN_PROVIDER: + return 'mutation createMailgunProvider($providerId: String!, $name: String!, $domain: String!, $apiKey: String!, $from: String!) { + messagingCreateMailgunProvider(providerId: $providerId, name: $name, domain: $domain, apiKey: $apiKey, from: $from) { + _id + name + provider + type + default + enabled + } + }'; + case self::$CREATE_SENDGRID_PROVIDER: + return 'mutation createSendgridProvider($providerId: String!, $name: String!, $apiKey: String!) { + messagingCreateSendgridProvider(providerId: $providerId, name: $name, apiKey: $apiKey) { + _id + name + provider + type + default + enabled + } + }'; + case self::$CREATE_TWILIO_PROVIDER: + return 'mutation createTwilioProvider($providerId: String!, $name: String!, $accountSid: String!, $authToken: String!) { + messagingCreateTwilioProvider(providerId: $providerId, name: $name, accountSid: $accountSid, authToken: $authToken) { + _id + name + provider + type + default + enabled + } + }'; + case self::$CREATE_TELESIGN_PROVIDER: + return 'mutation createTelesignProvider($providerId: String!, $name: String!, $username: String!, $password: String!) { + messagingCreateTelesignProvider(providerId: $providerId, name: $name, username: $username, password: $password) { + _id + name + provider + type + default + enabled + } + }'; + case self::$CREATE_TEXTMAGIC_PROVIDER: + return 'mutation createTextmagicProvider($providerId: String!, $name: String!, $username: String!, $apiKey: String!) { + messagingCreateTextmagicProvider(providerId: $providerId, name: $name, username: $username, apiKey: $apiKey) { + _id + name + provider + type + default + enabled + } + }'; + case self::$CREATE_MSG91_PROVIDER: + return 'mutation createMsg91Provider($providerId: String!, $name: String!, $from: String!, $senderId: String!, $authKey: String!, $default: Boolean, $enabled: Boolean) { + messagingCreateMsg91Provider(providerId: $providerId, name: $name, from: $from, senderId: $senderId, authKey: $authKey, default: $default, enabled: $enabled) { + _id + name + provider + type + default + enabled + } + }'; + case self::$CREATE_VONAGE_PROVIDER: + return 'mutation createVonageProvider($providerId: String!, $name: String!, $apiKey: String!, $apiSecret: String!) { + messagingCreateVonageProvider(providerId: $providerId, name: $name, apiKey: $apiKey, apiSecret: $apiSecret) { + _id + name + provider + type + default + enabled + } + }'; + case self::$CREATE_FCM_PROVIDER: + return 'mutation createFcmProvider($providerId: String!, $name: String!, $serverKey: String!) { + messagingCreateFcmProvider(providerId: $providerId, name: $name, serverKey: $serverKey) { + _id + name + provider + type + default + enabled + } + }'; + case self::$CREATE_APNS_PROVIDER: + return 'mutation createApnsProvider($providerId: String!, $name: String!, $authKey: String!, $authKeyId: String!, $teamId: String!, $bundleId: String!, $endpoint: String!) { + messagingCreateApnsProvider(providerId: $providerId, name: $name, authKey: $authKey, authKeyId: $authKeyId, teamId: $teamId, bundleId: $bundleId, endpoint: $endpoint) { + _id + name + provider + type + default + enabled + } + }'; + case self::$LIST_PROVIDERS: + return 'query listProviders { + messagingListProviders { + total + providers { + _id + name + provider + type + default + enabled + } + } + }'; + case self::$GET_PROVIDER: + return 'query getProvider($id: String!) { + messagingGetProvider(id: $id) { + _id + name + provider + type + default + enabled + } + }'; + case self::$UPDATE_MAILGUN_PROVIDER: + return 'mutation updateMailgunProvider($id: String!, $name: String!, $domain: String!, $apiKey: String!, $isEuRegion: Boolean, $enabled: Boolean) { + messagingUpdateMailgunProvider(id: $id, name: $name, domain: $domain, apiKey: $apiKey, isEuRegion: $isEuRegion, enabled: $enabled) { + _id + name + provider + type + default + enabled + } + }'; + case self::$UPDATE_SENDGRID_PROVIDER: + return 'mutation messagingUpdateSendgridProvider($id: String!, $name: String!, $apiKey: String!) { + messagingUpdateSendgridProvider(id: $id, name: $name, apiKey: $apiKey) { + _id + name + provider + type + default + enabled + } + }'; + case self::$UPDATE_TWILIO_PROVIDER: + return 'mutation updateTwilioProvider($id: String!, $name: String!, $accountSid: String!, $authToken: String!) { + messagingUpdateTwilioProvider(id: $id, name: $name, accountSid: $accountSid, authToken: $authToken) { + _id + name + provider + type + default + enabled + } + }'; + case self::$UPDATE_TELESIGN_PROVIDER: + return 'mutation updateTelesignProvider($id: String!, $name: String!, $username: String!, $password: String!) { + messagingUpdateTelesignProvider(id: $id, name: $name, username: $username, password: $password) { + _id + name + provider + type + default + enabled + } + }'; + case self::$UPDATE_TEXTMAGIC_PROVIDER: + return 'mutation updateTextmagicProvider($id: String!, $name: String!, $username: String!, $apiKey: String!) { + messagingUpdateTextmagicProvider(id: $id, name: $name, username: $username, apiKey: $apiKey) { + _id + name + provider + type + default + enabled + } + }'; + case self::$UPDATE_MSG91_PROVIDER: + return 'mutation updateMsg91Provider($id: String!, $name: String!, $senderId: String!, $authKey: String!) { + messagingUpdateMsg91Provider(id: $id, name: $name, senderId: $senderId, authKey: $authKey) { + _id + name + provider + type + default + enabled + } + }'; + case self::$UPDATE_VONAGE_PROVIDER: + return 'mutation updateVonageProvider($id: String!, $name: String!, $apiKey: String!, $apiSecret: String!) { + messagingUpdateVonageProvider(id: $id, name: $name, apiKey: $apiKey, apiSecret: $apiSecret) { + _id + name + provider + type + default + enabled + } + }'; + case self::$UPDATE_FCM_PROVIDER: + return 'mutation updateFcmProvider($id: String!, $name: String!, $serverKey: String!) { + messagingUpdateFcmProvider(id: $id, name: $name, serverKey: $serverKey) { + _id + name + provider + type + default + enabled + } + }'; + case self::$UPDATE_APNS_PROVIDER: + return 'mutation updateApnsProvider($id: String!, $name: String!, $authKey: String!, $authKeyId: String!, $teamId: String!, $bundleId: String!, $endpoint: String!) { + messagingUpdateApnsProvider(id: $id, name: $name, authKey: $authKey, authKeyId: $authKeyId, teamId: $teamId, bundleId: $bundleId, endpoint: $endpoint) { + _id + name + provider + type + default + enabled + } + }'; + case self::$DELETE_PROVIDER: + return 'mutation deleteProvider($id: String!) { + messagingDeleteProvider(id: $id) { + status + } + }'; case self::$COMPLEX_QUERY: return 'mutation complex($databaseId: String!, $databaseName: String!, $collectionId: String!, $collectionName: String!, $documentSecurity: Boolean!, $collectionPermissions: [String!]!) { databasesCreate(databaseId: $databaseId, name: $databaseName) { @@ -1931,33 +2181,6 @@ trait Base } } }' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES; - case self::$CREATE_PROVIDER: - return 'mutation createProviderMsg91( - $providerId: String!, - $name: String!, - $from: String!, - $senderId: String!, - $authKey: String! - $default: Boolean, - $enabled: Boolean, - ) { - messagingCreateProviderMsg91( - providerId: $providerId, - name: $name, - from: $from, - senderId: $senderId, - authKey: $authKey - default: $default, - enabled: $enabled, - ) { - _id - name - provider - type - default - enabled - } - }'; } throw new \InvalidArgumentException('Invalid query type'); diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php new file mode 100644 index 0000000000..1bc5e70477 --- /dev/null +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -0,0 +1,260 @@ + [ + 'providerId' => ID::unique(), + 'name' => 'Sengrid1', + 'apiKey' => 'my-apikey', + ], + 'Mailgun' => [ + 'providerId' => ID::unique(), + 'name' => 'Mailgun1', + 'apiKey' => 'my-apikey', + 'domain' => 'my-domain', + 'from' => 'sender-email@my-domain', + ], + 'Twilio' => [ + 'providerId' => ID::unique(), + 'name' => 'Twilio1', + 'accountSid' => 'my-accountSid', + 'authToken' => 'my-authToken', + ], + 'Telesign' => [ + 'providerId' => ID::unique(), + 'name' => 'Telesign1', + 'username' => 'my-username', + 'password' => 'my-password', + ], + 'Textmagic' => [ + 'providerId' => ID::unique(), + 'name' => 'Textmagic1', + 'username' => 'my-username', + 'apiKey' => 'my-apikey', + ], + 'Msg91' => [ + 'providerId' => ID::unique(), + 'name' => 'Ms91-1', + 'senderId' => 'my-senderid', + 'authKey' => 'my-authkey', + 'from' => '+123456789' + ], + 'Vonage' => [ + 'providerId' => ID::unique(), + 'name' => 'Vonage1', + 'apiKey' => 'my-apikey', + 'apiSecret' => 'my-apisecret', + ], + 'Fcm' => [ + 'providerId' => ID::unique(), + 'name' => 'FCM1', + 'serverKey' => 'my-serverkey', + ], + 'Apns' => [ + 'providerId' => ID::unique(), + 'name' => 'APNS1', + 'authKey' => 'my-authkey', + 'authKeyId' => 'my-authkeyid', + 'teamId' => 'my-teamid', + 'bundleId' => 'my-bundleid', + 'endpoint' => 'my-endpoint', + ], + ]; + + $providers = []; + + foreach (\array_keys($providersParams) as $key) { + $query = $this->getQuery('create_' . \strtolower($key) . '_provider'); + $graphQLPayload = [ + 'query' => $query, + 'variables' => $providersParams[$key], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + \array_push($providers, $response['body']['data']['messagingCreate' . $key . 'Provider']); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($providersParams[$key]['name'], $response['body']['data']['messagingCreate' . $key . 'Provider']['name']); + } + + return $providers; + } + + /** + * @depends testCreateProviders + */ + public function testUpdateProviders(array $providers): array + { + $providersParams = [ + 'Sendgrid' => [ + 'id' => $providers[0]['_id'], + 'name' => 'Sengrid2', + 'apiKey' => 'my-apikey', + ], + 'Mailgun' => [ + 'id' => $providers[1]['_id'], + 'name' => 'Mailgun2', + 'apiKey' => 'my-apikey', + 'domain' => 'my-domain', + ], + 'Twilio' => [ + 'id' => $providers[2]['_id'], + 'name' => 'Twilio2', + 'accountSid' => 'my-accountSid', + 'authToken' => 'my-authToken', + ], + 'Telesign' => [ + 'id' => $providers[3]['_id'], + 'name' => 'Telesign2', + 'username' => 'my-username', + 'password' => 'my-password', + ], + 'Textmagic' => [ + 'id' => $providers[4]['_id'], + 'name' => 'Textmagic2', + 'username' => 'my-username', + 'apiKey' => 'my-apikey', + ], + 'Msg91' => [ + 'id' => $providers[5]['_id'], + 'name' => 'Ms91-2', + 'senderId' => 'my-senderid', + 'authKey' => 'my-authkey', + ], + 'Vonage' => [ + 'id' => $providers[6]['_id'], + 'name' => 'Vonage2', + 'apiKey' => 'my-apikey', + 'apiSecret' => 'my-apisecret', + ], + 'Fcm' => [ + 'id' => $providers[7]['_id'], + 'name' => 'FCM2', + 'serverKey' => 'my-serverkey', + ], + 'Apns' => [ + 'id' => $providers[8]['_id'], + 'name' => 'APNS2', + 'authKey' => 'my-authkey', + 'authKeyId' => 'my-authkeyid', + 'teamId' => 'my-teamid', + 'bundleId' => 'my-bundleid', + 'endpoint' => 'my-endpoint', + ], + ]; + foreach (\array_keys($providersParams) as $index => $key) { + $query = $this->getQuery('update_' . \strtolower($key) . '_provider'); + $graphQLPayload = [ + 'query' => $query, + 'variables' => $providersParams[$key], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], $graphQLPayload); + $providers[$index] = $response['body']['data']['messagingUpdate' . $key . 'Provider']; + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($providersParams[$key]['name'], $response['body']['data']['messagingUpdate' . $key . 'Provider']['name']); + } + + $response = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'query' => $this->getQuery('update_mailgun_provider'), + 'variables' => [ + 'id' => $providers[1]['_id'], + 'name' => 'Mailgun2', + 'apiKey' => 'my-apikey', + 'domain' => 'my-domain', + 'isEuRegion' => true, + 'enabled' => false, + ] + ]); + $providers[1] = $response['body']['data']['messagingUpdateMailgunProvider']; + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('Mailgun2', $response['body']['data']['messagingUpdateMailgunProvider']['name']); + $this->assertEquals(false, $response['body']['data']['messagingUpdateMailgunProvider']['enabled']); + return $providers; + } + + /** + * @depends testUpdateProviders + */ + public function testListProviders(array $providers) + { + $query = $this->getQuery(self::$LIST_PROVIDERS); + $graphQLPayload = [ + 'query' => $query, + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], $graphQLPayload); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(\count($providers), \count($response['body']['data']['messagingListProviders']['providers'])); + } + + /** + * @depends testUpdateProviders + */ + public function testGetProvider(array $providers) + { + $query = $this->getQuery(self::$GET_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'id' => $providers[0]['_id'], + ] + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], $graphQLPayload); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($providers[0]['name'], $response['body']['data']['messagingGetProvider']['name']); + } + + /** + * @depends testUpdateProviders + */ + public function testDeleteProvider(array $providers) + { + foreach ($providers as $provider) { + $query = $this->getQuery(self::$DELETE_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'id' => $provider['_id'], + ] + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], $graphQLPayload); + $this->assertEquals(204, $response['headers']['status-code']); + } + } +} diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index e9225b93d6..3282330d86 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -76,9 +76,9 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), $providersParams[$key]); - \array_push($providers, $response['body']); $this->assertEquals(201, $response['headers']['status-code']); $this->assertEquals($providersParams[$key]['name'], $response['body']['name']); + \array_push($providers, $response['body']); } return $providers; @@ -143,9 +143,9 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], $providersParams[$key]); - $providers[$index] = $response['body']; $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($providersParams[$key]['name'], $response['body']['name']); + $providers[$index] = $response['body']; } $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/mailgun/' . $providers[1]['$id'], [ @@ -159,10 +159,10 @@ trait MessagingBase 'isEuRegion' => true, 'enabled' => false, ]); - $providers[1] = $response['body']; $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('Mailgun2', $response['body']['name']); $this->assertEquals(false, $response['body']['enabled']); + $providers[1] = $response['body']; return $providers; } From 22d445587ebd77cafbf5912642b58bedbfb0ad7e Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 5 Oct 2023 16:57:48 +0530 Subject: [PATCH 111/196] review changes --- app/controllers/api/account.php | 17 +++++--- app/controllers/api/messaging.php | 71 ++++++++++++++++--------------- app/controllers/api/users.php | 7 +-- app/workers/messaging.php | 4 +- src/Appwrite/Event/Messaging.php | 1 - 5 files changed, 52 insertions(+), 48 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 228a0621cd..23d8aea1cc 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1355,9 +1355,9 @@ App::post('/v1/account/sessions/phone') ])); $messaging - ->setMessageId($messageDoc->getId()) - ->setProject($project) - ->trigger(); + ->setMessageId($messageDoc->getId()) + ->setProject($project) + ->trigger(); $events->setPayload( $response->output( @@ -2964,7 +2964,10 @@ App::post('/v1/account/verification/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); - $target = $dbForProject->findOne('targets', [Query::equal('identifier', [$user->getAttribute('phone')]), Query::equal('providerInternalId', [$provider->getInternalId()])]); + $target = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$user->getAttribute('phone')]), + Query::equal('providerInternalId', [$provider->getInternalId()]) + ]); if (!$target) { $target = $dbForProject->createDocument('targets', new Document([ @@ -2987,9 +2990,9 @@ App::post('/v1/account/verification/phone') ])); $messaging - ->setMessageId($messageDoc->getId()) - ->setProject($project) - ->trigger(); + ->setMessageId($messageDoc->getId()) + ->setProject($project) + ->trigger(); $events ->setParam('userId', $user->getId()) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 396d81c06b..cc1df6ab62 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -69,8 +69,8 @@ App::post('/v1/messaging/providers/mailgun') // Check if a default provider exists, if not, set this one as default if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - Query::equal('type', ['email']) + Query::equal('default', [true]), + Query::equal('type', ['email']) ])) ) { $provider->setAttribute('default', true); @@ -79,7 +79,7 @@ App::post('/v1/messaging/providers/mailgun') try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } $response @@ -126,8 +126,8 @@ App::post('/v1/messaging/providers/sendgrid') // Check if a default provider exists, if not, set this one as default if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - Query::equal('type', ['sms']) + Query::equal('default', [true]), + Query::equal('type', ['sms']) ])) ) { $provider->setAttribute('default', true); @@ -136,7 +136,7 @@ App::post('/v1/messaging/providers/sendgrid') try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } $response @@ -198,13 +198,14 @@ App::post('/v1/messaging/providers/msg91') try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); }); + App::post('/v1/messaging/providers/telesign') ->desc('Create Telesign Provider') ->groups(['api', 'messaging']) @@ -245,8 +246,8 @@ App::post('/v1/messaging/providers/telesign') // Check if a default provider exists, if not, set this one as default if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - Query::equal('type', ['sms']) + Query::equal('default', [true]), + Query::equal('type', ['sms']) ])) ) { $provider->setAttribute('default', true); @@ -255,7 +256,7 @@ App::post('/v1/messaging/providers/telesign') try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } $response @@ -303,8 +304,8 @@ App::post('/v1/messaging/providers/textmagic') // Check if a default provider exists, if not, set this one as default if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - Query::equal('type', ['sms']) + Query::equal('default', [true]), + Query::equal('type', ['sms']) ])) ) { $provider->setAttribute('default', true); @@ -313,7 +314,7 @@ App::post('/v1/messaging/providers/textmagic') try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } $response @@ -361,8 +362,8 @@ App::post('/v1/messaging/providers/twilio') // Check if a default provider exists, if not, set this one as default if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - Query::equal('type', ['sms']) + Query::equal('default', [true]), + Query::equal('type', ['sms']) ])) ) { $provider->setAttribute('default', true); @@ -371,7 +372,7 @@ App::post('/v1/messaging/providers/twilio') try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } $response @@ -419,7 +420,7 @@ App::post('/v1/messaging/providers/vonage') // Check if a default provider exists, if not, set this one as default if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('default', [true]), Query::equal('type', ['sms']) ])) ) { @@ -429,7 +430,7 @@ App::post('/v1/messaging/providers/vonage') try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } $response @@ -475,8 +476,8 @@ App::post('/v1/messaging/providers/fcm') // Check if a default provider exists, if not, set this one as default if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - Query::equal('type', ['push']) + Query::equal('default', [true]), + Query::equal('type', ['push']) ])) ) { $provider->setAttribute('default', true); @@ -485,7 +486,7 @@ App::post('/v1/messaging/providers/fcm') try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } $response @@ -539,8 +540,8 @@ App::post('/v1/messaging/providers/apns') // Check if a default provider exists, if not, set this one as default if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), - Query::equal('type', ['push']) + Query::equal('default', [true]), + Query::equal('type', ['push']) ])) ) { $provider->setAttribute('default', true); @@ -549,7 +550,7 @@ App::post('/v1/messaging/providers/apns') try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { - throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } $response @@ -584,7 +585,7 @@ App::get('/v1/messaging/providers') Query::equal('$id', [$providerId]), ])); - if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { + if ($cursorDocument === false || $cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); } @@ -653,7 +654,7 @@ App::patch('/v1/messaging/providers/mailgun/:id') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'mailgun') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { @@ -721,7 +722,7 @@ App::patch('/v1/messaging/providers/sendgrid/:id') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'sendgrid') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { @@ -774,7 +775,7 @@ App::patch('/v1/messaging/providers/msg91/:id') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'msg91') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { @@ -833,7 +834,7 @@ App::patch('/v1/messaging/providers/telesign/:id') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'telesign') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { @@ -892,7 +893,7 @@ App::patch('/v1/messaging/providers/textmagic/:id') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'text-magic') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { @@ -951,7 +952,7 @@ App::patch('/v1/messaging/providers/twilio/:id') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'twilio') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { @@ -1010,7 +1011,7 @@ App::patch('/v1/messaging/providers/vonage/:id') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'vonage') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { @@ -1068,7 +1069,7 @@ App::patch('/v1/messaging/providers/fcm/:id') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'fcm') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { @@ -1123,7 +1124,7 @@ App::patch('/v1/messaging/providers/apns/:id') $providerAttr = $provider->getAttribute('provider'); if ($providerAttr !== 'apns') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr); + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { @@ -1211,7 +1212,7 @@ App::post('/v1/messaging/messages/email') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(998), 'Email Subject.') ->param('description', '', new Text(256), 'Description for Message.', true) - ->param('content', '', new Text(65407), 'Email Content.') + ->param('content', '', new Text(64230), 'Email Content.') ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->inject('dbForProject') ->inject('project') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 244bc1150b..ea3c865b96 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -428,9 +428,10 @@ App::post('/v1/users/:userId/targets') 'identifier' => $identifier, ])); $dbForProject->deleteCachedDocument('users', $user->getId()); + $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($target, Response::MODEL_TARGET); + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($target, Response::MODEL_TARGET); }); App::get('/v1/users') @@ -1238,7 +1239,7 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->setParam('targetId', $targetId); $response - ->dynamic($target, Response::MODEL_TARGET); + ->dynamic($target, Response::MODEL_TARGET); }); App::delete('/v1/users/:userId/sessions/:sessionId') diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 1a1a4fad4b..d867f98101 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -120,8 +120,8 @@ class MessagingV1 extends Worker } } finally { return [ - 'deliveredTo' => $deliveredTo, - 'deliveryErrors' => $deliveryErrors, + 'deliveredTo' => $deliveredTo, + 'deliveryErrors' => $deliveryErrors, ]; } }; diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index cbfb7981ac..999c9ee0dd 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -14,7 +14,6 @@ class Messaging extends Event parent::__construct(Event::MESSAGING_QUEUE_NAME, Event::MESSAGING_CLASS_NAME); } - /** * Sets message ID for the messaging event. * From 8e9f270ef099d2759140242257eded8f80693916 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 6 Oct 2023 03:30:47 +0530 Subject: [PATCH 112/196] update id param --- app/controllers/api/messaging.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index cc1df6ab62..72ece29eaa 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -599,7 +599,7 @@ App::get('/v1/messaging/providers') ]), Response::MODEL_PROVIDER_LIST); }); -App::get('/v1/messaging/providers/:id') +App::get('/v1/messaging/providers/:providerId') ->desc('Get Provider') ->groups(['api', 'messaging']) ->label('scope', 'providers.read') @@ -610,11 +610,11 @@ App::get('/v1/messaging/providers/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -1166,7 +1166,7 @@ App::patch('/v1/messaging/providers/apns/:id') ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::delete('/v1/messaging/providers/:id') +App::delete('/v1/messaging/providers/:providerId') ->desc('Delete Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.delete') @@ -1179,11 +1179,11 @@ App::delete('/v1/messaging/providers/:id') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -1252,7 +1252,7 @@ App::post('/v1/messaging/messages/email') ->dynamic($message, Response::MODEL_MESSAGE); }); -App::get('/v1/messaging/messages/:id') +App::get('/v1/messaging/messages/:messageId') ->desc('Get Message') ->groups(['api', 'messaging']) ->label('scope', 'messages.read') @@ -1263,11 +1263,11 @@ App::get('/v1/messaging/messages/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) - ->param('id', '', new UID(), 'Message ID.') + ->param('messageId', '', new UID(), 'Message ID.') ->inject('dbForProject') ->inject('response') - ->action(function (string $id, Database $dbForProject, Response $response) { - $message = $dbForProject->getDocument('messages', $id); + ->action(function (string $messageId, Database $dbForProject, Response $response) { + $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { throw new Exception(Exception::MESSAGE_NOT_FOUND); From a92390dda2568e00de5a355af05e663d9f59512f Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 6 Oct 2023 19:23:46 +0530 Subject: [PATCH 113/196] review changes --- app/config/collections.php | 18 ++ app/config/events.php | 3 + app/controllers/api/messaging.php | 204 ++++++++++++++---- app/controllers/api/users.php | 28 ++- app/workers/messaging.php | 66 +++--- .../Utopia/Response/Model/Message.php | 9 +- tests/e2e/Services/GraphQL/Base.php | 44 ++-- tests/e2e/Services/GraphQL/MessagingTest.php | 24 +-- 8 files changed, 278 insertions(+), 118 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 1a56b160c6..bf2dd07975 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1600,6 +1600,17 @@ $commonCollections = [ 'array' => false, 'filters' => ['datetime'], ], + [ + '$id' => ID::custom('deliveredAt'), + 'type' => Database::VAR_DATETIME, + 'format' => '', + 'size' => 0, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['datetime'], + ], [ '$id' => ID::custom('deliveryErrors'), 'type' => Database::VAR_STRING, @@ -1941,6 +1952,13 @@ $commonCollections = [ 'attributes' => ['identifier'], 'lengths' => [], 'orders' => [], + ], + [ + '$id' => ID::custom('_key_identifier_providerId'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['providerId', 'identifier'], + 'lengths' => [], + 'orders' => [], ] ], ], diff --git a/app/config/events.php b/app/config/events.php index 4aaa324e9c..b07d356470 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -258,6 +258,9 @@ return [ 'create' => [ '$description' => 'This event triggers when a message is created.', ], + 'update' => [ + '$description' => 'This event triggers when a message is updated.', + ], 'topics' => [ '$model' => Response::MODEL_TOPIC, '$resource' => true, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 72ece29eaa..e4a008165b 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -589,7 +589,7 @@ App::get('/v1/messaging/providers') throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); } - $cursor->setValue($cursorDocument[0]); + $cursor->setValue($cursorDocument); } $filterQueries = Query::groupByType($queries)['filters']; @@ -623,7 +623,7 @@ App::get('/v1/messaging/providers/:providerId') $response->dynamic($provider, Response::MODEL_PROVIDER); }); -App::patch('/v1/messaging/providers/mailgun/:id') +App::patch('/v1/messaging/providers/mailgun/:providerId') ->desc('Update Mailgun Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -636,7 +636,7 @@ App::patch('/v1/messaging/providers/mailgun/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('isEuRegion', null, new Boolean(), 'Set as eu region.', true) @@ -645,8 +645,8 @@ App::patch('/v1/messaging/providers/mailgun/:id') ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -694,7 +694,7 @@ App::patch('/v1/messaging/providers/mailgun/:id') ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::patch('/v1/messaging/providers/sendgrid/:id') +App::patch('/v1/messaging/providers/sendgrid/:providerId') ->desc('Update Sendgrid Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -707,14 +707,14 @@ App::patch('/v1/messaging/providers/sendgrid/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -746,7 +746,7 @@ App::patch('/v1/messaging/providers/sendgrid/:id') ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::patch('/v1/messaging/providers/msg91/:id') +App::patch('/v1/messaging/providers/msg91/:providerId') ->desc('Update Msg91 Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -759,15 +759,15 @@ App::patch('/v1/messaging/providers/msg91/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, string $senderId, string $authKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, string $name, ?bool $enabled, string $senderId, string $authKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -805,7 +805,7 @@ App::patch('/v1/messaging/providers/msg91/:id') ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::patch('/v1/messaging/providers/telesign/:id') +App::patch('/v1/messaging/providers/telesign/:providerId') ->desc('Update Telesign Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -818,15 +818,15 @@ App::patch('/v1/messaging/providers/telesign/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Telesign username.', true) ->param('password', '', new Text(0), 'Telesign password.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -864,7 +864,7 @@ App::patch('/v1/messaging/providers/telesign/:id') ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::patch('/v1/messaging/providers/textmagic/:id') +App::patch('/v1/messaging/providers/textmagic/:providerId') ->desc('Update Textmagic Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -877,15 +877,15 @@ App::patch('/v1/messaging/providers/textmagic/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -923,7 +923,7 @@ App::patch('/v1/messaging/providers/textmagic/:id') ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::patch('/v1/messaging/providers/twilio/:id') +App::patch('/v1/messaging/providers/twilio/:providerId') ->desc('Update Twilio Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -936,15 +936,15 @@ App::patch('/v1/messaging/providers/twilio/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, string $name, ?bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -982,7 +982,7 @@ App::patch('/v1/messaging/providers/twilio/:id') ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::patch('/v1/messaging/providers/vonage/:id') +App::patch('/v1/messaging/providers/vonage/:providerId') ->desc('Update Vonage Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -995,15 +995,15 @@ App::patch('/v1/messaging/providers/vonage/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -1041,7 +1041,7 @@ App::patch('/v1/messaging/providers/vonage/:id') ->dynamic($provider, Response::MODEL_PROVIDER); }); -App::patch('/v1/messaging/providers/fcm/:id') +App::patch('/v1/messaging/providers/fcm/:providerId') ->desc('Update FCM Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -1054,14 +1054,14 @@ App::patch('/v1/messaging/providers/fcm/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, string $serverKey, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, string $name, ?bool $enabled, string $serverKey, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -1092,7 +1092,7 @@ App::patch('/v1/messaging/providers/fcm/:id') }); -App::patch('/v1/messaging/providers/apns/:id') +App::patch('/v1/messaging/providers/apns/:providerId') ->desc('Update APNS Provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.update') @@ -1105,7 +1105,7 @@ App::patch('/v1/messaging/providers/apns/:id') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) - ->param('id', '', new UID(), 'Provider ID.') + ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('authKey', '', new Text(0), 'APNS authentication key.', true) @@ -1115,8 +1115,8 @@ App::patch('/v1/messaging/providers/apns/:id') ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $id, string $name, ?bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { - $provider = $dbForProject->getDocument('providers', $id); + ->action(function (string $providerId, string $name, ?bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); @@ -1213,12 +1213,13 @@ App::post('/v1/messaging/messages/email') ->param('subject', '', new Text(998), 'Email Subject.') ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.') + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $status, bool $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); @@ -1238,20 +1239,63 @@ App::post('/v1/messaging/messages/email') 'html' => $html, 'description' => $description, ], - 'status' => 'processing', + 'status' => $status, 'search' => $messageId . ' ' . $description . ' ' . $subject, ])); - $messaging - ->setMessageId($message->getId()) - ->setProject($project) - ->trigger(); + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project) + ->trigger(); + } $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($message, Response::MODEL_MESSAGE); }); +App::get('/v1/messaging/messages') + ->desc('List Messages') + ->groups(['api', 'messaging']) + ->label('scope', 'messages.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listMessages') + ->label('sdk.description', '/docs/references/messaging/list-messages.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE_LIST) + ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->inject('dbForProject') + ->inject('response') + ->action(function (array $queries, Database $dbForProject, Response $response) { + $queries = Query::parseQueries($queries); + + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); + + if ($cursor) { + $messageId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->findOne('messages', [ + Query::equal('$id', [$messageId]), + ])); + + if ($cursorDocument === false || $cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Message '{$messageId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + + $filterQueries = Query::groupByType($queries)['filters']; + $response->dynamic(new Document([ + 'total' => $dbForProject->count('messages', $filterQueries, APP_LIMIT_COUNT), + 'messages' => $dbForProject->find('messages', $queries), + ]), Response::MODEL_MESSAGE_LIST); + }); + App::get('/v1/messaging/messages/:messageId') ->desc('Get Message') ->groups(['api', 'messaging']) @@ -1275,3 +1319,77 @@ App::get('/v1/messaging/messages/:messageId') $response->dynamic($message, Response::MODEL_MESSAGE); }); + +App::post('/v1/messaging/messages/email/:messageId') + ->desc('Update an email.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.update') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateEmail') + ->label('sdk.description', '/docs/references/messaging/update-email.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new UID(), 'Message ID.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('subject', '', new Text(998), 'Email Subject.', true) + ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('content', '', new Text(64230), 'Email Content.', true) + ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status.', true) + ->param('html', false, new Boolean(), 'Is content of type HTML', true) + ->inject('dbForProject') + ->inject('project') + ->inject('messaging') + ->inject('response') + ->action(function (string $messageId, array $to, string $subject, string $description, string $content, string $status, bool $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $message = $dbForProject->getDocument('messages', $messageId); + + if ($message->isEmpty()) { + throw new Exception(Exception::MESSAGE_NOT_FOUND); + } + + if (\count($to) > 0) { + $message->setAttribute('to', $to); + } + + $data = $message->getAttribute('data'); + + if (!empty($subject)) { + $data['subject'] = $subject; + } + + if (!empty($content)) { + $data['content'] = $content; + } + + if (!empty($description)) { + $data['description'] = $description; + } + + if (!empty($html)) { + $data['html'] = $html; + } + + $message->setAttribute('data', $data); + $message->setAttribute('search', $message->getId() . ' ' . $data['description'] . ' ' . $data['subject']); + + if (!empty($status)) { + $message->setAttribute('status', $status); + } + + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); + + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project) + ->trigger(); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($message, Response::MODEL_MESSAGE); + }); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index e4ab995e19..9551a05ed9 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -419,14 +419,18 @@ App::post('/v1/users/:userId/targets') throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } - $target = $dbForProject->createDocument('targets', new Document([ - '$id' => $targetId, - 'providerId' => $providerId, - 'providerInternalId' => $provider->getInternalId(), - 'userId' => $userId, - 'userInternalId' => $user->getInternalId(), - 'identifier' => $identifier, - ])); + try { + $target = $dbForProject->createDocument('targets', new Document([ + '$id' => $targetId, + 'providerId' => $providerId, + 'providerInternalId' => $provider->getInternalId(), + 'userId' => $userId, + 'userInternalId' => $user->getInternalId(), + 'identifier' => $identifier, + ])); + } catch (Duplicate) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } $dbForProject->deleteCachedDocument('users', $user->getId()); $response @@ -1229,6 +1233,10 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') throw new Exception(Exception::USER_TARGET_NOT_FOUND); } + if ($user->getId() !== $target->getAttribute('userId')) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + $target->setAttribute('identifier', $identifier); $target = $dbForProject->updateDocument('targets', $target->getId(), $target); @@ -1404,6 +1412,10 @@ App::delete('/v1/users/:userId/targets/:targetId') throw new Exception(Exception::USER_TARGET_NOT_FOUND); } + if ($user->getId() !== $target->getAttribute('userId')) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + $target = $dbForProject->deleteDocument('targets', $target->getId()); $dbForProject->deleteCachedDocument('users', $user->getId()); diff --git a/app/workers/messaging.php b/app/workers/messaging.php index d867f98101..14a08e8cfa 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -62,16 +62,16 @@ class MessagingV1 extends Worker $this->processMessage($message, $provider); } - private function processMessage(Document $messageRecord, Document $providerRecord): void + private function processMessage(Document $message, Document $provider): void { - $provider = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->sms($providerRecord), - 'push' => $this->push($providerRecord), - 'email' => $this->email($providerRecord), + $adapter = match ($provider->getAttribute('type')) { + 'sms' => $this->sms($provider), + 'push' => $this->push($provider), + 'email' => $this->email($provider), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; - $recipientsId = $messageRecord->getAttribute('to'); + $recipientsId = $message->getAttribute('to'); /** * @var Document[] $recipients @@ -90,29 +90,31 @@ class MessagingV1 extends Worker $targets = $this->dbForProject->find('targets', [Query::equal('$id', $recipientsId)]); $recipients = \array_merge($recipients, $targets); - $recipients = \array_filter($recipients, fn (Document $recipient) => $recipient->getAttribute('providerId') === $providerRecord->getId()); + $recipients = \array_filter($recipients, function (Document $recipient) use ($provider) { + return $recipient->getAttribute('providerId') === $provider->getId(); + }); $identifiers = \array_map(function (Document $recipient) { return $recipient->getAttribute('identifier'); }, $recipients); - $maxBatchSize = $provider->getMaxMessagesPerRequest(); + $maxBatchSize = $adapter->getMaxMessagesPerRequest(); $batches = \array_chunk($identifiers, $maxBatchSize); - $results = batch(\array_map(function ($batch) use ($messageRecord, $providerRecord, $provider) { - return function () use ($batch, $messageRecord, $providerRecord, $provider) { + $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter) { + return function () use ($batch, $message, $provider, $adapter) { $deliveredTo = 0; $deliveryErrors = []; - $messageData = clone $messageRecord; + $messageData = clone $message; $messageData->setAttribute('to', $batch); - $message = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($messageData, $providerRecord), + $data = match ($provider->getAttribute('type')) { + 'sms' => $this->buildSMSMessage($messageData, $provider), 'push' => $this->buildPushMessage($messageData), - 'email' => $this->buildEmailMessage($messageData, $providerRecord), + 'email' => $this->buildEmailMessage($messageData, $provider), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; try { - $provider->send($message); + $adapter->send($data); $deliveredTo += \count($batch); } catch (\Exception $e) { foreach ($batch as $identifier) { @@ -133,28 +135,28 @@ class MessagingV1 extends Worker $deliveredTo += $result['deliveredTo']; $deliveryErrors = \array_merge($deliveryErrors, $result['deliveryErrors']); } - $messageRecord->setAttribute('deliveryErrors', $deliveryErrors); + $message->setAttribute('deliveryErrors', $deliveryErrors); - if (\count($messageRecord->getAttribute('deliveryErrors')) > 0) { - $messageRecord->setAttribute('status', 'failed'); + if (\count($message->getAttribute('deliveryErrors')) > 0) { + $message->setAttribute('status', 'failed'); } else { - $messageRecord->setAttribute('status', 'sent'); + $message->setAttribute('status', 'sent'); } - $messageRecord->setAttribute('to', $recipientsId); - $messageRecord->setAttribute('deliveredTo', $deliveredTo); - $messageRecord->setAttribute('deliveryTime', DateTime::now()); + $message->setAttribute('to', $recipientsId); + $message->setAttribute('deliveredTo', $deliveredTo); + $message->setAttribute('deliveredAt', DateTime::now()); - $this->dbForProject->updateDocument('messages', $messageRecord->getId(), $messageRecord); + $this->dbForProject->updateDocument('messages', $message->getId(), $message); } public function shutdown(): void { } - private function sms(Document $document): ?SMSAdapter + private function sms(Document $provider): ?SMSAdapter { - $credentials = $document->getAttribute('credentials'); - return match ($document->getAttribute('provider')) { + $credentials = $provider->getAttribute('credentials'); + return match ($provider->getAttribute('provider')) { 'mock' => new Mock('username', 'password'), 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), 'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']), @@ -165,10 +167,10 @@ class MessagingV1 extends Worker }; } - private function push(Document $document): ?PushAdapter + private function push(Document $provider): ?PushAdapter { - $credentials = $document->getAttribute('credentials'); - return match ($document->getAttribute('provider')) { + $credentials = $provider->getAttribute('credentials'); + return match ($provider->getAttribute('provider')) { 'apns' => new APNS( $credentials['authKey'], $credentials['authKeyId'], @@ -181,10 +183,10 @@ class MessagingV1 extends Worker }; } - private function email(Document $document): ?EmailAdapter + private function email(Document $provider): ?EmailAdapter { - $credentials = $document->getAttribute('credentials'); - return match ($document->getAttribute('provider')) { + $credentials = $provider->getAttribute('credentials'); + return match ($provider->getAttribute('provider')) { 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain'], $credentials['isEuRegion']), 'sendgrid' => new SendGrid($credentials['apiKey']), default => null diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 2f75997048..5e4a358490 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -32,11 +32,18 @@ class Message extends Any ]) ->addRule('deliveryTime', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Time the message is delivered at.', + 'description' => 'The scheduled time for message.', 'required' => false, 'default' => DateTime::now(), 'example' => self::TYPE_DATETIME_EXAMPLE, ]) + ->addRule('deliveredAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'The time when the message was delivered.', + 'required' => false, + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) ->addRule('deliveryErrors', [ 'type' => self::TYPE_STRING, 'description' => 'Delivery errors if any.', diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 3a7859662a..0a93ac34c4 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1823,8 +1823,8 @@ trait Base } }'; case self::$GET_PROVIDER: - return 'query getProvider($id: String!) { - messagingGetProvider(id: $id) { + return 'query getProvider($providerId: String!) { + messagingGetProvider(providerId: $providerId) { _id name provider @@ -1834,8 +1834,8 @@ trait Base } }'; case self::$UPDATE_MAILGUN_PROVIDER: - return 'mutation updateMailgunProvider($id: String!, $name: String!, $domain: String!, $apiKey: String!, $isEuRegion: Boolean, $enabled: Boolean) { - messagingUpdateMailgunProvider(id: $id, name: $name, domain: $domain, apiKey: $apiKey, isEuRegion: $isEuRegion, enabled: $enabled) { + return 'mutation updateMailgunProvider($providerId: String!, $name: String!, $domain: String!, $apiKey: String!, $isEuRegion: Boolean, $enabled: Boolean) { + messagingUpdateMailgunProvider(providerId: $providerId, name: $name, domain: $domain, apiKey: $apiKey, isEuRegion: $isEuRegion, enabled: $enabled) { _id name provider @@ -1845,8 +1845,8 @@ trait Base } }'; case self::$UPDATE_SENDGRID_PROVIDER: - return 'mutation messagingUpdateSendgridProvider($id: String!, $name: String!, $apiKey: String!) { - messagingUpdateSendgridProvider(id: $id, name: $name, apiKey: $apiKey) { + return 'mutation messagingUpdateSendgridProvider($providerId: String!, $name: String!, $apiKey: String!) { + messagingUpdateSendgridProvider(providerId: $providerId, name: $name, apiKey: $apiKey) { _id name provider @@ -1856,8 +1856,8 @@ trait Base } }'; case self::$UPDATE_TWILIO_PROVIDER: - return 'mutation updateTwilioProvider($id: String!, $name: String!, $accountSid: String!, $authToken: String!) { - messagingUpdateTwilioProvider(id: $id, name: $name, accountSid: $accountSid, authToken: $authToken) { + return 'mutation updateTwilioProvider($providerId: String!, $name: String!, $accountSid: String!, $authToken: String!) { + messagingUpdateTwilioProvider(providerId: $providerId, name: $name, accountSid: $accountSid, authToken: $authToken) { _id name provider @@ -1867,8 +1867,8 @@ trait Base } }'; case self::$UPDATE_TELESIGN_PROVIDER: - return 'mutation updateTelesignProvider($id: String!, $name: String!, $username: String!, $password: String!) { - messagingUpdateTelesignProvider(id: $id, name: $name, username: $username, password: $password) { + return 'mutation updateTelesignProvider($providerId: String!, $name: String!, $username: String!, $password: String!) { + messagingUpdateTelesignProvider(providerId: $providerId, name: $name, username: $username, password: $password) { _id name provider @@ -1878,8 +1878,8 @@ trait Base } }'; case self::$UPDATE_TEXTMAGIC_PROVIDER: - return 'mutation updateTextmagicProvider($id: String!, $name: String!, $username: String!, $apiKey: String!) { - messagingUpdateTextmagicProvider(id: $id, name: $name, username: $username, apiKey: $apiKey) { + return 'mutation updateTextmagicProvider($providerId: String!, $name: String!, $username: String!, $apiKey: String!) { + messagingUpdateTextmagicProvider(providerId: $providerId, name: $name, username: $username, apiKey: $apiKey) { _id name provider @@ -1889,8 +1889,8 @@ trait Base } }'; case self::$UPDATE_MSG91_PROVIDER: - return 'mutation updateMsg91Provider($id: String!, $name: String!, $senderId: String!, $authKey: String!) { - messagingUpdateMsg91Provider(id: $id, name: $name, senderId: $senderId, authKey: $authKey) { + return 'mutation updateMsg91Provider($providerId: String!, $name: String!, $senderId: String!, $authKey: String!) { + messagingUpdateMsg91Provider(providerId: $providerId, name: $name, senderId: $senderId, authKey: $authKey) { _id name provider @@ -1900,8 +1900,8 @@ trait Base } }'; case self::$UPDATE_VONAGE_PROVIDER: - return 'mutation updateVonageProvider($id: String!, $name: String!, $apiKey: String!, $apiSecret: String!) { - messagingUpdateVonageProvider(id: $id, name: $name, apiKey: $apiKey, apiSecret: $apiSecret) { + return 'mutation updateVonageProvider($providerId: String!, $name: String!, $apiKey: String!, $apiSecret: String!) { + messagingUpdateVonageProvider(providerId: $providerId, name: $name, apiKey: $apiKey, apiSecret: $apiSecret) { _id name provider @@ -1911,8 +1911,8 @@ trait Base } }'; case self::$UPDATE_FCM_PROVIDER: - return 'mutation updateFcmProvider($id: String!, $name: String!, $serverKey: String!) { - messagingUpdateFcmProvider(id: $id, name: $name, serverKey: $serverKey) { + return 'mutation updateFcmProvider($providerId: String!, $name: String!, $serverKey: String!) { + messagingUpdateFcmProvider(providerId: $providerId, name: $name, serverKey: $serverKey) { _id name provider @@ -1922,8 +1922,8 @@ trait Base } }'; case self::$UPDATE_APNS_PROVIDER: - return 'mutation updateApnsProvider($id: String!, $name: String!, $authKey: String!, $authKeyId: String!, $teamId: String!, $bundleId: String!, $endpoint: String!) { - messagingUpdateApnsProvider(id: $id, name: $name, authKey: $authKey, authKeyId: $authKeyId, teamId: $teamId, bundleId: $bundleId, endpoint: $endpoint) { + return 'mutation updateApnsProvider($providerId: String!, $name: String!, $authKey: String!, $authKeyId: String!, $teamId: String!, $bundleId: String!, $endpoint: String!) { + messagingUpdateApnsProvider(providerId: $providerId, name: $name, authKey: $authKey, authKeyId: $authKeyId, teamId: $teamId, bundleId: $bundleId, endpoint: $endpoint) { _id name provider @@ -1933,8 +1933,8 @@ trait Base } }'; case self::$DELETE_PROVIDER: - return 'mutation deleteProvider($id: String!) { - messagingDeleteProvider(id: $id) { + return 'mutation deleteProvider($providerId: String!) { + messagingDeleteProvider(providerId: $providerId) { status } }'; diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 1bc5e70477..99bad52887 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -104,53 +104,53 @@ class MessagingTest extends Scope { $providersParams = [ 'Sendgrid' => [ - 'id' => $providers[0]['_id'], + 'providerId' => $providers[0]['_id'], 'name' => 'Sengrid2', 'apiKey' => 'my-apikey', ], 'Mailgun' => [ - 'id' => $providers[1]['_id'], + 'providerId' => $providers[1]['_id'], 'name' => 'Mailgun2', 'apiKey' => 'my-apikey', 'domain' => 'my-domain', ], 'Twilio' => [ - 'id' => $providers[2]['_id'], + 'providerId' => $providers[2]['_id'], 'name' => 'Twilio2', 'accountSid' => 'my-accountSid', 'authToken' => 'my-authToken', ], 'Telesign' => [ - 'id' => $providers[3]['_id'], + 'providerId' => $providers[3]['_id'], 'name' => 'Telesign2', 'username' => 'my-username', 'password' => 'my-password', ], 'Textmagic' => [ - 'id' => $providers[4]['_id'], + 'providerId' => $providers[4]['_id'], 'name' => 'Textmagic2', 'username' => 'my-username', 'apiKey' => 'my-apikey', ], 'Msg91' => [ - 'id' => $providers[5]['_id'], + 'providerId' => $providers[5]['_id'], 'name' => 'Ms91-2', 'senderId' => 'my-senderid', 'authKey' => 'my-authkey', ], 'Vonage' => [ - 'id' => $providers[6]['_id'], + 'providerId' => $providers[6]['_id'], 'name' => 'Vonage2', 'apiKey' => 'my-apikey', 'apiSecret' => 'my-apisecret', ], 'Fcm' => [ - 'id' => $providers[7]['_id'], + 'providerId' => $providers[7]['_id'], 'name' => 'FCM2', 'serverKey' => 'my-serverkey', ], 'Apns' => [ - 'id' => $providers[8]['_id'], + 'providerId' => $providers[8]['_id'], 'name' => 'APNS2', 'authKey' => 'my-authkey', 'authKeyId' => 'my-authkeyid', @@ -182,7 +182,7 @@ class MessagingTest extends Scope ], [ 'query' => $this->getQuery('update_mailgun_provider'), 'variables' => [ - 'id' => $providers[1]['_id'], + 'providerId' => $providers[1]['_id'], 'name' => 'Mailgun2', 'apiKey' => 'my-apikey', 'domain' => 'my-domain', @@ -224,7 +224,7 @@ class MessagingTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'id' => $providers[0]['_id'], + 'providerId' => $providers[0]['_id'], ] ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -246,7 +246,7 @@ class MessagingTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'id' => $provider['_id'], + 'providerId' => $provider['_id'], ] ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', [ From a77a212e2c80dc60db5d0ae3431cfb97d9c65e4d Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Mon, 9 Oct 2023 17:29:26 +0530 Subject: [PATCH 114/196] adds scheduling for messaging worker --- app/controllers/api/messaging.php | 5 ++++- src/Appwrite/Event/Messaging.php | 36 +++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index e4a008165b..f4718e55b2 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -21,6 +21,7 @@ use Utopia\Validator\Boolean; use Utopia\Validator\JSON; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; +use Utopia\Database\DateTime; App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun Provider') @@ -1340,11 +1341,12 @@ App::post('/v1/messaging/messages/email/:messageId') ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) + ->param('deliveryTime', DateTime::now(), new DatetimeValidator(), 'Delivery time for message.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, array $to, string $subject, string $description, string $content, string $status, bool $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, array $to, string $subject, string $description, string $content, string $status, bool $html, string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -1385,6 +1387,7 @@ App::post('/v1/messaging/messages/email/:messageId') if ($status === 'processing') { $messaging ->setMessageId($message->getId()) + ->setDeliveryTime($deliveryTime) ->setProject($project) ->trigger(); } diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index 999c9ee0dd..18887ffcd3 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -2,12 +2,13 @@ namespace Appwrite\Event; -use Resque; -use Utopia\Database\Document; +use ResqueScheduler; +use Utopia\Database\DateTime; class Messaging extends Event { protected ?string $messageId = null; + private ?string $deliveryTime = null; public function __construct() { @@ -38,17 +39,38 @@ class Messaging extends Event } /** - * Executes the event and sends it to the messaging worker. + * Sets Delivery time for the messaging event. * - * @return string|bool - * @throws \InvalidArgumentException + * @param string $deliveryTime + * @return self */ - public function trigger(): string|bool + public function setDeliveryTime(string $deliveryTime): self { - return Resque::enqueue($this->queue, $this->class, [ + $this->deliveryTime = $deliveryTime; + + return $this; + } + + /** + * Returns set Delivery Time for the messaging event. + * + * @return string + */ + public function getDeliveryTime(): string + { + return $this->deliveryTime; + } + + /** + * Executes the event and sends it to the messaging worker. + */ + public function trigger(): string | bool + { + ResqueScheduler::enqueueAt(!empty($this->deliveryTime) ? $this->deliveryTime : DateTime::now(), $this->queue, $this->class, [ 'project' => $this->project, 'user' => $this->user, 'messageId' => $this->messageId, ]); + return true; } } From cc1769ed41e2bed120111490a9b033f7baacb0ce Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 12 Oct 2023 11:48:26 +0530 Subject: [PATCH 115/196] review changes --- app/controllers/api/messaging.php | 3 +-- app/workers/messaging.php | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index f4718e55b2..533086a058 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1321,7 +1321,7 @@ App::get('/v1/messaging/messages/:messageId') $response->dynamic($message, Response::MODEL_MESSAGE); }); -App::post('/v1/messaging/messages/email/:messageId') +App::patch('/v1/messaging/messages/email/:messageId') ->desc('Update an email.') ->groups(['api', 'messaging']) ->label('audits.event', 'messages.update') @@ -1393,6 +1393,5 @@ App::post('/v1/messaging/messages/email/:messageId') } $response - ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($message, Response::MODEL_MESSAGE); }); diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 14a08e8cfa..8432e43d80 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -100,9 +100,10 @@ class MessagingV1 extends Worker $maxBatchSize = $adapter->getMaxMessagesPerRequest(); $batches = \array_chunk($identifiers, $maxBatchSize); + $batchIndex = 0; - $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter) { - return function () use ($batch, $message, $provider, $adapter) { + $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex) { + return function () use ($batch, $message, $provider, $adapter, $batchIndex) { $deliveredTo = 0; $deliveryErrors = []; $messageData = clone $message; @@ -117,10 +118,9 @@ class MessagingV1 extends Worker $adapter->send($data); $deliveredTo += \count($batch); } catch (\Exception $e) { - foreach ($batch as $identifier) { - $deliveryErrors[] = 'Failed to send message to target' . $identifier . ': ' . $e->getMessage(); - } + $deliveryErrors[] = 'Failed sending to targets ' . $batchIndex + 1 . '-' . \count($batch) . ' with error: ' . $e->getMessage(); } finally { + $batchIndex++; return [ 'deliveredTo' => $deliveredTo, 'deliveryErrors' => $deliveryErrors, From 0b1b7646d5677c7c085ba5d1784c9b6503374501 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 13 Oct 2023 18:26:54 +0530 Subject: [PATCH 116/196] review changes --- app/controllers/api/messaging.php | 63 ++++++++++++------- src/Appwrite/Event/Messaging.php | 37 ++++++++++- .../Database/Validator/Queries/Messages.php | 25 ++++++++ .../Database/Validator/Queries/Providers.php | 4 +- 4 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Messages.php diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 058f3ce1f6..40e6a159bc 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -5,6 +5,7 @@ use Appwrite\Extend\Exception; use Appwrite\Permission; use Appwrite\Role; use Appwrite\Utopia\Database\Validator\CustomId; +use Appwrite\Utopia\Database\Validator\Queries\Messages; use Appwrite\Utopia\Database\Validator\Queries\Providers; use Appwrite\Utopia\Database\Validator\Queries\Topics; use Appwrite\Utopia\Response; @@ -19,10 +20,8 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; -use Utopia\Validator\JSON; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; -use Utopia\Database\DateTime; App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun Provider') @@ -1236,12 +1235,13 @@ App::post('/v1/messaging/topics') try { $topic = $dbForProject->createDocument('topics', $topic); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($topic, Response::MODEL_TOPIC); } catch (DuplicateException) { throw new Exception(Exception::TOPIC_ALREADY_EXISTS); } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($topic, Response::MODEL_TOPIC); }); App::get('/v1/messaging/topics') @@ -1328,7 +1328,7 @@ App::patch('/v1/messaging/topics/:topicId') ->label('sdk.response.model', Response::MODEL_TOPIC) ->param('topicId', '', new UID(), 'Topic ID.') ->param('name', '', new Text(128), 'Topic Name.', true) - ->param('description', null, new Text(128), 'Topic Description.', true) + ->param('description', null, new Text(2048), 'Topic Description.', true) ->inject('dbForProject') ->inject('response') ->action(function (string $topicId, string $name, string $description, Database $dbForProject, Response $response) { @@ -1387,8 +1387,8 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->label('scope', 'subscribers.write') ->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', 'addSubscriber') - ->label('sdk.description', '/docs/references/messaging/add-subscriber.md') + ->label('sdk.method', 'createSubscriber') + ->label('sdk.description', '/docs/references/messaging/create-subscriber.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_SUBSCRIBER) @@ -1427,19 +1427,20 @@ App::post('/v1/messaging/topics/:topicId/subscribers') try { $subscriber = $dbForProject->createDocument('subscribers', $subscriber); $dbForProject->deleteCachedDocument('topics', $topicId); - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); } catch (DuplicateException) { throw new Exception(Exception::SUBSCRIBER_ALREADY_EXISTS); } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); }); App::get('/v1/messaging/topics/:topicId/subscribers') ->desc('List topic\'s subscribers.') ->groups(['api', 'messaging']) ->label('scope', 'subscribers.read') - ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'listSubscribers') ->label('sdk.description', '/docs/references/messaging/list-subscribers.md') @@ -1471,7 +1472,7 @@ App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->desc('Get a topic\'s subscriber.') ->groups(['api', 'messaging']) ->label('scope', 'subscribers.read') - ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'getSubscriber') ->label('sdk.description', '/docs/references/messaging/get-subscriber.md') @@ -1537,15 +1538,15 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') }); App::post('/v1/messaging/messages/email') - ->desc('Send an email.') + ->desc('Create an email.') ->groups(['api', 'messaging']) ->label('audits.event', 'messages.create') ->label('audits.resource', 'messages/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'sendEmail') - ->label('sdk.description', '/docs/references/messaging/send-email.md') + ->label('sdk.method', 'createEmail') + ->label('sdk.description', '/docs/references/messaging/create-email.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) @@ -1557,11 +1558,12 @@ App::post('/v1/messaging/messages/email') ->param('content', '', new Text(64230), 'Email Content.') ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) + ->param('deliveryTime', null, new DatetimeValidator(), 'Delivery time for message.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $status, bool $html, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); @@ -1588,8 +1590,15 @@ App::post('/v1/messaging/messages/email') if ($status === 'processing') { $messaging ->setMessageId($message->getId()) - ->setProject($project) - ->trigger(); + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging + ->setDeliveryTime($deliveryTime) + ->schedule(); + } else { + $messaging->trigger(); + } } $response @@ -1608,7 +1617,7 @@ App::get('/v1/messaging/messages') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE_LIST) - ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Messages(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) ->inject('dbForProject') ->inject('response') ->action(function (array $queries, Database $dbForProject, Response $response) { @@ -1682,12 +1691,12 @@ App::patch('/v1/messaging/messages/email/:messageId') ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('deliveryTime', DateTime::now(), new DatetimeValidator(), 'Delivery time for message.', true) + ->param('deliveryTime', null, new DatetimeValidator(), 'Delivery time for message in ISO 8601 format.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, array $to, string $subject, string $description, string $content, string $status, bool $html, string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, array $to, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -1728,9 +1737,15 @@ App::patch('/v1/messaging/messages/email/:messageId') if ($status === 'processing') { $messaging ->setMessageId($message->getId()) + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging ->setDeliveryTime($deliveryTime) - ->setProject($project) - ->trigger(); + ->schedule(); + } else { + $messaging->trigger(); + } } $response diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index 18887ffcd3..45ef843caa 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -2,8 +2,9 @@ namespace Appwrite\Event; +use Resque; use ResqueScheduler; -use Utopia\Database\DateTime; +use Utopia\Database\Document; class Messaging extends Event { @@ -61,16 +62,46 @@ class Messaging extends Event return $this->deliveryTime; } + /** + * Set project for this event. + * + * @param Document $project + * @return self + */ + public function setProject(Document $project): self + { + $this->project = $project; + + return $this; + } + /** * Executes the event and sends it to the messaging worker. + * @return string|bool + * @throws \InvalidArgumentException */ public function trigger(): string | bool { - ResqueScheduler::enqueueAt(!empty($this->deliveryTime) ? $this->deliveryTime : DateTime::now(), $this->queue, $this->class, [ + return Resque::enqueue($this->queue, $this->class, [ + 'project' => $this->project, + 'user' => $this->user, + 'messageId' => $this->messageId, + ]); + } + + /** + * Schedules the messaging event and schedules it in the messaging worker queue. + * + * @return void + * @throws \Resque_Exception + * @throws \ResqueScheduler_InvalidTimestampException + */ + public function schedule(): void + { + ResqueScheduler::enqueueAt(new \DateTime($this->deliveryTime, new \DateTimeZone('UTC')), $this->queue, $this->class, [ 'project' => $this->project, 'user' => $this->user, 'messageId' => $this->messageId, ]); - return true; } } diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php new file mode 100644 index 0000000000..5fa391e7f6 --- /dev/null +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php @@ -0,0 +1,25 @@ + Date: Fri, 13 Oct 2023 18:35:49 +0530 Subject: [PATCH 117/196] adds already sent exception in update message --- app/config/errors.php | 5 +++++ app/controllers/api/messaging.php | 4 ++++ src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 10 insertions(+) diff --git a/app/config/errors.php b/app/config/errors.php index 2c5dfbad01..5514e8e68e 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -785,5 +785,10 @@ return [ 'name' => Exception::MESSAGE_NOT_FOUND, 'description' => 'Message with the requested ID could not be found.', 'code' => 404, + ], + Exception::MESSAGE_ALREADY_SENT => [ + 'name' => Exception::MESSAGE_ALREADY_SENT, + 'description' => 'Message with the requested ID has already been sent.', + 'code' => 400, ] ]; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 40e6a159bc..e83fc1114d 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1703,6 +1703,10 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_NOT_FOUND); } + if ($message->getAttribute('status') === 'sent') { + throw new Exception(Exception::MESSAGE_ALREADY_SENT); + } + if (\count($to) > 0) { $message->setAttribute('to', $to); } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 861db5271c..ee17ccef0c 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -240,6 +240,7 @@ class Exception extends \Exception /** Message */ public const MESSAGE_NOT_FOUND = 'message_not_found'; + public const MESSAGE_ALREADY_SENT = 'message_already_sent'; protected $type = ''; protected $errors = []; From 4ccffb6649ece498d95a91f68127980aa1985187 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 17 Oct 2023 03:41:42 +0530 Subject: [PATCH 118/196] adds graphql tests for topics, subcribers, email --- .env | 10 +- app/controllers/api/messaging.php | 9 +- composer.lock | 6 +- docker-compose.yml | 10 +- tests/e2e/Services/GraphQL/Base.php | 191 +++++++++ tests/e2e/Services/GraphQL/MessagingTest.php | 402 ++++++++++++++++++ .../e2e/Services/Messaging/MessagingBase.php | 20 +- 7 files changed, 624 insertions(+), 24 deletions(-) diff --git a/.env b/.env index cb0ae9a424..aa90470729 100644 --- a/.env +++ b/.env @@ -103,8 +103,8 @@ _APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID= _APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY= _APP_MESSAGE_SMS_PROVIDER_MSG91_FROM= _APP_MESSAGE_SMS_PROVIDER_MSG91_TO= -_APP_MESSAGE_SMS_PROVIDER_MAILGUN_API_KEY= -_APP_MESSAGE_SMS_PROVIDER_MAILGUN_DOMAIN= -_APP_MESSAGE_SMS_PROVIDER_MAILGUN_FROM= -_APP_MESSAGE_SMS_PROVIDER_MAILGUN_RECEIVER_EMAIL= -_APP_MESSAGE_SMS_PROVIDER_MAILGUN_IS_EU_REGION= +_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY= +_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN= +_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM= +_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL= +_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION= diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index e83fc1114d..b3deaa409f 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1192,7 +1192,9 @@ App::delete('/v1/messaging/providers/:providerId') $dbForProject->deleteDocument('providers', $provider->getId()); - $response->noContent(); + $response + ->setStatusCode(Response::STATUS_CODE_NOCONTENT) + ->noContent(); }); App::post('/v1/messaging/topics') @@ -1376,7 +1378,10 @@ App::delete('/v1/messaging/topics/:topicId') } $topic = $dbForProject->deleteDocument('topics', $topicId); - $response->noContent(); + + $response + ->setStatusCode(Response::STATUS_CODE_NOCONTENT) + ->noContent(); }); App::post('/v1/messaging/topics/:topicId/subscribers') diff --git a/composer.lock b/composer.lock index 8abede5fa4..f80104986c 100644 --- a/composer.lock +++ b/composer.lock @@ -156,11 +156,11 @@ }, { "name": "appwrite/php-runtimes", - "version": "0.13.0", + "version": "0.13.1", "source": { "type": "git", "url": "https://github.com/appwrite/runtimes.git", - "reference": "5ab496b3908992b39275994a23783701c4b3de84" + "reference": "b584d19cdcd82737d0ee5c34d23de791f5ed3610" }, "require": { "php": ">=8.0", @@ -195,7 +195,7 @@ "php", "runtimes" ], - "time": "2023-09-12T19:38:43+00:00" + "time": "2023-10-16T15:39:53+00:00" }, { "name": "chillerlan/php-qrcode", diff --git a/docker-compose.yml b/docker-compose.yml index f0ddbfe41b..a365ce17ba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -192,11 +192,11 @@ services: - _APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY - _APP_MESSAGE_SMS_PROVIDER_MSG91_FROM - _APP_MESSAGE_SMS_PROVIDER_MSG91_TO - - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_API_KEY - - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_DOMAIN - - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_FROM - - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_RECEIVER_EMAIL - - _APP_MESSAGE_SMS_PROVIDER_MAILGUN_IS_EU_REGION + - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY + - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN + - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM + - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL + - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION appwrite-realtime: entrypoint: realtime diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 0a93ac34c4..f3947c53b4 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -107,6 +107,11 @@ trait Base public static string $DELETE_USER_SESSIONS = 'delete_user_sessions'; public static string $DELETE_USER_SESSION = 'delete_user_session'; public static string $DELETE_USER = 'delete_user'; + public static string $CREATE_USER_TARGET = 'create_user_target'; + public static string $LIST_USER_TARGETS = 'list_user_targets'; + public static string $GET_USER_TARGET = 'get_user_target'; + public static string $UPDATE_USER_TARGET = 'update_user_target'; + public static string $DELETE_USER_TARGET = 'delete_user_target'; // Teams public static string $GET_TEAM = 'get_team'; @@ -220,6 +225,24 @@ trait Base public static string $UPDATE_APNS_PROVIDER = 'update_apns_provider'; public static string $DELETE_PROVIDER = 'delete_provider'; + // Topics + public static string $CREATE_TOPIC = 'create_topic'; + public static string $LIST_TOPICS = 'list_topics'; + public static string $GET_TOPIC = 'get_topic'; + public static string $UPDATE_TOPIC = 'update_topic'; + public static string $DELETE_TOPIC = 'delete_topic'; + + // Subscriptions + public static string $CREATE_SUBSCRIBER = 'create_subscriber'; + public static string $LIST_SUBSCRIBERS = 'list_subscribers'; + public static string $GET_SUBSCRIBER = 'get_subscriber'; + public static string $DELETE_SUBSCRIBER = 'delete_subscriber'; + + // Messages + public static string $CREATE_EMAIL = 'create_email'; + public static string $LIST_MESSAGES = 'list_messages'; + public static string $GET_MESSAGE = 'get_message'; + // Complex queries public static string $COMPLEX_QUERY = 'complex_query'; @@ -902,6 +925,51 @@ trait Base status } }'; + case self::$CREATE_USER_TARGET: + return 'mutation createUserTarget($userId: String!, $targetId: String!, $providerId: String!, $identifier: String!){ + usersCreateTarget(userId: $userId, targetId: $targetId, providerId: $providerId, identifier: $identifier) { + _id + userId + providerId + identifier + } + }'; + case self::$LIST_USER_TARGETS: + return 'query listUserTargets($userId: String!) { + usersListTargets(userId: $userId) { + total + targets { + _id + userId + providerId + identifier + } + } + }'; + case self::$GET_USER_TARGET: + return 'query getUserTarget($userId: String!, $targetId: String!) { + usersGetTarget(userId: $userId, targetId: $targetId) { + _id + userId + providerId + identifier + } + }'; + case self::$UPDATE_USER_TARGET: + return 'mutation updateUserTarget($userId: String!, $targetId: String!, $identifier: String!){ + usersUpdateTargetIdentifier(userId: $userId, targetId: $targetId, identifier: $identifier) { + _id + userId + providerId + identifier + } + }'; + case self::$DELETE_USER_TARGET: + return 'mutation deleteUserTarget($userId: String!, $targetId: String!){ + usersDeleteTarget(userId: $userId, targetId: $targetId) { + status + } + }'; case self::$GET_LOCALE: return 'query getLocale { localeGet { @@ -1938,6 +2006,129 @@ trait Base status } }'; + case self::$CREATE_TOPIC: + return 'mutation createTopic($providerId: String!, $topicId: String!, $name: String!, $description: String!) { + messagingCreateTopic(providerId: $providerId, topicId: $topicId, name: $name, description: $description) { + _id + name + providerId + description + } + }'; + case self::$LIST_TOPICS: + return 'query listTopics { + messagingListTopics { + total + topics { + _id + name + providerId + description + } + } + }'; + case self::$GET_TOPIC: + return 'query getTopic($topicId: String!) { + messagingGetTopic(topicId: $topicId) { + _id + name + providerId + description + } + }'; + case self::$UPDATE_TOPIC: + return 'mutation updateTopic($topicId: String!, $name: String!, $description: String!) { + messagingUpdateTopic(topicId: $topicId, name: $name, description: $description) { + _id + name + providerId + description + } + }'; + case self::$DELETE_TOPIC: + return 'mutation deleteTopic($topicId: String!) { + messagingDeleteTopic(topicId: $topicId) { + status + } + }'; + case self::$CREATE_SUBSCRIBER: + return 'mutation createSubscriber($subscriberId: String!, $targetId: String!, $topicId: String!) { + messagingCreateSubscriber(subscriberId: $subscriberId, targetId: $targetId, topicId: $topicId) { + _id + targetId + topicId + } + }'; + case self::$LIST_SUBSCRIBERS: + return 'query listSubscribers($topicId: String!) { + messagingListSubscribers(topicId: $topicId) { + total + subscribers { + _id + targetId + topicId + } + } + }'; + case self::$GET_SUBSCRIBER: + return 'query getSubscriber($topicId: String!, $subscriberId: String!) { + messagingGetSubscriber(topicId: $topicId, subscriberId: $subscriberId) { + _id + targetId + topicId + } + }'; + case self::$DELETE_SUBSCRIBER: + return 'mutation deleteSubscriber($topicId: String!, $subscriberId: String!) { + messagingDeleteSubscriber(topicId: $topicId, subscriberId: $subscriberId) { + status + } + }'; + case self::$CREATE_EMAIL: + return 'mutation createEmail($messageId: String!, $providerId: String!, $to: [String!]!, $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { + messagingCreateEmail(messageId: $messageId, providerId: $providerId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; + case self::$LIST_MESSAGES: + return 'query listMessages { + messagingListMessages { + total + messages { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + } + }'; + case self::$GET_MESSAGE: + return 'query getMessage($messageId: String!) { + messagingGetMessage(messageId: $messageId) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; case self::$COMPLEX_QUERY: return 'mutation complex($databaseId: String!, $databaseName: String!, $collectionId: String!, $collectionName: String!, $documentSecurity: Boolean!, $collectionPermissions: [String!]!) { databasesCreate(databaseId: $databaseId, name: $databaseName) { diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 99bad52887..178b9a6a6c 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -6,6 +6,7 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; +use Utopia\App; use Utopia\Database\Helpers\ID; class MessagingTest extends Scope @@ -257,4 +258,405 @@ class MessagingTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } } + + public function testCreateTopic() + { + $providerParam = [ + 'sendgrid' => [ + 'providerId' => ID::unique(), + 'name' => 'Sengrid1', + 'apiKey' => 'my-apikey', + ] + ]; + $query = $this->getQuery(self::$CREATE_SENDGRID_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => $providerParam['sendgrid'], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $providerId = $response['body']['data']['messagingCreateSendgridProvider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('topic1', $response['body']['data']['messagingCreateTopic']['name']); + $this->assertEquals('Active users', $response['body']['data']['messagingCreateTopic']['description']); + + return $response['body']['data']['messagingCreateTopic']; + } + + /** + * @depends testCreateTopic + */ + public function testUpdateTopic(array $topic) + { + $topicId = $topic['_id']; + $query = $this->getQuery(self::$UPDATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + 'name' => 'topic2', + 'description' => 'Inactive users', + ], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('topic2', $response['body']['data']['messagingUpdateTopic']['name']); + $this->assertEquals('Inactive users', $response['body']['data']['messagingUpdateTopic']['description']); + + return $topicId; + } + + /** + * @depends testCreateTopic + */ + public function testListTopics() + { + $query = $this->getQuery(self::$LIST_TOPICS); + $graphQLPayload = [ + 'query' => $query, + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(1, \count($response['body']['data']['messagingListTopics']['topics'])); + } + + /** + * @depends testUpdateTopic + */ + public function testGetTopic(string $topicId) + { + $query = $this->getQuery(self::$GET_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + ], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('topic2', $response['body']['data']['messagingGetTopic']['name']); + $this->assertEquals('Inactive users', $response['body']['data']['messagingGetTopic']['description']); + } + + /** + * @depends testCreateTopic + */ + public function testCreateSubscriber(array $topic) + { + $topicId = $topic['_id']; + + $userId = $this->getUser()['$id']; + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $userId, + 'providerId' => $topic['providerId'], + 'identifier' => 'token', + ], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($userId, $response['body']['data']['usersCreateTarget']['userId']); + $this->assertEquals('token', $response['body']['data']['usersCreateTarget']['identifier']); + + $targetId = $response['body']['data']['usersCreateTarget']['_id']; + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topicId, + 'targetId' => $targetId, + ], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $response['headers']['status-code']); + + return $response['body']['data']['messagingCreateSubscriber']; + } + + /** + * @depends testUpdateTopic + */ + public function testListSubscribers(string $topicId) + { + $query = $this->getQuery(self::$LIST_SUBSCRIBERS); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + ], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(1, \count($response['body']['data']['messagingListSubscribers']['subscribers'])); + } + + /** + * @depends testCreateSubscriber + */ + public function testGetSubscriber(array $subscriber) + { + $topicId = $subscriber['topicId']; + $subscriberId = $subscriber['_id']; + + $query = $this->getQuery(self::$GET_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + 'subscriberId' => $subscriberId, + ], + ]; + + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($subscriberId, $response['body']['data']['messagingGetSubscriber']['_id']); + } + + /** + * @depends testCreateSubscriber + */ + public function testDeleteSubscriber(array $subscriber) + { + $topicId = $subscriber['topicId']; + $subscriberId = $subscriber['_id']; + + $query = $this->getQuery(self::$DELETE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + 'subscriberId' => $subscriberId, + ], + ]; + + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $response['headers']['status-code']); + } + + /** + * @depends testUpdateTopic + */ + public function testDeleteTopic(string $topicId) + { + $query = $this->getQuery(self::$DELETE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + ], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(204, $response['headers']['status-code']); + } + + public function testSendEmail() + { + $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); + $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); + $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); + $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); + $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); + if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { + $this->markTestSkipped('Email provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_MAILGUN_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'Mailgun1', + 'apiKey' => $apiKey, + 'domain' => $domain, + 'from' => $from, + 'isEuRegion' => $isEuRegion, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + + $providerId = $provider['body']['data']['messagingCreateMailgunProvider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::custom('test-user'), + 'email' => $to, + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_EMAIL); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ], + ]; + $email = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $email['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $email['body']['data']['messagingCreateEmail']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + } } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 3f8039fae6..1c349a2dbe 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -323,7 +323,8 @@ trait MessagingBase $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'] . '/subscriber/' . $data['subscriberId'], \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); + 'x-appwrite-key' => $this->getProject()['apiKey'], + ])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($data['topicId'], $response['body']['topicId']); $this->assertEquals($data['targetId'], $response['body']['targetId']); @@ -337,7 +338,8 @@ trait MessagingBase $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'] . '/subscribers', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); + 'x-appwrite-key' => $this->getProject()['apiKey'], + ])); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); @@ -371,11 +373,11 @@ trait MessagingBase public function testSendEmail() { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_RECEIVER_EMAIL'); - $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_FROM'); - $apiKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_API_KEY'); - $domain = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_DOMAIN'); - $isEuRegion = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MAILGUN_IS_EU_REGION'); + $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); + $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); + $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); + $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); + $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { $this->markTestSkipped('Email provider not configured'); } @@ -415,7 +417,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'userId' => ID::custom('test-user'), - 'email' => 'prateekbanga12@gmail.com', + 'email' => $to, 'password' => 'password', 'name' => 'Messaging User', ], false); @@ -454,7 +456,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'providerId' => $provider['body']['$id'], - 'to' => [$target['body']['$id']], + 'to' => [$topic['body']['$id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ]); From ffeb3f8fcf1a8f954ad4ced75e057ffa1489ab72 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 17 Oct 2023 22:53:26 +0530 Subject: [PATCH 119/196] review work --- app/controllers/api/messaging.php | 45 ++-- app/init.php | 1 + app/workers/deletes.php | 22 ++ .../Database/Validator/Queries/Messages.php | 3 +- .../Database/Validator/Queries/Providers.php | 2 - tests/e2e/Services/GraphQL/MessagingTest.php | 198 +++++++++--------- 6 files changed, 146 insertions(+), 125 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index b3deaa409f..9a2f5b9856 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1,5 +1,6 @@ getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('$id', [$providerId]), - ])); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); - if ($cursorDocument === false || $cursorDocument->isEmpty()) { + if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found."); } @@ -1242,8 +1241,8 @@ App::post('/v1/messaging/topics') } $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($topic, Response::MODEL_TOPIC); + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($topic, Response::MODEL_TOPIC); }); App::get('/v1/messaging/topics') @@ -1269,12 +1268,9 @@ App::get('/v1/messaging/topics') if ($cursor) { $topicId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->find('topics', [ - Query::equal('$id', [$topicId]), - Query::limit(1), - ])); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); - if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { + if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Topic '{$topicId}' for the 'cursor' value not found."); } @@ -1330,7 +1326,7 @@ App::patch('/v1/messaging/topics/:topicId') ->label('sdk.response.model', Response::MODEL_TOPIC) ->param('topicId', '', new UID(), 'Topic ID.') ->param('name', '', new Text(128), 'Topic Name.', true) - ->param('description', null, new Text(2048), 'Topic Description.', true) + ->param('description', '', new Text(2048), 'Topic Description.', true) ->inject('dbForProject') ->inject('response') ->action(function (string $topicId, string $name, string $description, Database $dbForProject, Response $response) { @@ -1340,11 +1336,11 @@ App::patch('/v1/messaging/topics/:topicId') throw new Exception(Exception::TOPIC_NOT_FOUND); } - if ($name) { + if (!empty($name)) { $topic->setAttribute('name', $name); } - if ($description) { + if (!empty($description)) { $topic->setAttribute('description', $description); } @@ -1369,15 +1365,20 @@ App::delete('/v1/messaging/topics/:topicId') ->label('sdk.response.model', Response::MODEL_NONE) ->param('topicId', '', new UID(), 'Topic ID.') ->inject('dbForProject') + ->inject('deletes') ->inject('response') - ->action(function (string $topicId, Database $dbForProject, Response $response) { + ->action(function (string $topicId, Database $dbForProject, Delete $deletes, Response $response) { $topic = $dbForProject->getDocument('topics', $topicId); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); } - $topic = $dbForProject->deleteDocument('topics', $topicId); + $dbForProject->deleteDocument('topics', $topicId); + + $deletes + ->setType(DELETE_TYPE_SUBSCRIBERS) + ->setDocument($topic); $response ->setStatusCode(Response::STATUS_CODE_NOCONTENT) @@ -1437,8 +1438,8 @@ App::post('/v1/messaging/topics/:topicId/subscribers') } $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); }); App::get('/v1/messaging/topics/:topicId/subscribers') @@ -1563,7 +1564,7 @@ App::post('/v1/messaging/messages/email') ->param('content', '', new Text(64230), 'Email Content.') ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('deliveryTime', null, new DatetimeValidator(), 'Delivery time for message.', true) + ->param('deliveryTime', null, new DatetimeValidator(false), 'Delivery time for message.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') @@ -1634,11 +1635,9 @@ App::get('/v1/messaging/messages') if ($cursor) { $messageId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->findOne('messages', [ - Query::equal('$id', [$messageId]), - ])); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('messages', $messageId)); - if ($cursorDocument === false || $cursorDocument->isEmpty()) { + if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Message '{$messageId}' for the 'cursor' value not found."); } diff --git a/app/init.php b/app/init.php index 5b40ad386c..cc1c77c6ea 100644 --- a/app/init.php +++ b/app/init.php @@ -169,6 +169,7 @@ const DELETE_TYPE_SESSIONS = 'sessions'; const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp'; const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; const DELETE_TYPE_SCHEDULES = 'schedules'; +const DELETE_TYPE_SUBSCRIBERS = 'subscribers'; // Compression type const COMPRESSION_TYPE_NONE = 'none'; const COMPRESSION_TYPE_GZIP = 'gzip'; diff --git a/app/workers/deletes.php b/app/workers/deletes.php index f831c1df3f..d5e319a662 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -127,6 +127,10 @@ class DeletesV1 extends Worker case DELETE_TYPE_SCHEDULES: $this->deleteSchedules($this->args['datetime']); break; + case DELETE_TYPE_SUBSCRIBERS: + $topic = new Document($this->args['document'] ?? []); + $this->deleteSubscribers($project, $topic); + break; default: Console::error('No delete operation for type: ' . $type); break; @@ -170,6 +174,24 @@ class DeletesV1 extends Worker ); } + /** + * @param Document $project + * @param Document $topic + * @throws Exception + */ + protected function deleteSubscribers(Document $project, Document $topic) + { + if ($topic->isEmpty()) { + Console::error('Failed to delete subscribers. Topic not found'); + return; + } + $dbForProject = $this->getProjectDB($project); + + $this->deleteByGroup('subscribers', [ + Query::equal('topicInternalId', [$topic->getInternalId()]) + ], $dbForProject); + } + /** * @param Document $project * @param string $resource diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php index 5fa391e7f6..4bff13ae19 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php @@ -11,7 +11,8 @@ class Messages extends Base 'deliveredTo', 'deliveryErrors', 'status', - 'description' + 'description', + 'data' ]; /** diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php index ad0e08403c..1fd6c9e9f8 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php @@ -10,8 +10,6 @@ class Providers extends Base 'type', 'default', 'enabled', - 'credentials', - 'options' ]; /** diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 178b9a6a6c..8c3e4970e7 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -270,8 +270,8 @@ class MessagingTest extends Scope ]; $query = $this->getQuery(self::$CREATE_SENDGRID_PROVIDER); $graphQLPayload = [ - 'query' => $query, - 'variables' => $providerParam['sendgrid'], + 'query' => $query, + 'variables' => $providerParam['sendgrid'], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -283,13 +283,13 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$CREATE_TOPIC); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'providerId' => $providerId, - 'topicId' => ID::unique(), - 'name' => 'topic1', - 'description' => 'Active users', - ], + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -312,12 +312,12 @@ class MessagingTest extends Scope $topicId = $topic['_id']; $query = $this->getQuery(self::$UPDATE_TOPIC); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'topicId' => $topicId, - 'name' => 'topic2', - 'description' => 'Inactive users', - ], + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + 'name' => 'topic2', + 'description' => 'Inactive users', + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -339,7 +339,7 @@ class MessagingTest extends Scope { $query = $this->getQuery(self::$LIST_TOPICS); $graphQLPayload = [ - 'query' => $query, + 'query' => $query, ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -358,10 +358,10 @@ class MessagingTest extends Scope { $query = $this->getQuery(self::$GET_TOPIC); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'topicId' => $topicId, - ], + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -385,13 +385,13 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$CREATE_USER_TARGET); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'targetId' => ID::unique(), - 'userId' => $userId, - 'providerId' => $topic['providerId'], - 'identifier' => 'token', - ], + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $userId, + 'providerId' => $topic['providerId'], + 'identifier' => 'token', + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -407,12 +407,12 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$CREATE_SUBSCRIBER); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'subscriberId' => ID::unique(), - 'topicId' => $topicId, - 'targetId' => $targetId, - ], + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topicId, + 'targetId' => $targetId, + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -431,10 +431,10 @@ class MessagingTest extends Scope { $query = $this->getQuery(self::$LIST_SUBSCRIBERS); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'topicId' => $topicId, - ], + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -456,11 +456,11 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$GET_SUBSCRIBER); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'topicId' => $topicId, - 'subscriberId' => $subscriberId, - ], + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + 'subscriberId' => $subscriberId, + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -483,11 +483,11 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$DELETE_SUBSCRIBER); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'topicId' => $topicId, - 'subscriberId' => $subscriberId, - ], + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + 'subscriberId' => $subscriberId, + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -504,10 +504,10 @@ class MessagingTest extends Scope { $query = $this->getQuery(self::$DELETE_TOPIC); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'topicId' => $topicId, - ], + 'query' => $query, + 'variables' => [ + 'topicId' => $topicId, + ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -531,15 +531,15 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$CREATE_MAILGUN_PROVIDER); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'providerId' => ID::unique(), - 'name' => 'Mailgun1', - 'apiKey' => $apiKey, - 'domain' => $domain, - 'from' => $from, - 'isEuRegion' => $isEuRegion, - ], + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'Mailgun1', + 'apiKey' => $apiKey, + 'domain' => $domain, + 'from' => $from, + 'isEuRegion' => $isEuRegion, + ], ]; $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -553,13 +553,13 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$CREATE_TOPIC); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'providerId' => $providerId, - 'topicId' => ID::unique(), - 'name' => 'topic1', - 'description' => 'Active users', - ], + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], ]; $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -571,13 +571,13 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$CREATE_USER); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'userId' => ID::custom('test-user'), - 'email' => $to, - 'password' => 'password', - 'name' => 'Messaging User', - ] + 'query' => $query, + 'variables' => [ + 'userId' => ID::custom('test-user'), + 'email' => $to, + 'password' => 'password', + 'name' => 'Messaging User', + ] ]; $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -589,13 +589,13 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$CREATE_USER_TARGET); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'targetId' => ID::unique(), - 'userId' => $user['body']['data']['usersCreate']['_id'], - 'providerId' => $providerId, - 'identifier' => $to, - ], + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], ]; $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -607,12 +607,12 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$CREATE_SUBSCRIBER); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'subscriberId' => ID::unique(), - 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], - 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], - ], + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], ]; $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -623,14 +623,14 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$CREATE_EMAIL); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'messageId' => ID::unique(), - 'providerId' => $providerId, - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], - 'subject' => 'Khali beats Undertaker', - 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', - ], + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ], ]; $email = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', @@ -644,10 +644,10 @@ class MessagingTest extends Scope $query = $this->getQuery(self::$GET_MESSAGE); $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'messageId' => $email['body']['data']['messagingCreateEmail']['_id'], - ], + 'query' => $query, + 'variables' => [ + 'messageId' => $email['body']['data']['messagingCreateEmail']['_id'], + ], ]; $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', From 8602c44d14ad5af3be4e2ba6ed63259866322f25 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 17 Oct 2023 23:29:10 +0530 Subject: [PATCH 120/196] adds user targets graphql testsl --- tests/e2e/Services/GraphQL/UsersTest.php | 145 +++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/tests/e2e/Services/GraphQL/UsersTest.php b/tests/e2e/Services/GraphQL/UsersTest.php index 9bd503df0f..c0327381cd 100644 --- a/tests/e2e/Services/GraphQL/UsersTest.php +++ b/tests/e2e/Services/GraphQL/UsersTest.php @@ -45,6 +45,55 @@ class UsersTest extends Scope return $user; } + /** + * @depends testCreateUser + */ + public function testCreateUserTarget(array $user) + { + $projectId = $this->getProject()['$id']; + + $query = $this->getQuery(self::$CREATE_MAILGUN_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'Mailgun1', + 'apiKey' => 'api-key', + 'domain' => 'domain', + 'from' => 'from@domain', + 'isEuRegion' => false, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getHeaders()), $graphQLPayload); + $providerId = $provider['body']['data']['messagingCreateMailgunProvider']['_id']; + + $this->assertEquals(200, $provider['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['_id'], + 'providerId' => $providerId, + 'identifier' => 'identifier', + ] + ]; + + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + $this->assertEquals('identifier', $target['body']['data']['usersCreateTarget']['identifier']); + + return $target['body']['data']['usersCreateTarget']; + } + public function testGetUsers() { $projectId = $this->getProject()['$id']; @@ -176,6 +225,54 @@ class UsersTest extends Scope $this->assertIsArray($user['body']['data']['usersListLogs']); } + /** + * @depends testCreateUserTarget + */ + public function testListUserTargets(array $target) + { + $projectId = $this->getProject()['$id']; + $query = $this->getQuery(self::$LIST_USER_TARGETS); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => $target['userId'], + ] + ]; + + $targets = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $targets['headers']['status-code']); + $this->assertIsArray($targets['body']['data']['usersListTargets']); + $this->assertCount(1, $targets['body']['data']['usersListTargets']['targets']); + } + + /** + * @depends testCreateUserTarget + */ + public function testGetUserTarget(array $target) + { + $projectId = $this->getProject()['$id']; + $query = $this->getQuery(self::$GET_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => $target['userId'], + 'targetId' => $target['_id'], + ] + ]; + + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + $this->assertEquals('identifier', $target['body']['data']['usersGetTarget']['identifier']); + } + public function testUpdateUserStatus() { $projectId = $this->getProject()['$id']; @@ -360,6 +457,31 @@ class UsersTest extends Scope $this->assertEquals('{"key":"value"}', $user['body']['data']['usersUpdatePrefs']['data']); } + /** + * @depends testCreateUserTarget + */ + public function testUpdateUserTarget(array $target) + { + $projectId = $this->getProject()['$id']; + $query = $this->getQuery(self::$UPDATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => $target['userId'], + 'targetId' => $target['_id'], + 'identifier' => 'newidentifier', + ], + ]; + + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + $this->assertEquals('newidentifier', $target['body']['data']['usersUpdateTargetIdentifier']['identifier']); + } + public function testDeleteUserSessions() { $projectId = $this->getProject()['$id']; @@ -407,6 +529,29 @@ class UsersTest extends Scope $this->getUser(); } + /** + * @depends testCreateUserTarget + */ + public function testDeleteUserTarget(array $target) + { + $projectId = $this->getProject()['$id']; + $query = $this->getQuery(self::$DELETE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => $target['userId'], + 'targetId' => $target['_id'], + ] + ]; + + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(204, $target['headers']['status-code']); + } + public function testDeleteUser() { $projectId = $this->getProject()['$id']; From b86f531b309ff44071d8e91e618b49674df5d8dc Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 17 Oct 2023 23:45:46 +0530 Subject: [PATCH 121/196] adds data in message model and search param in messages query validator --- .../Utopia/Database/Validator/Queries/Messages.php | 3 ++- src/Appwrite/Utopia/Response/Model/Message.php | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php index 4bff13ae19..d21aa5de1b 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php @@ -12,7 +12,8 @@ class Messages extends Base 'deliveryErrors', 'status', 'description', - 'data' + 'data', + 'search' ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 5e4a358490..0cadc378d9 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -58,6 +58,15 @@ class Message extends Any 'default' => 0, 'example' => 1, ]) + ->addRule('data', [ + 'type' => self::TYPE_JSON, + 'description' => 'Data of the message.', + 'default' => [], + 'example' => [ + 'subject' => 'Welcome to Appwrite', + 'content' => 'Hi there, welcome to Appwrite family.', + ], + ]) ->addRule('status', [ 'type' => self::TYPE_STRING, 'description' => 'Status of delivery.', From 4bef86d88b15f41589b736369026774222d29cd0 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 18 Oct 2023 13:19:21 +0530 Subject: [PATCH 122/196] review changes --- app/controllers/api/databases.php | 7 +++- app/controllers/api/messaging.php | 39 ++++++++++++----- composer.json | 6 +-- composer.lock | 42 +++++++++---------- .../Validator/Queries/Subscribers.php | 20 +++++++++ 5 files changed, 78 insertions(+), 36 deletions(-) create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 0c60c01a1e..9eb243521b 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2489,8 +2489,11 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'orders' => $orders, ]); - $validator = new IndexValidator($dbForProject->getAdapter()->getMaxIndexLength()); - if (!$validator->isValid($collection->setAttribute('indexes', $index, Document::SET_TYPE_APPEND))) { + $validator = new IndexValidator( + $collection->getAttribute('attributes'), + $dbForProject->getAdapter()->getMaxIndexLength() + ); + if (!$validator->isValid($index)) { throw new Exception(Exception::INDEX_INVALID, $validator->getDescription()); } diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 9a2f5b9856..72f0b9fdb4 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -8,6 +8,7 @@ use Appwrite\Role; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Database\Validator\Queries\Messages; use Appwrite\Utopia\Database\Validator\Queries\Providers; +use Appwrite\Utopia\Database\Validator\Queries\Subscribers; use Appwrite\Utopia\Database\Validator\Queries\Topics; use Appwrite\Utopia\Response; use Utopia\App; @@ -1454,23 +1455,41 @@ App::get('/v1/messaging/topics/:topicId/subscribers') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_SUBSCRIBER_LIST) ->param('topicId', '', new UID(), 'Topic ID.') + ->param('queries', [], new Subscribers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) ->inject('dbForProject') ->inject('response') - ->action(function (string $topicId, Database $dbForProject, Response $response) { + ->action(function (string $topicId, array $queries, Database $dbForProject, Response $response) { + $queries = Query::parseQueries($queries); + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { throw new Exception(Exception::TOPIC_NOT_FOUND); } - $subscribers = $dbForProject->find('subscribers', [ - Query::equal('topicInternalId', [$topic->getInternalId()]) - ]); + \array_push($queries, Query::equal('topicInternalId', [$topic->getInternalId()])); + + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); + + if ($cursor) { + $subscriberId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId)); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Subscriber '{$subscriberId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + + $filterQueries = Query::groupByType($queries)['filters']; $response ->dynamic(new Document([ - 'subscribers' => $subscribers, - 'total' => \count($subscribers), + 'subscribers' => $dbForProject->find('subscribers', $queries), + 'total' => $dbForProject->count('subscribers', $filterQueries, APP_LIMIT_COUNT), ]), Response::MODEL_SUBSCRIBER_LIST); }); @@ -1562,9 +1581,9 @@ App::post('/v1/messaging/messages/email') ->param('subject', '', new Text(998), 'Email Subject.') ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.') - ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status.', true) + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('deliveryTime', null, new DatetimeValidator(false), 'Delivery time for message.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') @@ -1693,9 +1712,9 @@ App::patch('/v1/messaging/messages/email/:messageId') ->param('subject', '', new Text(998), 'Email Subject.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) - ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status.', true) + ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('deliveryTime', null, new DatetimeValidator(), 'Delivery time for message in ISO 8601 format.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') diff --git a/composer.json b/composer.json index ed5cfbd825..f4d92146c0 100644 --- a/composer.json +++ b/composer.json @@ -43,13 +43,13 @@ "ext-sockets": "*", "appwrite/php-runtimes": "0.13.*", "appwrite/php-clamav": "2.0.*", - "utopia-php/abuse": "0.31.*", + "utopia-php/abuse": "0.32.*", "utopia-php/analytics": "0.10.*", - "utopia-php/audit": "0.33.*", + "utopia-php/audit": "0.34.*", "utopia-php/cache": "0.8.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.43.*", + "utopia-php/database": "0.44.*", "utopia-php/domains": "0.3.*", "utopia-php/dsn": "0.1.*", "utopia-php/framework": "0.31.0", diff --git a/composer.lock b/composer.lock index f80104986c..8f7ca86d06 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": "34cb0b1c81424d1858df197aed030793", + "content-hash": "ee4518740e581a9a4889936fb584a5a4", "packages": [ { "name": "adhocore/jwt", @@ -1861,23 +1861,23 @@ }, { "name": "utopia-php/abuse", - "version": "0.31.1", + "version": "0.32.0", "source": { "type": "git", "url": "https://github.com/utopia-php/abuse.git", - "reference": "b2ad372d1070f55f9545cb811b6ed2d40094e6dd" + "reference": "9717ffb2d7711f3fd621bb6df3edf5724c08ea78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/abuse/zipball/b2ad372d1070f55f9545cb811b6ed2d40094e6dd", - "reference": "b2ad372d1070f55f9545cb811b6ed2d40094e6dd", + "url": "https://api.github.com/repos/utopia-php/abuse/zipball/9717ffb2d7711f3fd621bb6df3edf5724c08ea78", + "reference": "9717ffb2d7711f3fd621bb6df3edf5724c08ea78", "shasum": "" }, "require": { "ext-curl": "*", "ext-pdo": "*", "php": ">=8.0", - "utopia-php/database": "0.43.*" + "utopia-php/database": "0.44.*" }, "require-dev": { "laravel/pint": "1.5.*", @@ -1904,9 +1904,9 @@ ], "support": { "issues": "https://github.com/utopia-php/abuse/issues", - "source": "https://github.com/utopia-php/abuse/tree/0.31.1" + "source": "https://github.com/utopia-php/abuse/tree/0.32.0" }, - "time": "2023-08-29T11:07:46+00:00" + "time": "2023-10-18T07:28:55+00:00" }, { "name": "utopia-php/analytics", @@ -1956,21 +1956,21 @@ }, { "name": "utopia-php/audit", - "version": "0.33.1", + "version": "0.34.0", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "c117e8e9ce4e3e1b369e8b5b55b2d6ab3138eadd" + "reference": "cf34cc3f9f20da4e574a9be4517e1a11025a858f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/c117e8e9ce4e3e1b369e8b5b55b2d6ab3138eadd", - "reference": "c117e8e9ce4e3e1b369e8b5b55b2d6ab3138eadd", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/cf34cc3f9f20da4e574a9be4517e1a11025a858f", + "reference": "cf34cc3f9f20da4e574a9be4517e1a11025a858f", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/database": "0.43.*" + "utopia-php/database": "0.44.*" }, "require-dev": { "laravel/pint": "1.5.*", @@ -1997,9 +1997,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/0.33.1" + "source": "https://github.com/utopia-php/audit/tree/0.34.0" }, - "time": "2023-08-29T11:07:40+00:00" + "time": "2023-10-18T07:43:25+00:00" }, { "name": "utopia-php/cache", @@ -2152,16 +2152,16 @@ }, { "name": "utopia-php/database", - "version": "0.43.5", + "version": "0.44.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "5f7b05189cfbcc0506090498c580c5765375a00a" + "reference": "e0b832d217e4d429c96ade671e85ece942446543" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/5f7b05189cfbcc0506090498c580c5765375a00a", - "reference": "5f7b05189cfbcc0506090498c580c5765375a00a", + "url": "https://api.github.com/repos/utopia-php/database/zipball/e0b832d217e4d429c96ade671e85ece942446543", + "reference": "e0b832d217e4d429c96ade671e85ece942446543", "shasum": "" }, "require": { @@ -2202,9 +2202,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.43.5" + "source": "https://github.com/utopia-php/database/tree/0.44.1" }, - "time": "2023-10-06T06:49:47+00:00" + "time": "2023-10-18T07:05:41+00:00" }, { "name": "utopia-php/domains", diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php new file mode 100644 index 0000000000..048ae60033 --- /dev/null +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php @@ -0,0 +1,20 @@ + Date: Wed, 18 Oct 2023 13:30:01 +0530 Subject: [PATCH 123/196] fix typo --- src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php index 048ae60033..55bb455903 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php @@ -15,6 +15,6 @@ class Subscribers extends Base */ public function __construct() { - parent::__construct('messages', self::ALLOWED_ATTRIBUTES); + parent::__construct('subscribers', self::ALLOWED_ATTRIBUTES); } } From 99b5ac8669d60997454ceef3c1758f8d7067c21f Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 19 Oct 2023 13:29:48 +0530 Subject: [PATCH 124/196] adds push and sms controllers --- .env | 2 + app/controllers/api/messaging.php | 379 ++++++++- composer.lock | 2 +- docker-compose.yml | 3 +- tests/e2e/Services/GraphQL/Base.php | 76 ++ tests/e2e/Services/GraphQL/MessagingTest.php | 761 +++++++++++++++++- .../e2e/Services/Messaging/MessagingBase.php | 598 +++++++++++++- 7 files changed, 1805 insertions(+), 16 deletions(-) diff --git a/.env b/.env index aa90470729..127efd2e4a 100644 --- a/.env +++ b/.env @@ -108,3 +108,5 @@ _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN= _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM= _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL= _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION= +_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY= +_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN= diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 72f0b9fdb4..8735cf57de 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -22,6 +22,7 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; +use Utopia\Validator\JSON; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -1593,7 +1594,7 @@ App::post('/v1/messaging/messages/email') $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty()) { + if ($provider->isEmpty() || $provider->getAttribute('type') !== 'email') { throw new Exception(Exception::PROVIDER_NOT_FOUND); } @@ -1602,14 +1603,183 @@ App::post('/v1/messaging/messages/email') 'providerId' => $provider->getId(), 'providerInternalId' => $provider->getInternalId(), 'to' => $to, + 'description' => $description, 'data' => [ 'subject' => $subject, 'content' => $content, 'html' => $html, - 'description' => $description, ], 'status' => $status, - 'search' => $messageId . ' ' . $description . ' ' . $subject, + 'search' => $messageId . ' ' . $description . ' ' . $subject . ' ' . $providerId, + ])); + + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging + ->setDeliveryTime($deliveryTime) + ->schedule(); + } else { + $messaging->trigger(); + } + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($message, Response::MODEL_MESSAGE); + }); + +App::post('/v1/messaging/messages/sms') + ->desc('Create an sms.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.create') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createSMS') + ->label('sdk.description', '/docs/references/messaging/create-sms.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new UID(), 'SMS Provider ID.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') + ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('content', '', new Text(64230), 'SMS Content.') + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('dbForProject') + ->inject('project') + ->inject('messaging') + ->inject('response') + ->action(function (string $messageId, string $providerId, array $to, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty() || $provider->getAttribute('type') !== 'sms') { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $message = $dbForProject->createDocument('messages', new Document([ + '$id' => $messageId, + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'to' => $to, + 'description' => $description, + 'data' => [ + 'content' => $content, + ], + 'status' => $status, + 'search' => $messageId . ' ' . $description . ' ' . $providerId, + ])); + + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging + ->setDeliveryTime($deliveryTime) + ->schedule(); + } else { + $messaging->trigger(); + } + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($message, Response::MODEL_MESSAGE); + }); + +App::post('/v1/messaging/messages/push') + ->desc('Create a push notification.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.create') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createPushNotification') + ->label('sdk.description', '/docs/references/messaging/create-push-notification.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new UID(), 'Push Provider ID.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') + ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('title', '', new Text(256), 'Title for push notification.') + ->param('body', '', new Text(64230), 'Body for push notification.') + ->param('data', null, new JSON(), 'Additional Data for push notification.', true) + ->param('action', '', new Text(256), 'Action for push notification.', true) + ->param('icon', '', new Text(256), 'Icon for push notification.', true) + ->param('sound', '', new Text(256), 'Sound for push notification.', true) + ->param('color', '', new Text(256), 'Color for push notification.', true) + ->param('tag', '', new Text(256), 'Tag for push notification.', true) + ->param('badge', '', new Text(256), 'Badge for push notification.', true) + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('dbForProject') + ->inject('project') + ->inject('messaging') + ->inject('response') + ->action(function (string $messageId, string $providerId, array $to, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty() || $provider->getAttribute('type') !== 'push') { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $pushData = [ + 'title' => $title, + 'body' => $body, + ]; + + if (!is_null($data)) { + $pushData['data'] = $data; + } + + if ($action) { + $pushData['action'] = $action; + } + + if ($icon) { + $pushData['icon'] = $icon; + } + + if ($sound) { + $pushData['sound'] = $sound; + } + + if ($color) { + $pushData['color'] = $color; + } + + if ($tag) { + $pushData['tag'] = $tag; + } + + if ($badge) { + $pushData['badge'] = $badge; + } + + $message = $dbForProject->createDocument('messages', new Document([ + '$id' => $messageId, + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'to' => $to, + 'description' => $description, + 'data' => $pushData, + 'status' => $status, + 'search' => $messageId . ' ' . $description . ' ' . $title . ' ' . $providerId, ])); if ($status === 'processing') { @@ -1704,7 +1874,7 @@ App::patch('/v1/messaging/messages/email/:messageId') ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateEmail') ->label('sdk.description', '/docs/references/messaging/update-email.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') @@ -1744,21 +1914,212 @@ App::patch('/v1/messaging/messages/email/:messageId') $data['content'] = $content; } - if (!empty($description)) { - $data['description'] = $description; - } - if (!empty($html)) { $data['html'] = $html; } $message->setAttribute('data', $data); - $message->setAttribute('search', $message->getId() . ' ' . $data['description'] . ' ' . $data['subject']); + $message->setAttribute('search', $message->getId() . ' ' . $data['description'] . ' ' . $data['subject'] . ' ' . $message->getAttribute('providerId')); + + if (!empty($description)) { + $message->setAttribute('description', $description); + } if (!empty($status)) { $message->setAttribute('status', $status); } + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); + + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging + ->setDeliveryTime($deliveryTime) + ->schedule(); + } else { + $messaging->trigger(); + } + } + + $response + ->dynamic($message, Response::MODEL_MESSAGE); + }); + +App::patch('/v1/messaging/messages/sms/:messageId') + ->desc('Update an sms.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.update') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateSMS') + ->label('sdk.description', '/docs/references/messaging/update-email.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new UID(), 'Message ID.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('content', '', new Text(64230), 'Email Content.', true) + ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('dbForProject') + ->inject('project') + ->inject('messaging') + ->inject('response') + ->action(function (string $messageId, array $to, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $message = $dbForProject->getDocument('messages', $messageId); + + if ($message->isEmpty()) { + throw new Exception(Exception::MESSAGE_NOT_FOUND); + } + + if ($message->getAttribute('status') === 'sent') { + throw new Exception(Exception::MESSAGE_ALREADY_SENT); + } + + if (\count($to) > 0) { + $message->setAttribute('to', $to); + } + + $data = $message->getAttribute('data'); + + if (!empty($content)) { + $data['content'] = $content; + } + + $message->setAttribute('data', $data); + $message->setAttribute('search', $message->getId() . ' ' . $data['description'] . ' ' . $message->getAttribute('providerId')); + + if (!empty($status)) { + $message->setAttribute('status', $status); + } + + if (!empty($description)) { + $message->setAttribute('description', $description); + } + + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); + + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging + ->setDeliveryTime($deliveryTime) + ->schedule(); + } else { + $messaging->trigger(); + } + } + + $response + ->dynamic($message, Response::MODEL_MESSAGE); + }); + +App::patch('/v1/messaging/messages/push/:messageId') + ->desc('Update a push notification.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.update') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updatePushNotification') + ->label('sdk.description', '/docs/references/messaging/update-push-notification.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new UID(), 'Message ID.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('title', '', new Text(256), 'Title for push notification.', true) + ->param('body', '', new Text(64230), 'Body for push notification.', true) + ->param('data', null, new JSON(), 'Additional Data for push notification.', true) + ->param('action', '', new Text(256), 'Action for push notification.', true) + ->param('icon', '', new Text(256), 'Icon for push notification.', true) + ->param('sound', '', new Text(256), 'Sound for push notification.', true) + ->param('color', '', new Text(256), 'Color for push notification.', true) + ->param('tag', '', new Text(256), 'Tag for push notification.', true) + ->param('badge', '', new Text(256), 'Badge for push notification.', true) + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('dbForProject') + ->inject('project') + ->inject('messaging') + ->inject('response') + ->action(function (string $messageId, array $to, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $message = $dbForProject->getDocument('messages', $messageId); + + if ($message->isEmpty()) { + throw new Exception(Exception::MESSAGE_NOT_FOUND); + } + + if ($message->getAttribute('status') === 'sent') { + throw new Exception(Exception::MESSAGE_ALREADY_SENT); + } + + if (\count($to) > 0) { + $message->setAttribute('to', $to); + } + + $pushData = $message->getAttribute('data'); + + if ($title) { + $pushData['title'] = $title; + } + + if ($body) { + $pushData['body'] = $body; + } + + if (!is_null($data)) { + $pushData['data'] = $data; + } + + if ($action) { + $pushData['action'] = $action; + } + + if ($icon) { + $pushData['icon'] = $icon; + } + + if ($sound) { + $pushData['sound'] = $sound; + } + + if ($color) { + $pushData['color'] = $color; + } + + if ($tag) { + $pushData['tag'] = $tag; + } + + if ($badge) { + $pushData['badge'] = $badge; + } + + $message->setAttribute('data', $pushData); + $message->setAttribute('search', $message->getId() . ' ' . $pushData['description'] . ' ' . $pushData['title'] . ' ' . $message->getAttribute('providerId')); + + if (!empty($status)) { + $message->setAttribute('status', $status); + } + + if (!empty($description)) { + $message->setAttribute('description', $description); + } + + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { diff --git a/composer.lock b/composer.lock index 8f7ca86d06..e44b093609 100644 --- a/composer.lock +++ b/composer.lock @@ -6019,5 +6019,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/docker-compose.yml b/docker-compose.yml index a365ce17ba..c8a7b6c64b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -197,7 +197,8 @@ services: - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION - + - _APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY + - _APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN appwrite-realtime: entrypoint: realtime <<: *x-logging diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index f3947c53b4..9cd4fe0629 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -240,9 +240,15 @@ trait Base // Messages public static string $CREATE_EMAIL = 'create_email'; + public static string $CREATE_SMS = 'create_sms'; + public static string $CREATE_PUSH_NOTIFICATION = 'create_push_notification'; public static string $LIST_MESSAGES = 'list_messages'; public static string $GET_MESSAGE = 'get_message'; + public static string $UPDATE_EMAIL = 'update_email'; + public static string $UPDATE_SMS = 'update_sms'; + public static string $UPDATE_PUSH_NOTIFICATION = 'update_push_notification'; + // Complex queries public static string $COMPLEX_QUERY = 'complex_query'; @@ -2098,6 +2104,34 @@ trait Base description } }'; + case self::$CREATE_SMS: + return 'mutation createSMS($messageId: String!, $providerId: String!, $to: [String!]!, $content: String!, $status: String, $description: String, $deliveryTime: String) { + messagingCreateSMS(messageId: $messageId, providerId: $providerId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; + case self::$CREATE_PUSH_NOTIFICATION: + return 'mutation createPushNotification($messageId: String!, $providerId: String!, $to: [String!]!, $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { + messagingCreatePushNotification(messageId: $messageId, providerId: $providerId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; case self::$LIST_MESSAGES: return 'query listMessages { messagingListMessages { @@ -2129,6 +2163,48 @@ trait Base description } }'; + case self::$UPDATE_EMAIL: + return 'mutation updateEmail($messageId: String!, $to: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { + messagingUpdateEmail(messageId: $messageId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; + case self::$UPDATE_SMS: + return 'mutation updateSMS($messageId: String!, $to: [String!], $content: String, $status: String, $description: String, $deliveryTime: String) { + messagingUpdateSMS(messageId: $messageId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; + case self::$UPDATE_PUSH_NOTIFICATION: + return 'mutation updatePushNotification($messageId: String!, $to: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { + messagingUpdatePushNotification(messageId: $messageId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; case self::$COMPLEX_QUERY: return 'mutation complex($databaseId: String!, $databaseName: String!, $collectionId: String!, $collectionName: String!, $documentSecurity: Boolean!, $collectionPermissions: [String!]!) { databasesCreate(databaseId: $databaseId, name: $databaseName) { diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 8c3e4970e7..ec8f4b0a6a 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -573,8 +573,8 @@ class MessagingTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'userId' => ID::custom('test-user'), - 'email' => $to, + 'userId' => ID::unique(), + 'email' => 'random1-mail@mail.org', 'password' => 'password', 'name' => 'Messaging User', ] @@ -658,5 +658,762 @@ class MessagingTest extends Scope $this->assertEquals(200, $message['headers']['status-code']); $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + + return $message['body']['data']['messagingGetMessage']; + } + + /** + * @depends testSendEmail + */ + public function testUpdateEmail(array $email) + { + $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); + $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); + $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); + $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); + $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); + if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { + $this->markTestSkipped('Email provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_MAILGUN_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'Mailgun2', + 'apiKey' => $apiKey, + 'domain' => $domain, + 'from' => $from, + 'isEuRegion' => $isEuRegion, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + + $providerId = $provider['body']['data']['messagingCreateMailgunProvider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random2-mail@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_EMAIL); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'status' => 'draft', + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ], + ]; + $email = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $email['headers']['status-code']); + + $query = $this->getQuery(self::$UPDATE_EMAIL); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $email['body']['data']['messagingCreateEmail']['_id'], + 'status' => 'processing', + ], + ]; + $email = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $email['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $email['body']['data']['messagingUpdateEmail']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + } + + public function testSendSMS() + { + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { + $this->markTestSkipped('SMS provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_MSG91_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'Msg91-1', + 'senderId' => $senderId, + 'authKey' => $authKey, + 'from' => $from, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + + $providerId = $provider['body']['data']['messagingCreateMsg91Provider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random3-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SMS); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'content' => '454665', + ], + ]; + $sms = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $sms['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $sms['body']['data']['messagingCreateSMS']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + return $message['body']['data']['messagingGetMessage']; + } + + /** + * @depends testSendSMS + */ + public function testUpdateSMS(array $sms) + { + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { + $this->markTestSkipped('SMS provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_MSG91_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'Msg91-2', + 'senderId' => $senderId, + 'authKey' => $authKey, + 'from' => $from, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + + $providerId = $provider['body']['data']['messagingCreateMsg91Provider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random4-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SMS); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'status' => 'draft', + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'content' => '345463', + ], + ]; + $sms = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $sms['headers']['status-code']); + + $query = $this->getQuery(self::$UPDATE_SMS); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $sms['body']['data']['messagingCreateSMS']['_id'], + 'status' => 'processing', + ], + ]; + $sms = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $sms['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $sms['body']['data']['messagingUpdateSMS']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + } + + public function testSendPushNotification() + { + $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); + $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + if (empty($to) || empty($serverKey)) { + $this->markTestSkipped('Push provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_FCM_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'FCM1', + 'serverKey' => $serverKey, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + + $providerId = $provider['body']['data']['messagingCreateFcmProvider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random5-mail@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_PUSH_NOTIFICATION); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'title' => 'Push Notification Title', + 'body' => 'Push Notifiaction Body', + ], + ]; + $push = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $push['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $push['body']['data']['messagingCreatePushNotification']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + + return $message['body']['data']['messagingGetMessage']; + } + + /** + * @depends testSendPushNotification + */ + public function testUpdatePushNotification(array $push) + { + $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); + $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + if (empty($to) || empty($serverKey)) { + $this->markTestSkipped('Push provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_FCM_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'FCM2', + 'serverKey' => $serverKey, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + var_dump($provider['body']); + $providerId = $provider['body']['data']['messagingCreateFcmProvider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random5-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_PUSH_NOTIFICATION); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'status' => 'draft', + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'title' => 'Push Notification Title', + 'body' => 'Push Notifiaction Body', + ], + ]; + $push = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $push['headers']['status-code']); + + $query = $this->getQuery(self::$UPDATE_PUSH_NOTIFICATION); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $push['body']['data']['messagingCreatePushNotification']['_id'], + 'status' => 'processing', + ], + ]; + $push = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $push['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $push['body']['data']['messagingUpdatePushNotification']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); } } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 1c349a2dbe..b4ed8311df 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -416,16 +416,16 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'userId' => ID::custom('test-user'), + 'userId' => ID::unique(), 'email' => $to, 'password' => 'password', 'name' => 'Messaging User', - ], false); + ]); $this->assertEquals(201, $user['headers']['status-code']); // Create Target - $target = $this->client->call(Client::METHOD_POST, '/users/test-user/targets', [ + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -475,5 +475,597 @@ trait MessagingBase $this->assertEquals(200, $message['headers']['status-code']); $this->assertEquals(1, $message['body']['deliveredTo']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + + return $message; + } + + /** + * @depends testSendEmail + */ + public function testUpdateEmail(array $email) + { + + $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); + $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); + $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); + $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); + $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); + if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { + $this->markTestSkipped('Email provider not configured'); + } + + $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + // Test failure as the message has already been sent. + $this->assertEquals(400, $message['headers']['status-code']); + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/mailgun', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'Mailgun-provider-2', + 'apiKey' => $apiKey, + 'domain' => $domain, + 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), + 'from' => $from + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create Email + $email = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'status' => 'draft', + 'to' => [$topic['body']['$id']], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ]); + + $this->assertEquals(201, $email['headers']['status-code']); + + $email = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'status' => 'processing', + ]); + + $this->assertEquals(200, $email['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + } + + public function testSendSMS() + { + + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { + $this->markTestSkipped('SMS provider not configured'); + } + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/msg91', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'Msg91-1', + 'senderId' => $senderId, + 'authKey' => $authKey, + 'from' => $from + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random1-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create SMS + $sms = $this->client->call(Client::METHOD_POST, '/messaging/messages/sms', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'to' => [$topic['body']['$id']], + 'content' => '064763', + ]); + + $this->assertEquals(201, $sms['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $sms['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + + return $message; + } + + /** + * @depends testSendSMS + */ + public function testUpdateSMS(array $sms) + { + + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { + $this->markTestSkipped('SMS provider not configured'); + } + + $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/sms/' . $sms['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + // Test failure as the message has already been sent. + $this->assertEquals(400, $message['headers']['status-code']); + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/msg91', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'Msg91-2', + 'senderId' => $senderId, + 'authKey' => $authKey, + 'from' => $from + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random2-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create SMS + $sms = $this->client->call(Client::METHOD_POST, '/messaging/messages/sms', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'status' => 'draft', + 'to' => [$topic['body']['$id']], + 'content' => '047487', + ]); + + $this->assertEquals(201, $sms['headers']['status-code']); + + $sms = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/sms/' . $sms['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'status' => 'processing', + ]); + + $this->assertEquals(200, $sms['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $sms['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + } + + public function testSendPushNotification() + { + + $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); + $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + if (empty($to) || empty($serverKey)) { + $this->markTestSkipped('Push provider not configured'); + } + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/fcm', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'FCM-1', + 'serverKey' => $serverKey, + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random3-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create push notification + $push = $this->client->call(Client::METHOD_POST, '/messaging/messages/push', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'to' => [$topic['body']['$id']], + 'title' => 'Test-Notification', + 'body' => 'Test-Notification-Body', + ]); + + $this->assertEquals(201, $push['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $push['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + + return $message; + } + + /** + * @depends testSendPushNotification + */ + public function testUpdatePushNotification(array $push) + { + + $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); + $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + if (empty($to) || empty($serverKey)) { + $this->markTestSkipped('Push provider not configured'); + } + + $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/push/' . $push['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + // Test failure as the message has already been sent. + $this->assertEquals(400, $message['headers']['status-code']); + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/fcm', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'FCM-2', + 'serverKey' => $serverKey, + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random4-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create push notification + $push = $this->client->call(Client::METHOD_POST, '/messaging/messages/push', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'status' => 'draft', + 'to' => [$topic['body']['$id']], + 'title' => 'Test-Notification', + 'body' => 'Test-Notification-Body', + ]); + + $this->assertEquals(201, $push['headers']['status-code']); + + $push = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/push/' . $push['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'status' => 'processing', + ]); + + $this->assertEquals(200, $push['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $push['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } } From db9e7b0199b39f27dfb009446a9c79cf86986ab7 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 20 Oct 2023 13:28:23 +0530 Subject: [PATCH 125/196] review changes --- app/config/errors.php | 5 +++ app/controllers/api/messaging.php | 65 +++++++++++++++++++++---------- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 5514e8e68e..07741eddac 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -790,5 +790,10 @@ return [ 'name' => Exception::MESSAGE_ALREADY_SENT, 'description' => 'Message with the requested ID has already been sent.', 'code' => 400, + ], + Exception::MESSAGE_ALREADY_SCHEDULED => [ + 'name' => Exception::MESSAGE_ALREADY_SCHEDULED, + 'description' => 'Message with the requested ID has already been scheduled for delivery.', + 'code' => 400, ] ]; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 8735cf57de..ae048020ac 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1580,8 +1580,8 @@ App::post('/v1/messaging/messages/email') ->param('providerId', '', new UID(), 'Email Provider ID.') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(998), 'Email Subject.') - ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.') + ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) @@ -1589,15 +1589,19 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $subject, string $content, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty() || $provider->getAttribute('type') !== 'email') { + if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } + if ($provider->getAttribute('type') !== 'email') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, 'providerId' => $provider->getId(), @@ -1633,7 +1637,7 @@ App::post('/v1/messaging/messages/email') }); App::post('/v1/messaging/messages/sms') - ->desc('Create an sms.') + ->desc('Create an SMS.') ->groups(['api', 'messaging']) ->label('audits.event', 'messages.create') ->label('audits.resource', 'messages/{response.$id}') @@ -1648,23 +1652,27 @@ App::post('/v1/messaging/messages/sms') ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('providerId', '', new UID(), 'SMS Provider ID.') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') - ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'SMS Content.') + ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $content, string $description, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty() || $provider->getAttribute('type') !== 'sms') { + if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } + if ($provider->getAttribute('type') !== 'sms') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, 'providerId' => $provider->getId(), @@ -1713,31 +1721,35 @@ App::post('/v1/messaging/messages/push') ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('providerId', '', new UID(), 'Push Provider ID.') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') - ->param('description', '', new Text(256), 'Description for Message.', true) ->param('title', '', new Text(256), 'Title for push notification.') ->param('body', '', new Text(64230), 'Body for push notification.') + ->param('description', '', new Text(256), 'Description for Message.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true) ->param('action', '', new Text(256), 'Action for push notification.', true) - ->param('icon', '', new Text(256), 'Icon for push notification.', true) - ->param('sound', '', new Text(256), 'Sound for push notification.', true) - ->param('color', '', new Text(256), 'Color for push notification.', true) - ->param('tag', '', new Text(256), 'Tag for push notification.', true) - ->param('badge', '', new Text(256), 'Badge for push notification.', true) + ->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true) + ->param('sound', '', new Text(256), 'Sound for push notification. Available only for Android and IOS Platform.', true) + ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) + ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) + ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $title, string $body, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty() || $provider->getAttribute('type') !== 'push') { + if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } + if ($provider->getAttribute('type') !== 'push') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); + } + $pushData = [ 'title' => $title, 'body' => $body, @@ -1900,6 +1912,10 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } + if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); + } + if (\count($to) > 0) { $message->setAttribute('to', $to); } @@ -1983,6 +1999,10 @@ App::patch('/v1/messaging/messages/sms/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } + if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); + } + if (\count($to) > 0) { $message->setAttribute('to', $to); } @@ -2044,12 +2064,11 @@ App::patch('/v1/messaging/messages/push/:messageId') ->param('body', '', new Text(64230), 'Body for push notification.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true) ->param('action', '', new Text(256), 'Action for push notification.', true) - ->param('icon', '', new Text(256), 'Icon for push notification.', true) - ->param('sound', '', new Text(256), 'Sound for push notification.', true) - ->param('color', '', new Text(256), 'Color for push notification.', true) - ->param('tag', '', new Text(256), 'Tag for push notification.', true) - ->param('badge', '', new Text(256), 'Badge for push notification.', true) - ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true) + ->param('sound', '', new Text(256), 'Sound for push notification. Available only for Android and IOS Platform.', true) + ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) + ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) + ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) ->inject('dbForProject') ->inject('project') @@ -2066,6 +2085,10 @@ App::patch('/v1/messaging/messages/push/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } + if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); + } + if (\count($to) > 0) { $message->setAttribute('to', $to); } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index ee17ccef0c..6650accb9d 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -241,6 +241,7 @@ class Exception extends \Exception /** Message */ public const MESSAGE_NOT_FOUND = 'message_not_found'; public const MESSAGE_ALREADY_SENT = 'message_already_sent'; + public const MESSAGE_ALREADY_SCHEDULED = 'message_already_scheduled'; protected $type = ''; protected $errors = []; From e4d2d15f7047d7e1700f6825e6512f39738a32aa Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 20 Oct 2023 13:31:56 +0530 Subject: [PATCH 126/196] review changes --- app/controllers/api/messaging.php | 13 +++++++++++++ tests/e2e/Services/Messaging/MessagingBase.php | 6 ------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index ae048020ac..8e79912566 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1679,6 +1679,7 @@ App::post('/v1/messaging/messages/sms') 'providerInternalId' => $provider->getInternalId(), 'to' => $to, 'description' => $description, + 'deliveryTime' => $deliveryTime, 'data' => [ 'content' => $content, ], @@ -1789,6 +1790,7 @@ App::post('/v1/messaging/messages/push') 'providerInternalId' => $provider->getInternalId(), 'to' => $to, 'description' => $description, + 'deliveryTime' => $deliveryTime, 'data' => $pushData, 'status' => $status, 'search' => $messageId . ' ' . $description . ' ' . $title . ' ' . $providerId, @@ -1945,6 +1947,10 @@ App::patch('/v1/messaging/messages/email/:messageId') $message->setAttribute('status', $status); } + if (!is_null($deliveryTime)) { + $message->setAttribute('deliveryTime', $deliveryTime); + } + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { @@ -2024,6 +2030,10 @@ App::patch('/v1/messaging/messages/sms/:messageId') $message->setAttribute('description', $description); } + if (!is_null($deliveryTime)) { + $message->setAttribute('deliveryTime', $deliveryTime); + } + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { @@ -2142,6 +2152,9 @@ App::patch('/v1/messaging/messages/push/:messageId') $message->setAttribute('description', $description); } + if (!is_null($deliveryTime)) { + $message->setAttribute('deliveryTime', $deliveryTime); + } $message = $dbForProject->updateDocument('messages', $message->getId(), $message); diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index b4ed8311df..5b374e97b1 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -372,7 +372,6 @@ trait MessagingBase public function testSendEmail() { - $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); @@ -484,7 +483,6 @@ trait MessagingBase */ public function testUpdateEmail(array $email) { - $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); @@ -611,7 +609,6 @@ trait MessagingBase public function testSendSMS() { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); @@ -720,7 +717,6 @@ trait MessagingBase */ public function testUpdateSMS(array $sms) { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); @@ -844,7 +840,6 @@ trait MessagingBase public function testSendPushNotification() { - $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); if (empty($to) || empty($serverKey)) { @@ -950,7 +945,6 @@ trait MessagingBase */ public function testUpdatePushNotification(array $push) { - $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); if (empty($to) || empty($serverKey)) { From 24b2d7044178ba085d511ebbcf45c39b2ccf9215 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 20 Oct 2023 13:33:27 +0530 Subject: [PATCH 127/196] review changes --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 8e79912566..58490baef7 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1972,7 +1972,7 @@ App::patch('/v1/messaging/messages/email/:messageId') }); App::patch('/v1/messaging/messages/sms/:messageId') - ->desc('Update an sms.') + ->desc('Update an SMS.') ->groups(['api', 'messaging']) ->label('audits.event', 'messages.update') ->label('audits.resource', 'messages/{response.$id}') From d714760eb807c15ee64a8e284a63964b8abb2e7e Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 20 Oct 2023 13:51:13 +0530 Subject: [PATCH 128/196] review changeS --- app/controllers/api/messaging.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 58490baef7..2f2deabdd7 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1914,7 +1914,7 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + if (!is_null($message->getAttribute('deliveryTime')) && $message->getAttribute('deliveryTime') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } @@ -2005,7 +2005,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + if (!is_null($message->getAttribute('deliveryTime')) && $message->getAttribute('deliveryTime') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } @@ -2095,7 +2095,7 @@ App::patch('/v1/messaging/messages/push/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + if (!is_null($message->getAttribute('deliveryTime')) && $message->getAttribute('deliveryTime') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } From e040ecba36007436dfd437d345eb1f8da0ee1c37 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 20 Oct 2023 15:03:56 +0530 Subject: [PATCH 129/196] fixed lint error --- app/init.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/init.php b/app/init.php index 64a5897f3e..cfbbe6f43f 100644 --- a/app/init.php +++ b/app/init.php @@ -1,7 +1,5 @@ Date: Fri, 20 Oct 2023 17:02:13 +0530 Subject: [PATCH 130/196] review changes --- app/controllers/api/messaging.php | 17 ++++++++++------- app/controllers/api/users.php | 13 +++---------- app/worker.php | 1 - src/Appwrite/Platform/Workers/Messaging.php | 14 ++++++-------- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 1e30d41b1a..3bf7561a49 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1367,9 +1367,9 @@ App::delete('/v1/messaging/topics/:topicId') ->label('sdk.response.model', Response::MODEL_NONE) ->param('topicId', '', new UID(), 'Topic ID.') ->inject('dbForProject') - ->inject('deletes') + ->inject('queueForDeletes') ->inject('response') - ->action(function (string $topicId, Database $dbForProject, Delete $deletes, Response $response) { + ->action(function (string $topicId, Database $dbForProject, Delete $queueForDeletes, Response $response) { $topic = $dbForProject->getDocument('topics', $topicId); if ($topic->isEmpty()) { @@ -1378,7 +1378,7 @@ App::delete('/v1/messaging/topics/:topicId') $dbForProject->deleteDocument('topics', $topicId); - $deletes + $queueForDeletes ->setType(DELETE_TYPE_SUBSCRIBERS) ->setDocument($topic); @@ -1589,7 +1589,7 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $subject, string $content, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); @@ -1916,12 +1916,13 @@ App::patch('/v1/messaging/messages/email/:messageId') } $message->setAttribute('data', $data); - $message->setAttribute('search', $message->getId() . ' ' . $data['description'] . ' ' . $data['subject'] . ' ' . $message->getAttribute('providerId')); if (!empty($description)) { $message->setAttribute('description', $description); } + $message->setAttribute('search', $message->getId() . ' ' . $message->getAttribute('description') . ' ' . $data['subject'] . ' ' . $message->getAttribute('providerId')); + if (!empty($status)) { $message->setAttribute('status', $status); } @@ -1992,7 +1993,6 @@ App::patch('/v1/messaging/messages/sms/:messageId') } $message->setAttribute('data', $data); - $message->setAttribute('search', $message->getId() . ' ' . $data['description'] . ' ' . $message->getAttribute('providerId')); if (!empty($status)) { $message->setAttribute('status', $status); @@ -2006,6 +2006,8 @@ App::patch('/v1/messaging/messages/sms/:messageId') $message->setAttribute('deliveryTime', $deliveryTime); } + $message->setAttribute('search', $message->getId() . ' ' . $message->getAttribute('description') . ' ' . $message->getAttribute('providerId')); + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { @@ -2107,7 +2109,6 @@ App::patch('/v1/messaging/messages/push/:messageId') } $message->setAttribute('data', $pushData); - $message->setAttribute('search', $message->getId() . ' ' . $pushData['description'] . ' ' . $pushData['title'] . ' ' . $message->getAttribute('providerId')); if (!empty($status)) { $message->setAttribute('status', $status); @@ -2121,6 +2122,8 @@ App::patch('/v1/messaging/messages/push/:messageId') $message->setAttribute('deliveryTime', $deliveryTime); } + $message->setAttribute('search', $message->getId() . ' ' . $message->getAttribute('description') . ' ' . $pushData['title'] . ' ' . $message->getAttribute('providerId')); + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index c03f00cc6a..ac545ba329 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -398,8 +398,7 @@ App::post('/v1/users/:userId/targets') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') ->inject('response') ->inject('dbForProject') - ->inject('events') - ->action(function (string $userId, string $targetId, string $providerId, string $identifier, Response $response, Database $dbForProject, Event $events) { + ->action(function (string $userId, string $targetId, string $providerId, string $identifier, Response $response, Database $dbForProject) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1217,8 +1216,7 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') ->inject('response') ->inject('dbForProject') - ->inject('events') - ->action(function (string $userId, string $targetId, string $identifier, Response $response, Database $dbForProject, Event $events) { + ->action(function (string $userId, string $targetId, string $identifier, Response $response, Database $dbForProject) { $user = $dbForProject->getDocument('users', $userId); @@ -1241,10 +1239,6 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') $target = $dbForProject->updateDocument('targets', $target->getId(), $target); $dbForProject->deleteCachedDocument('users', $user->getId()); - $events - ->setParam('userId', $userId) - ->setParam('targetId', $targetId); - $response ->dynamic($target, Response::MODEL_TARGET); }); @@ -1396,8 +1390,7 @@ App::delete('/v1/users/:userId/targets/:targetId') ->param('targetId', '', new UID(), 'Target ID.') ->inject('response') ->inject('dbForProject') - ->inject('events') - ->action(function (string $userId, string $targetId, Response $response, Database $dbForProject, Event $events) { + ->action(function (string $userId, string $targetId, Response $response, Database $dbForProject) { $user = $dbForProject->getDocument('users', $userId); diff --git a/app/worker.php b/app/worker.php index 1514688b14..886c8f6d33 100644 --- a/app/worker.php +++ b/app/worker.php @@ -12,7 +12,6 @@ use Appwrite\Event\Func; use Appwrite\Event\Mail; use Appwrite\Event\Messaging; use Appwrite\Event\Migration; -use Appwrite\Event\Phone; use Appwrite\Platform\Appwrite; use Appwrite\Usage\Stats; use Swoole\Runtime; diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 372ef691d9..d87fb05532 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -29,8 +29,6 @@ use Utopia\Messaging\Messages\SMS; use function Swoole\Coroutine\batch; -require_once __DIR__ . '/../init.php'; - class Messaging extends Action { protected ?SMSAdapter $sms = null; @@ -78,10 +76,10 @@ class Messaging extends Action $provider = $dbForProject->getDocument('providers', $message->getAttribute('providerId')); - $this->processMessage($message, $provider); + $this->processMessage($dbForProject, $message, $provider); } - private function processMessage(Document $message, Document $provider): void + private function processMessage(Database $dbForProject, Document $message, Document $provider): void { $adapter = match ($provider->getAttribute('type')) { 'sms' => $this->sms($provider), @@ -97,17 +95,17 @@ class Messaging extends Action */ $recipients = []; - $topics = $this->dbForProject->find('topics', [Query::equal('$id', $recipientsId)]); + $topics = $dbForProject->find('topics', [Query::equal('$id', $recipientsId)]); foreach ($topics as $topic) { $recipients = \array_merge($recipients, $topic->getAttribute('targets')); } - $users = $this->dbForProject->find('users', [Query::equal('$id', $recipientsId)]); + $users = $dbForProject->find('users', [Query::equal('$id', $recipientsId)]); foreach ($users as $user) { $recipients = \array_merge($recipients, $user->getAttribute('targets')); } - $targets = $this->dbForProject->find('targets', [Query::equal('$id', $recipientsId)]); + $targets = $dbForProject->find('targets', [Query::equal('$id', $recipientsId)]); $recipients = \array_merge($recipients, $targets); $recipients = \array_filter($recipients, function (Document $recipient) use ($provider) { return $recipient->getAttribute('providerId') === $provider->getId(); @@ -165,7 +163,7 @@ class Messaging extends Action $message->setAttribute('deliveredTo', $deliveredTo); $message->setAttribute('deliveredAt', DateTime::now()); - $this->dbForProject->updateDocument('messages', $message->getId(), $message); + $dbForProject->updateDocument('messages', $message->getId(), $message); } public function shutdown(): void From b60cbcada5324acd4030791564ffb06ac5607dd8 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 24 Oct 2023 01:05:46 +0530 Subject: [PATCH 131/196] adds from field in remaining providers --- app/controllers/api/messaging.php | 103 ++++++++++++++---- tests/e2e/Services/GraphQL/MessagingTest.php | 5 + .../e2e/Services/Messaging/MessagingBase.php | 5 + 3 files changed, 92 insertions(+), 21 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 3bf7561a49..f6d68117da 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -106,12 +106,13 @@ App::post('/v1/messaging/providers/sendgrid') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') + ->param('from', '', new Text(256), 'Sender Email Address.') + ->param('apiKey', '', new Text(0), 'Sendgrid API key.') ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('apiKey', '', new Text(0), 'Sendgrid API key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, bool $default, bool $enabled, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -120,11 +121,13 @@ App::post('/v1/messaging/providers/sendgrid') 'type' => 'email', 'default' => $default, 'enabled' => $enabled, - 'options' => [], 'search' => $providerId . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email', 'credentials' => [ 'apiKey' => $apiKey, ], + 'options' => [ + 'from' => $from, + ] ]); // Check if a default provider exists, if not, set this one as default @@ -225,13 +228,14 @@ App::post('/v1/messaging/providers/telesign') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Text(256), 'Sender Number.') ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $username, string $password, bool $default, bool $enabled, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -245,6 +249,9 @@ App::post('/v1/messaging/providers/telesign') 'username' => $username, 'password' => $password, ], + 'options' => [ + 'from' => $from, + ] ]); // Check if a default provider exists, if not, set this one as default @@ -283,13 +290,14 @@ App::post('/v1/messaging/providers/textmagic') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Text(256), 'Sender Number.') ->param('username', '', new Text(0), 'Textmagic username.') ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $username, string $apiKey, bool $default, bool $enabled, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -303,6 +311,9 @@ App::post('/v1/messaging/providers/textmagic') 'username' => $username, 'apiKey' => $apiKey, ], + 'options' => [ + 'from' => $from, + ] ]); // Check if a default provider exists, if not, set this one as default @@ -341,13 +352,14 @@ App::post('/v1/messaging/providers/twilio') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Text(256), 'Sender number.') ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $accountSid, string $authToken, bool $default, bool $enabled, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -361,6 +373,9 @@ App::post('/v1/messaging/providers/twilio') 'accountSid' => $accountSid, 'authToken' => $authToken, ], + 'options' => [ + 'from' => $from, + ] ]); // Check if a default provider exists, if not, set this one as default @@ -399,13 +414,14 @@ App::post('/v1/messaging/providers/vonage') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Text(256), 'Sender number.') ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, string $apiSecret, bool $default, bool $enabled, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -419,6 +435,9 @@ App::post('/v1/messaging/providers/vonage') 'apiKey' => $apiKey, 'apiSecret' => $apiSecret, ], + 'options' => [ + 'from' => $from, + ] ]); // Check if a default provider exists, if not, set this one as default @@ -713,9 +732,10 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) + ->param('from', '', new Text(256), 'Sender Email Address.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -732,6 +752,12 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email'); } + if (!empty($from)) { + $provider->setAttribute('options', [ + 'from' => $from, + ]); + } + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -766,9 +792,10 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) + ->param('from', '', new Text(256), 'Sender Number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $senderId, string $authKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $senderId, string $authKey, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -785,6 +812,12 @@ App::patch('/v1/messaging/providers/msg91/:providerId') $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms'); } + if (!empty($from)) { + $provider->setAttribute('options', [ + 'from' => $from, + ]); + } + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -825,9 +858,10 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Telesign username.', true) ->param('password', '', new Text(0), 'Telesign password.', true) + ->param('from', '', new Text(256), 'Sender Number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $password, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -844,6 +878,12 @@ App::patch('/v1/messaging/providers/telesign/:providerId') $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms'); } + if (!empty($from)) { + $provider->setAttribute('options', [ + 'from' => $from, + ]); + } + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -884,9 +924,10 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) + ->param('from', '', new Text(256), 'Sender Number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $apiKey, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -903,6 +944,12 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'textmagic' . ' ' . 'sms'); } + if (!empty($from)) { + $provider->setAttribute('options', [ + 'from' => $from, + ]); + } + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -943,9 +990,10 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) + ->param('from', '', new Text(256), 'Sender Number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $accountSid, string $authToken, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -962,6 +1010,12 @@ App::patch('/v1/messaging/providers/twilio/:providerId') $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms'); } + if (!empty($from)) { + $provider->setAttribute('options', [ + 'from' => $from, + ]); + } + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } @@ -1002,9 +1056,10 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) + ->param('from', '', new Text(256), 'Sender Number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $apiSecret, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1021,6 +1076,12 @@ App::patch('/v1/messaging/providers/vonage/:providerId') $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms'); } + if (!empty($from)) { + $provider->setAttribute('options', [ + 'from' => $from, + ]); + } + if ($enabled === true || $enabled === false) { $provider->setAttribute('enabled', $enabled); } diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index ec8f4b0a6a..68dcda49ec 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -22,6 +22,7 @@ class MessagingTest extends Scope 'providerId' => ID::unique(), 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', + 'from' => 'sender-email@my-domain', ], 'Mailgun' => [ 'providerId' => ID::unique(), @@ -35,18 +36,21 @@ class MessagingTest extends Scope 'name' => 'Twilio1', 'accountSid' => 'my-accountSid', 'authToken' => 'my-authToken', + 'from' => '+123456789', ], 'Telesign' => [ 'providerId' => ID::unique(), 'name' => 'Telesign1', 'username' => 'my-username', 'password' => 'my-password', + 'from' => '+123456789', ], 'Textmagic' => [ 'providerId' => ID::unique(), 'name' => 'Textmagic1', 'username' => 'my-username', 'apiKey' => 'my-apikey', + 'from' => '+123456789', ], 'Msg91' => [ 'providerId' => ID::unique(), @@ -60,6 +64,7 @@ class MessagingTest extends Scope 'name' => 'Vonage1', 'apiKey' => 'my-apikey', 'apiSecret' => 'my-apisecret', + 'from' => '+123456789', ], 'Fcm' => [ 'providerId' => ID::unique(), diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 5b374e97b1..3e686d4f65 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -15,6 +15,7 @@ trait MessagingBase 'providerId' => ID::unique(), 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', + 'from' => 'sender-email@my-domain', ], 'mailgun' => [ 'providerId' => ID::unique(), @@ -28,18 +29,21 @@ trait MessagingBase 'name' => 'Twilio1', 'accountSid' => 'my-accountSid', 'authToken' => 'my-authToken', + 'from' => '+123456789', ], 'telesign' => [ 'providerId' => ID::unique(), 'name' => 'Telesign1', 'username' => 'my-username', 'password' => 'my-password', + 'from' => '+123456789', ], 'textmagic' => [ 'providerId' => ID::unique(), 'name' => 'Textmagic1', 'username' => 'my-username', 'apiKey' => 'my-apikey', + 'from' => '+123456789', ], 'msg91' => [ 'providerId' => ID::unique(), @@ -53,6 +57,7 @@ trait MessagingBase 'name' => 'Vonage1', 'apiKey' => 'my-apikey', 'apiSecret' => 'my-apisecret', + 'from' => '+123456789', ], 'fcm' => [ 'providerId' => ID::unique(), From 2435f722ca8bdcd3e76d9091193e7a4cb3fa6477 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 25 Oct 2023 21:45:55 +0530 Subject: [PATCH 132/196] fixes test cases --- composer.lock | 14 ++++++------- tests/e2e/Services/GraphQL/Base.php | 20 +++++++++---------- tests/e2e/Services/GraphQL/MessagingTest.php | 1 + .../e2e/Services/Messaging/MessagingBase.php | 1 + 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/composer.lock b/composer.lock index 08a5812099..7212a951a4 100644 --- a/composer.lock +++ b/composer.lock @@ -1906,16 +1906,16 @@ }, { "name": "utopia-php/database", - "version": "0.44.2", + "version": "0.44.3", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "591cadbc2c622a3304aae9a16ebfdbe75ef33a06" + "reference": "b2d403c25a77506e03db5736335b0cae52bcc18a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/591cadbc2c622a3304aae9a16ebfdbe75ef33a06", - "reference": "591cadbc2c622a3304aae9a16ebfdbe75ef33a06", + "url": "https://api.github.com/repos/utopia-php/database/zipball/b2d403c25a77506e03db5736335b0cae52bcc18a", + "reference": "b2d403c25a77506e03db5736335b0cae52bcc18a", "shasum": "" }, "require": { @@ -1928,7 +1928,7 @@ }, "require-dev": { "fakerphp/faker": "^1.14", - "laravel/pint": "1.4.*", + "laravel/pint": "1.13.*", "pcov/clobber": "^2.0", "phpstan/phpstan": "1.10.*", "phpunit/phpunit": "^9.4", @@ -1956,9 +1956,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.44.2" + "source": "https://github.com/utopia-php/database/tree/0.44.3" }, - "time": "2023-10-19T07:39:00+00:00" + "time": "2023-10-24T10:13:48+00:00" }, { "name": "utopia-php/domains", diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 9cd4fe0629..abad045120 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1795,8 +1795,8 @@ trait Base } }'; case self::$CREATE_SENDGRID_PROVIDER: - return 'mutation createSendgridProvider($providerId: String!, $name: String!, $apiKey: String!) { - messagingCreateSendgridProvider(providerId: $providerId, name: $name, apiKey: $apiKey) { + return 'mutation createSendgridProvider($providerId: String!, $name: String!, $from: String!, $apiKey: String!) { + messagingCreateSendgridProvider(providerId: $providerId, name: $name, from: $from, apiKey: $apiKey) { _id name provider @@ -1806,8 +1806,8 @@ trait Base } }'; case self::$CREATE_TWILIO_PROVIDER: - return 'mutation createTwilioProvider($providerId: String!, $name: String!, $accountSid: String!, $authToken: String!) { - messagingCreateTwilioProvider(providerId: $providerId, name: $name, accountSid: $accountSid, authToken: $authToken) { + return 'mutation createTwilioProvider($providerId: String!, $name: String!, $from: String!, $accountSid: String!, $authToken: String!) { + messagingCreateTwilioProvider(providerId: $providerId, name: $name, from: $from, accountSid: $accountSid, authToken: $authToken) { _id name provider @@ -1817,8 +1817,8 @@ trait Base } }'; case self::$CREATE_TELESIGN_PROVIDER: - return 'mutation createTelesignProvider($providerId: String!, $name: String!, $username: String!, $password: String!) { - messagingCreateTelesignProvider(providerId: $providerId, name: $name, username: $username, password: $password) { + return 'mutation createTelesignProvider($providerId: String!, $name: String!, $from: String!, $username: String!, $password: String!) { + messagingCreateTelesignProvider(providerId: $providerId, name: $name, from: $from, username: $username, password: $password) { _id name provider @@ -1828,8 +1828,8 @@ trait Base } }'; case self::$CREATE_TEXTMAGIC_PROVIDER: - return 'mutation createTextmagicProvider($providerId: String!, $name: String!, $username: String!, $apiKey: String!) { - messagingCreateTextmagicProvider(providerId: $providerId, name: $name, username: $username, apiKey: $apiKey) { + return 'mutation createTextmagicProvider($providerId: String!, $name: String!, $from: String!, $username: String!, $apiKey: String!) { + messagingCreateTextmagicProvider(providerId: $providerId, name: $name, from: $from, username: $username, apiKey: $apiKey) { _id name provider @@ -1850,8 +1850,8 @@ trait Base } }'; case self::$CREATE_VONAGE_PROVIDER: - return 'mutation createVonageProvider($providerId: String!, $name: String!, $apiKey: String!, $apiSecret: String!) { - messagingCreateVonageProvider(providerId: $providerId, name: $name, apiKey: $apiKey, apiSecret: $apiSecret) { + return 'mutation createVonageProvider($providerId: String!, $name: String!, $from: String!, $apiKey: String!, $apiSecret: String!) { + messagingCreateVonageProvider(providerId: $providerId, name: $name, from: $from, apiKey: $apiKey, apiSecret: $apiSecret) { _id name provider diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 68dcda49ec..171b6b1b89 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -271,6 +271,7 @@ class MessagingTest extends Scope 'providerId' => ID::unique(), 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', + 'from' => 'sender-email@my-domain', ] ]; $query = $this->getQuery(self::$CREATE_SENDGRID_PROVIDER); diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 3e686d4f65..164608224b 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -225,6 +225,7 @@ trait MessagingBase 'providerId' => 'unique()', 'name' => 'Sendgrid1', 'apiKey' => 'my-apikey', + 'from' => 'sender-email@my-domain', ]); $this->assertEquals(201, $provider['headers']['status-code']); $response = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ From fd4a81c4fc3fe7288d93080e39a2a7eb2a5fa3f8 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 25 Oct 2023 23:03:23 +0530 Subject: [PATCH 133/196] made review changes --- app/config/collections.php | 4 +- app/config/events.php | 33 ++-- app/controllers/api/account.php | 26 +-- app/controllers/api/avatars.php | 4 +- app/controllers/api/messaging.php | 178 +++++++++--------- app/controllers/api/projects.php | 8 +- app/controllers/api/teams.php | 5 +- app/controllers/api/users.php | 8 +- app/init.php | 9 +- docs/tutorials/add-oauth2-provider.md | 6 +- src/Appwrite/Migration/Version/V15.php | 2 +- src/Appwrite/Migration/Version/V16.php | 12 +- src/Appwrite/Platform/Workers/Deletes.php | 40 +++- src/Appwrite/Platform/Workers/Messaging.php | 7 - .../Database/Validator/Queries/Messages.php | 3 +- src/Appwrite/Utopia/Response/Filters/V13.php | 4 +- src/Appwrite/Utopia/Response/Filters/V16.php | 6 +- .../Utopia/Response/Model/Project.php | 10 +- .../Projects/ProjectsConsoleClientTest.php | 6 +- .../unit/Utopia/Response/Filters/V16Test.php | 6 +- 20 files changed, 201 insertions(+), 176 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index bf2dd07975..8f4edef99f 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -5,7 +5,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Helpers\ID; -$providers = Config::getParam('authProviders', []); +$providers = Config::getParam('oAuthProviders', []); $auth = Config::getParam('auth', []); /** @@ -4008,7 +4008,7 @@ $consoleCollections = array_merge([ 'filters' => ['json'], ], [ - '$id' => ID::custom('authProviders'), + '$id' => ID::custom('oAuthProviders'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => 16384, diff --git a/app/config/events.php b/app/config/events.php index b07d356470..8a89402184 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -261,29 +261,28 @@ return [ 'update' => [ '$description' => 'This event triggers when a message is updated.', ], - 'topics' => [ - '$model' => Response::MODEL_TOPIC, + ], + 'topics' => [ + '$model' => Response::MODEL_TOPIC, + '$resource' => true, + '$description' => 'This event triggers on any topic event.', + 'create' => [ + '$description' => 'This event triggers when a provider is created.', + ], + 'delete' => [ + '$description' => 'This event triggers when a provider is deleted.' + ], + 'subscribers' => [ + '$model' => Response::MODEL_SUBSCRIBER, '$resource' => true, - '$description' => 'This event triggers on any topic event.', + '$description' => 'This event triggers on any subscriber event.', 'create' => [ - '$description' => 'This event triggers when a provider is created.', + '$description' => 'This event triggers when a subscriber is created.', ], 'delete' => [ - '$description' => 'This event triggers when a provider is deleted.' - ], - 'subscribers' => [ - '$model' => Response::MODEL_SUBSCRIBER, - '$resource' => true, - '$description' => 'This event triggers on any subscriber event.', - 'create' => [ - '$description' => 'This event triggers when a subscriber is created.', - ], - 'delete' => [ - '$description' => 'This event triggers when a subscriber is deleted.' - ], + '$description' => 'This event triggers when a subscriber is deleted.' ], ], - ], 'providers' => [ '$model' => Response::MODEL_PROVIDER, diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 175c239b8e..f119d33414 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -299,7 +299,7 @@ App::get('/v1/account/sessions/oauth2/:provider') ->label('sdk.methodType', 'webAuth') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('authProviders'), fn($node) => (!$node['mock'])))) . '.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn($node) => (!$node['mock'])))) . '.') ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s 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']) ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s 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']) ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) @@ -311,14 +311,14 @@ App::get('/v1/account/sessions/oauth2/:provider') $protocol = $request->getProtocol(); $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); - $providerEnabled = $project->getAttribute('authProviders', [])[$provider . 'Enabled'] ?? false; + $providerEnabled = $project->getAttribute('oAuthProviders', [])[$provider . 'Enabled'] ?? false; if (!$providerEnabled) { throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your ' . APP_NAME . ' console to continue.'); } - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}'; if (!empty($appSecret) && isset($appSecret['version'])) { $key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']); @@ -358,7 +358,7 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->label('scope', 'public') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 provider.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) ->param('state', '', new Text(2048), 'Login state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) @@ -391,7 +391,7 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->label('origin', '*') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 provider.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) ->param('state', '', new Text(2048), 'Login state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) @@ -430,7 +430,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('docs', false) ->label('usage.metric', 'sessions.{scope}.requests.create') ->label('usage.params', ['provider:{request.provider}']) - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 provider.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) ->param('state', '', new Text(2048), 'OAuth2 state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) @@ -448,9 +448,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); $defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => '']; $validateURL = new URL(); - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; - $providerEnabled = $project->getAttribute('authProviders', [])[$provider . 'Enabled'] ?? false; + $appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}'; + $providerEnabled = $project->getAttribute('oAuthProviders', [])[$provider . 'Enabled'] ?? false; $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); @@ -458,7 +458,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } - $providers = Config::getParam('authProviders'); + $providers = Config::getParam('oAuthProviders'); $providerName = $providers[$provider]['name'] ?? ''; /** @var Appwrite\Auth\OAuth2 $oauth2 */ @@ -2296,8 +2296,8 @@ App::patch('/v1/account/sessions/:sessionId') $provider = $session->getAttribute('provider'); $refreshToken = $session->getAttribute('providerRefreshToken'); - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}'; $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index e0d967eb00..b6395774e9 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -84,8 +84,8 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro $accessTokenExpiry = $gitHubSession->getAttribute('providerAccessTokenExpiry'); $refreshToken = $gitHubSession->getAttribute('providerRefreshToken'); - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}'; $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 3bf7561a49..20989da623 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -3,6 +3,7 @@ use Appwrite\Event\Delete; use Appwrite\Event\Messaging; use Appwrite\Extend\Exception; +use Appwrite\Network\Validator\Email; use Appwrite\Permission; use Appwrite\Role; use Appwrite\Utopia\Database\Validator\CustomId; @@ -27,9 +28,9 @@ use Utopia\Validator\Text; use Utopia\Validator\WhiteList; App::post('/v1/messaging/providers/mailgun') - ->desc('Create Mailgun Provider') + ->desc('Create Mailgun provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -41,15 +42,14 @@ App::post('/v1/messaging/providers/mailgun') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('isEuRegion', false, new Boolean(), 'Set as EU region.', true) - ->param('from', '', new Text(256), 'Sender Email Address.') + ->param('from', '', new Email(), 'Sender Email Address.') ->param('apiKey', '', new Text(0), 'Mailgun API Key.') ->param('domain', '', new Text(0), 'Mailgun Domain.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ @@ -57,7 +57,6 @@ App::post('/v1/messaging/providers/mailgun') 'name' => $name, 'provider' => 'mailgun', 'type' => 'email', - 'default' => $default, 'enabled' => $enabled, 'search' => $providerId . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email', 'credentials' => [ @@ -92,9 +91,9 @@ App::post('/v1/messaging/providers/mailgun') }); App::post('/v1/messaging/providers/sendgrid') - ->desc('Create Sendgrid Provider') + ->desc('Create Sendgrid provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -106,19 +105,17 @@ App::post('/v1/messaging/providers/sendgrid') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'sendgrid', 'type' => 'email', - 'default' => $default, 'enabled' => $enabled, 'options' => [], 'search' => $providerId . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email', @@ -149,9 +146,9 @@ App::post('/v1/messaging/providers/sendgrid') }); App::post('/v1/messaging/providers/msg91') - ->desc('Create Msg91 Provider') + ->desc('Create Msg91 provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -163,14 +160,13 @@ App::post('/v1/messaging/providers/msg91') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('from', '', new Text(256), 'Sender Number.') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $from, string $senderId, string $authKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $from, string $senderId, string $authKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -178,7 +174,6 @@ App::post('/v1/messaging/providers/msg91') 'provider' => 'msg91', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'senderId' => $senderId, @@ -211,9 +206,9 @@ App::post('/v1/messaging/providers/msg91') }); App::post('/v1/messaging/providers/telesign') - ->desc('Create Telesign Provider') + ->desc('Create Telesign provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -225,13 +220,12 @@ App::post('/v1/messaging/providers/telesign') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -239,7 +233,6 @@ App::post('/v1/messaging/providers/telesign') 'provider' => 'telesign', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'username' => $username, @@ -269,27 +262,26 @@ App::post('/v1/messaging/providers/telesign') }); App::post('/v1/messaging/providers/textmagic') - ->desc('Create Textmagic Provider') + ->desc('Create TextMagic provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createTextmagicProvider') + ->label('sdk.method', 'createTextMagicProvider') ->label('sdk.description', '/docs/references/messaging/create-textmagic-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('username', '', new Text(0), 'Textmagic username.') - ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') + ->param('username', '', new Text(0), 'TextMagic username.') + ->param('apiKey', '', new Text(0), 'TextMagic apiKey.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -297,7 +289,6 @@ App::post('/v1/messaging/providers/textmagic') 'provider' => 'text-magic', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'text-magic' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'username' => $username, @@ -327,9 +318,9 @@ App::post('/v1/messaging/providers/textmagic') }); App::post('/v1/messaging/providers/twilio') - ->desc('Create Twilio Provider') + ->desc('Create Twilio provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -341,13 +332,12 @@ App::post('/v1/messaging/providers/twilio') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -355,7 +345,6 @@ App::post('/v1/messaging/providers/twilio') 'provider' => 'twilio', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'accountSid' => $accountSid, @@ -385,9 +374,9 @@ App::post('/v1/messaging/providers/twilio') }); App::post('/v1/messaging/providers/vonage') - ->desc('Create Vonage Provider') + ->desc('Create Vonage provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -399,13 +388,12 @@ App::post('/v1/messaging/providers/vonage') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -413,7 +401,6 @@ App::post('/v1/messaging/providers/vonage') 'provider' => 'vonage', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'apiKey' => $apiKey, @@ -443,9 +430,9 @@ App::post('/v1/messaging/providers/vonage') }); App::post('/v1/messaging/providers/fcm') - ->desc('Create FCM Provider') + ->desc('Create FCM provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -457,9 +444,8 @@ App::post('/v1/messaging/providers/fcm') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('serverKey', '', new Text(0), 'FCM Server Key.') + ->param('serverKey', '', new Text(0), 'FCM server key.') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { @@ -470,7 +456,6 @@ App::post('/v1/messaging/providers/fcm') 'provider' => 'fcm', 'type' => 'push', 'search' => $providerId . ' ' . $name . ' ' . 'fcm' . ' ' . 'push', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'serverKey' => $serverKey, @@ -499,9 +484,9 @@ App::post('/v1/messaging/providers/fcm') }); App::post('/v1/messaging/providers/apns') - ->desc('Create APNS Provider') + ->desc('Create APNS provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -513,7 +498,6 @@ App::post('/v1/messaging/providers/apns') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('authKey', '', new Text(0), 'APNS authentication key.') ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') @@ -530,7 +514,6 @@ App::post('/v1/messaging/providers/apns') 'provider' => 'apns', 'type' => 'push', 'search' => $providerId . ' ' . $name . ' ' . 'apns' . ' ' . 'push', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'authKey' => $authKey, @@ -563,7 +546,7 @@ App::post('/v1/messaging/providers/apns') }); App::get('/v1/messaging/providers') - ->desc('List Providers') + ->desc('List providers') ->groups(['api', 'messaging']) ->label('scope', 'providers.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -574,11 +557,16 @@ App::get('/v1/messaging/providers') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER_LIST) ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') ->inject('response') ->action(function (array $queries, Database $dbForProject, Response $response) { $queries = Query::parseQueries($queries); + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + // Get cursor document if there was a cursor query $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); $cursor = reset($cursor); @@ -594,15 +582,14 @@ App::get('/v1/messaging/providers') $cursor->setValue($cursorDocument); } - $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ - 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), 'providers' => $dbForProject->find('providers', $queries), + 'total' => $dbForProject->count('providers', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_PROVIDER_LIST); }); App::get('/v1/messaging/providers/:providerId') - ->desc('Get Provider') + ->desc('Get provider') ->groups(['api', 'messaging']) ->label('scope', 'providers.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -626,9 +613,9 @@ App::get('/v1/messaging/providers/:providerId') }); App::patch('/v1/messaging/providers/mailgun/:providerId') - ->desc('Update Mailgun Provider') + ->desc('Update Mailgun provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -697,9 +684,9 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') }); App::patch('/v1/messaging/providers/sendgrid/:providerId') - ->desc('Update Sendgrid Provider') + ->desc('Update Sendgrid provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -749,9 +736,9 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') }); App::patch('/v1/messaging/providers/msg91/:providerId') - ->desc('Update Msg91 Provider') + ->desc('Update Msg91 provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -808,9 +795,9 @@ App::patch('/v1/messaging/providers/msg91/:providerId') }); App::patch('/v1/messaging/providers/telesign/:providerId') - ->desc('Update Telesign Provider') + ->desc('Update Telesign provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -867,14 +854,14 @@ App::patch('/v1/messaging/providers/telesign/:providerId') }); App::patch('/v1/messaging/providers/textmagic/:providerId') - ->desc('Update Textmagic Provider') + ->desc('Update TextMagic provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateTextmagicProvider') + ->label('sdk.method', 'updateTextMagicProvider') ->label('sdk.description', '/docs/references/messaging/update-textmagic-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -882,8 +869,8 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('username', '', new Text(0), 'Textmagic username.', true) - ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) + ->param('username', '', new Text(0), 'TextMagic username.', true) + ->param('apiKey', '', new Text(0), 'TextMagic apiKey.', true) ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { @@ -926,9 +913,9 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') }); App::patch('/v1/messaging/providers/twilio/:providerId') - ->desc('Update Twilio Provider') + ->desc('Update Twilio provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -985,9 +972,9 @@ App::patch('/v1/messaging/providers/twilio/:providerId') }); App::patch('/v1/messaging/providers/vonage/:providerId') - ->desc('Update Vonage Provider') + ->desc('Update Vonage provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1044,9 +1031,9 @@ App::patch('/v1/messaging/providers/vonage/:providerId') }); App::patch('/v1/messaging/providers/fcm/:providerId') - ->desc('Update FCM Provider') + ->desc('Update FCM provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1095,9 +1082,9 @@ App::patch('/v1/messaging/providers/fcm/:providerId') App::patch('/v1/messaging/providers/apns/:providerId') - ->desc('Update APNS Provider') + ->desc('Update APNS provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1169,7 +1156,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') }); App::delete('/v1/messaging/providers/:providerId') - ->desc('Delete Provider') + ->desc('Delete provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.delete') ->label('audits.resource', 'providers/{request.id}') @@ -1182,15 +1169,20 @@ App::delete('/v1/messaging/providers/:providerId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) ->param('providerId', '', new UID(), 'Provider ID.') + ->inject('queueForDeletes') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, Database $dbForProject, Response $response) { + ->action(function (string $providerId, Delete $queueForDeletes, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } + $queueForDeletes + ->setType(DELETE_TYPE_PROVIDER) + ->setDocument($provider); + $dbForProject->deleteDocument('providers', $provider->getId()); $response @@ -1259,11 +1251,16 @@ App::get('/v1/messaging/topics') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TOPIC_LIST) ->param('queries', [], new Topics(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Topics::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') ->inject('response') - ->action(function (array $queries, Database $dbForProject, Response $response) { + ->action(function (array $queries, string $search, Database $dbForProject, Response $response) { $queries = Query::parseQueries($queries); + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + // Get cursor document if there was a cursor query $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); $cursor = reset($cursor); @@ -1279,10 +1276,9 @@ App::get('/v1/messaging/topics') $cursor->setValue($cursorDocument[0]); } - $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ - 'total' => $dbForProject->count('topics', $filterQueries, APP_LIMIT_COUNT), 'topics' => $dbForProject->find('topics', $queries), + 'total' => $dbForProject->count('topics', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_TOPIC_LIST); }); @@ -1379,7 +1375,7 @@ App::delete('/v1/messaging/topics/:topicId') $dbForProject->deleteDocument('topics', $topicId); $queueForDeletes - ->setType(DELETE_TYPE_SUBSCRIBERS) + ->setType(DELETE_TYPE_TOPIC) ->setDocument($topic); $response @@ -1388,7 +1384,7 @@ App::delete('/v1/messaging/topics/:topicId') }); App::post('/v1/messaging/topics/:topicId/subscribers') - ->desc('Adds a Subscriber to a Topic.') + ->desc('Adds a subscriber to a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'subscribers.create') ->label('audits.resource', 'subscribers/{response.$id}') @@ -1485,12 +1481,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $cursor->setValue($cursorDocument); } - $filterQueries = Query::groupByType($queries)['filters']; - $response ->dynamic(new Document([ 'subscribers' => $dbForProject->find('subscribers', $queries), - 'total' => $dbForProject->count('subscribers', $filterQueries, APP_LIMIT_COUNT), + 'total' => $dbForProject->count('subscribers', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_SUBSCRIBER_LIST); }); @@ -1527,7 +1521,7 @@ App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') }); App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') - ->desc('Delete a Subscriber from a Topic.') + ->desc('Delete a subscriber from a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'subscribers.delete') ->label('audits.resource', 'subscribers/{request.subscriberId}') @@ -1581,7 +1575,7 @@ App::post('/v1/messaging/messages/email') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(998), 'Email Subject.') ->param('content', '', new Text(64230), 'Email Content.') - ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('description', '', new Text(256), 'Description for message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) @@ -1795,7 +1789,7 @@ App::post('/v1/messaging/messages/push') }); App::get('/v1/messaging/messages') - ->desc('List Messages') + ->desc('List messages') ->groups(['api', 'messaging']) ->label('scope', 'messages.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1806,11 +1800,16 @@ App::get('/v1/messaging/messages') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE_LIST) ->param('queries', [], new Messages(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') ->inject('response') - ->action(function (array $queries, Database $dbForProject, Response $response) { + ->action(function (array $queries, string $search, Database $dbForProject, Response $response) { $queries = Query::parseQueries($queries); + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + // Get cursor document if there was a cursor query $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); $cursor = reset($cursor); @@ -1826,15 +1825,14 @@ App::get('/v1/messaging/messages') $cursor->setValue($cursorDocument); } - $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ - 'total' => $dbForProject->count('messages', $filterQueries, APP_LIMIT_COUNT), 'messages' => $dbForProject->find('messages', $queries), + 'total' => $dbForProject->count('messages', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_MESSAGE_LIST); }); App::get('/v1/messaging/messages/:messageId') - ->desc('Get Message') + ->desc('Get a message') ->groups(['api', 'messaging']) ->label('scope', 'messages.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index a5f3b76608..de9cc82b84 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -164,7 +164,7 @@ App::post('/v1/projects') 'legalTaxId' => ID::custom($legalTaxId), 'services' => new stdClass(), 'platforms' => null, - 'authProviders' => [], + 'oAuthProviders' => [], 'webhooks' => null, 'keys' => null, 'auths' => $auths, @@ -613,7 +613,7 @@ App::patch('/v1/projects/:projectId/oauth2') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'Provider Name') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'Provider Name') ->param('appId', null, new Text(256), 'Provider app ID. Max length: 256 chars.', true) ->param('secret', null, new text(512), 'Provider secret key. Max length: 512 chars.', true) ->param('enabled', null, new Boolean(), 'Provider status. Set to \'false\' to disable new session creation.', true) @@ -627,7 +627,7 @@ App::patch('/v1/projects/:projectId/oauth2') throw new Exception(Exception::PROJECT_NOT_FOUND); } - $providers = $project->getAttribute('authProviders', []); + $providers = $project->getAttribute('oAuthProviders', []); if ($appId !== null) { $providers[$provider . 'Appid'] = $appId; @@ -641,7 +641,7 @@ App::patch('/v1/projects/:projectId/oauth2') $providers[$provider . 'Enabled'] = $enabled; } - $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('authProviders', $providers)); + $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('oAuthProviders', $providers)); $response->dynamic($project, Response::MODEL_PROJECT); }); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index f600eb9aa5..da2261fd50 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -380,7 +380,6 @@ App::post('/v1/teams/:teamId/memberships') ->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('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', 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) - ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('response') ->inject('project') ->inject('user') @@ -389,7 +388,7 @@ App::post('/v1/teams/:teamId/memberships') ->inject('queueForMails') ->inject('queueForMessaging') ->inject('queueForEvents') - ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, string $from, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents) { + ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents) { $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -634,7 +633,7 @@ App::post('/v1/teams/:teamId/memberships') ; } elseif (!empty($phone)) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true, false]), + Query::equal('default', [true]), Query::equal('type', ['sms']) ])); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index ac545ba329..7c9253684e 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -382,7 +382,7 @@ App::post('/v1/users/scrypt-modified') App::post('/v1/users/:userId/targets') ->desc('Create User Target') ->groups(['api', 'users']) - ->label('audits.event', 'users.targets.create') + ->label('audits.event', 'target.create') ->label('audits.resource', 'target/response.$id') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) @@ -1201,7 +1201,7 @@ App::patch('/v1/users/:userId/prefs') App::patch('/v1/users/:userId/targets/:targetId/identifier') ->desc('Update user target\'s identifier') ->groups(['api', 'users']) - ->label('audits.event', 'users.targets.update') + ->label('audits.event', 'target.update') ->label('audits.resource', 'target/{response.$id}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) @@ -1376,7 +1376,7 @@ App::delete('/v1/users/:userId') App::delete('/v1/users/:userId/targets/:targetId') ->desc('Delete user target') ->groups(['api', 'users']) - ->label('audits.event', 'users.targets.delete') + ->label('audits.event', 'target.delete') ->label('audits.resource', 'target/{request.$targetId}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) @@ -1455,7 +1455,7 @@ App::get('/v1/users/usage') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_USAGE_USERS) ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true) - ->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('authProviders', [])))), true), 'Provider Name.', true) + ->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('oAuthProviders', [])))), true), 'Provider Name.', true) ->inject('response') ->inject('dbForProject') ->inject('register') diff --git a/app/init.php b/app/init.php index 2513d713f5..136ecd25cb 100644 --- a/app/init.php +++ b/app/init.php @@ -168,7 +168,8 @@ const DELETE_TYPE_SESSIONS = 'sessions'; const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp'; const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; const DELETE_TYPE_SCHEDULES = 'schedules'; -const DELETE_TYPE_SUBSCRIBERS = 'subscribers'; +const DELETE_TYPE_PROVIDER = 'provider'; +const DELETE_TYPE_TOPIC = 'topic'; // Compression type const COMPRESSION_TYPE_NONE = 'none'; const COMPRESSION_TYPE_GZIP = 'gzip'; @@ -233,7 +234,7 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION)); Config::load('events', __DIR__ . '/config/events.php'); Config::load('auth', __DIR__ . '/config/auth.php'); Config::load('errors', __DIR__ . '/config/errors.php'); -Config::load('authProviders', __DIR__ . '/config/authProviders.php'); +Config::load('oAuthProviders', __DIR__ . '/config/oAuthProviders.php'); Config::load('platforms', __DIR__ . '/config/platforms.php'); Config::load('collections', __DIR__ . '/config/collections.php'); Config::load('runtimes', __DIR__ . '/config/runtimes.php'); @@ -531,6 +532,7 @@ Database::addFilter( return Authorization::skip(fn() => $database ->find('targets', [ Query::equal('userInternalId', [$document->getInternalId()]), + Query::limit(APP_LIMIT_SUBQUERY) ])); } ); @@ -546,6 +548,7 @@ Database::addFilter( $database ->find('subscribers', [ Query::equal('topicInternalId', [$document->getInternalId()]), + Query::limit(1000000) ]) )); if (\count($targetIds) > 0) { @@ -1128,7 +1131,7 @@ App::setResource('console', function () { ], 'authWhitelistEmails' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [], 'authWhitelistIPs' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [], - 'authProviders' => [ + 'oAuthProviders' => [ 'githubEnabled' => true, 'githubSecret' => App::getEnv('_APP_CONSOLE_GITHUB_SECRET', ''), 'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', '') diff --git a/docs/tutorials/add-oauth2-provider.md b/docs/tutorials/add-oauth2-provider.md index 6481c64162..ab33f70cb2 100644 --- a/docs/tutorials/add-oauth2-provider.md +++ b/docs/tutorials/add-oauth2-provider.md @@ -37,7 +37,7 @@ Finally, you will need to create a `feat-XXX-YYY-oauth` branch based on the `mas The first step in adding a new OAuth2 provider is to add it to the list of providers located at: ``` -app/config/authProviders.php +app/config/oAuthProviders.php ``` Make sure to fill in all data needed and that your provider array key name: @@ -45,7 +45,7 @@ Make sure to fill in all data needed and that your provider array key name: - is in [`camelCase`](https://en.wikipedia.org/wiki/Camel_case) format for sentence, but lowercase for names. `github` must be all lowercased, but `paypalSandbox` should have uppercase S - has no spaces or special characters -> Please make sure to keep the list of providers in `authProviders.php` in the alphabetical order A-Z. +> Please make sure to keep the list of providers in `oAuthProviders.php` in the alphabetical order A-Z. ### 2.2 Add Provider Logo @@ -199,7 +199,7 @@ If you need any help with the contribution, feel free to head over to [our Disco If your OAuth provider requires special configuration apart from `clientId` and `clientSecret` you can create a custom form. Currently this is being realized through putting all custom fields as JSON into the `clientSecret` field to keep the project API stable. You can implement your custom form following these steps: -1. Add your custom form in `app/views/console/users/oauth/[PROVIDER].phtml`. Below is a template you can use. Add the filename to `app/config/authProviders.php`. +1. Add your custom form in `app/views/console/users/oauth/[PROVIDER].phtml`. Below is a template you can use. Add the filename to `app/config/oAuthProviders.php`. ```php "oauth-" . $value, - \array_keys(Config::getParam('authProviders', [])) + \array_keys(Config::getParam('oAuthProviders', [])) ) ); diff --git a/src/Appwrite/Migration/Version/V16.php b/src/Appwrite/Migration/Version/V16.php index bee2236dfb..49f244598e 100644 --- a/src/Appwrite/Migration/Version/V16.php +++ b/src/Appwrite/Migration/Version/V16.php @@ -124,23 +124,23 @@ class V16 extends Migration /** * Enable OAuth providers with data */ - $authProviders = $document->getAttribute('authProviders', []); + $oAuthProviders = $document->getAttribute('oAuthProviders', []); - foreach (Config::getParam('authProviders') as $provider => $value) { + foreach (Config::getParam('oAuthProviders') as $provider => $value) { if (!$value['enabled']) { continue; } - if (($authProviders[$provider . 'Appid'] ?? false) && ($authProviders[$provider . 'Secret'] ?? false)) { - if (array_key_exists($provider . 'Enabled', $authProviders)) { + if (($oAuthProviders[$provider . 'Appid'] ?? false) && ($oAuthProviders[$provider . 'Secret'] ?? false)) { + if (array_key_exists($provider . 'Enabled', $oAuthProviders)) { continue; } - $authProviders[$provider . 'Enabled'] = true; + $oAuthProviders[$provider . 'Enabled'] = true; } } - $document->setAttribute('authProviders', $authProviders); + $document->setAttribute('oAuthProviders', $oAuthProviders); break; } diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index cf2b359deb..6f33679aca 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -150,8 +150,11 @@ class Deletes extends Action case DELETE_TYPE_SCHEDULES: $this->deleteSchedules($dbForConsole, $getProjectDB, $datetime); break; - case DELETE_TYPE_SUBSCRIBERS: - $this->deleteSubscribers($project, $getProjectDB, $document); + case DELETE_TYPE_PROVIDER: + $this->deleteProvider($project, $getProjectDB, $document); + break; + case DELETE_TYPE_TOPIC: + $this->deleteTopic($project, $getProjectDB, $document); break; default: Console::error('No delete operation for type: ' . $type); @@ -196,13 +199,44 @@ class Deletes extends Action ); } + /** + * @param Document $project + * @param callable $getProjectDB + * @param Document $provider + * @throws Exception + */ + protected function deleteProvider(Document $project, callable $getProjectDB, Document $provider) + { + if ($provider->isEmpty()) { + Console::error('Failed to delete topics, subscribers and messages. Provider not found'); + return; + } + + $dbForProject = $getProjectDB($project); + $topics = $dbForProject->find('topics', [Query::equal('providerInternalId', [$provider->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY)]); + + $this->deleteByGroup('topics', [ + Query::equal('providerInternalId', [$provider->getInternalId()]) + ], $dbForProject); + + foreach ($topics as $topic) { + $this->deleteByGroup('subscribers', [ + Query::equal('topicInternalId', [$topic->getInternalId()]) + ], $dbForProject); + } + + $this->deleteByGroup('messages', [ + Query::equal('providerInternalId', [$provider->getInternalId()]) + ], $dbForProject); + } + /** * @param Document $project * @param callable $getProjectDB * @param Document $topic * @throws Exception */ - protected function deleteSubscribers(Document $project, callable $getProjectDB, Document $topic) + protected function deleteTopic(Document $project, callable $getProjectDB, Document $topic) { if ($topic->isEmpty()) { Console::error('Failed to delete subscribers. Topic not found'); diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index d87fb05532..b542dccaf2 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -31,13 +31,6 @@ use function Swoole\Coroutine\batch; class Messaging extends Action { - protected ?SMSAdapter $sms = null; - protected ?PushAdapter $push = null; - protected ?EmailAdapter $email = null; - - protected ?Database $dbForProject = null; - - public static function getName(): string { return "messaging"; diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php index d21aa5de1b..4bff13ae19 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php @@ -12,8 +12,7 @@ class Messages extends Base 'deliveryErrors', 'status', 'description', - 'data', - 'search' + 'data' ]; /** diff --git a/src/Appwrite/Utopia/Response/Filters/V13.php b/src/Appwrite/Utopia/Response/Filters/V13.php index d48473593e..04f9782915 100644 --- a/src/Appwrite/Utopia/Response/Filters/V13.php +++ b/src/Appwrite/Utopia/Response/Filters/V13.php @@ -60,8 +60,8 @@ class V13 extends Filter protected function parseProject($content) { - $content['providers'] = $content['authProviders']; - unset($content['authProviders']); + $content['providers'] = $content['oAuthProviders']; + unset($content['oAuthProviders']); return $content; } diff --git a/src/Appwrite/Utopia/Response/Filters/V16.php b/src/Appwrite/Utopia/Response/Filters/V16.php index 66cf650a78..609f118f6e 100644 --- a/src/Appwrite/Utopia/Response/Filters/V16.php +++ b/src/Appwrite/Utopia/Response/Filters/V16.php @@ -88,9 +88,9 @@ class V16 extends Filter protected function parseProject(array $content) { - foreach ($content['authProviders'] ?? [] as $i => $provider) { - $content['authProviders'][$i]['name'] = \ucfirst($provider['key']); - unset($content['authProviders'][$i]['key']); + foreach ($content['oAuthProviders'] ?? [] as $i => $provider) { + $content['oAuthProviders'][$i]['name'] = \ucfirst($provider['key']); + unset($content['oAuthProviders'][$i]['key']); } $content['domains'] = []; diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 807c1fb574..6bab4401d7 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -138,7 +138,7 @@ class Project extends Model 'default' => false, 'example' => true, ]) - ->addRule('authProviders', [ + ->addRule('oAuthProviders', [ 'type' => Response::MODEL_AUTH_PROVIDER, 'description' => 'List of Auth Providers.', 'default' => [], @@ -328,9 +328,9 @@ class Project extends Model $document->setAttribute('auth' . ucfirst($key), $value); } - // Providers - $providers = Config::getParam('authProviders', []); - $providerValues = $document->getAttribute('authProviders', []); + // OAuth Providers + $providers = Config::getParam('oAuthProviders', []); + $providerValues = $document->getAttribute('oAuthProviders', []); $projectProviders = []; foreach ($providers as $key => $provider) { @@ -348,7 +348,7 @@ class Project extends Model ]); } - $document->setAttribute('authProviders', $projectProviders); + $document->setAttribute('oAuthProviders', $projectProviders); return $document; } diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index eefc766b94..83e136fab4 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -794,7 +794,7 @@ class ProjectsConsoleClientTest extends Scope public function testUpdateProjectOAuth($data): array { $id = $data['projectId'] ?? ''; - $providers = require('app/config/authProviders.php'); + $providers = require('app/config/oAuthProviders.php'); /** * Test for SUCCESS @@ -825,7 +825,7 @@ class ProjectsConsoleClientTest extends Scope foreach ($providers as $key => $provider) { $asserted = false; - foreach ($response['body']['authProviders'] as $responseProvider) { + foreach ($response['body']['oAuthProviders'] as $responseProvider) { if ($responseProvider['key'] === $key) { $this->assertEquals('AppId-' . ucfirst($key), $responseProvider['appId']); $this->assertEquals('Secret-' . ucfirst($key), $responseProvider['secret']); @@ -867,7 +867,7 @@ class ProjectsConsoleClientTest extends Scope $i = 0; foreach ($providers as $key => $provider) { $asserted = false; - foreach ($response['body']['authProviders'] as $responseProvider) { + foreach ($response['body']['oAuthProviders'] as $responseProvider) { if ($responseProvider['key'] === $key) { // On first provider, test enabled=false $this->assertEquals($i !== 0, $responseProvider['enabled']); diff --git a/tests/unit/Utopia/Response/Filters/V16Test.php b/tests/unit/Utopia/Response/Filters/V16Test.php index 96c615f452..2078559b61 100644 --- a/tests/unit/Utopia/Response/Filters/V16Test.php +++ b/tests/unit/Utopia/Response/Filters/V16Test.php @@ -154,9 +154,9 @@ class V16Test extends TestCase public function projectProvider(): array { return [ - 'authProviders' => [ + 'oAuthProviders' => [ [ - 'authProviders' => [ + 'oAuthProviders' => [ [ 'key' => 'github', 'name' => 'GitHub', @@ -167,7 +167,7 @@ class V16Test extends TestCase ], ], [ - 'authProviders' => [ + 'oAuthProviders' => [ [ 'name' => 'Github', 'appId' => 'client_id', From 887eeef5856c2715c65c0dc317875dea5c36d47b Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 25 Oct 2023 23:09:38 +0530 Subject: [PATCH 134/196] review changes --- app/controllers/api/messaging.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 20989da623..c0e8f7215a 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -448,7 +448,7 @@ App::post('/v1/messaging/providers/fcm') ->param('serverKey', '', new Text(0), 'FCM server key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -506,7 +506,7 @@ App::post('/v1/messaging/providers/apns') ->param('endpoint', '', new Text(0), 'APNS endpoint.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, From f5aa226b57679a007d9240194c7b98d16d214e6b Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 26 Oct 2023 00:02:22 +0530 Subject: [PATCH 135/196] fix test --- tests/e2e/Services/Users/UsersBase.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index 9c734befea..9ca00aa5df 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -1234,7 +1234,8 @@ trait UsersBase ], $this->getHeaders()), [ 'providerId' => 'unique()', 'name' => 'Sengrid1', - 'apiKey' => 'my-apikey' + 'apiKey' => 'my-apikey', + 'from' => 'from@domain.com', ]); $this->assertEquals(201, $provider['headers']['status-code']); $response = $this->client->call(Client::METHOD_POST, '/users/' . $data['userId'] . '/targets', array_merge([ From 34b3ed68ee0f1aa6606ca82a585518cf286e9b17 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 26 Oct 2023 12:37:39 +0530 Subject: [PATCH 136/196] adds total count for subscribers in topics model --- app/config/collections.php | 13 ++++++++- app/controllers/api/messaging.php | 5 ++-- composer.lock | 2 +- src/Appwrite/Utopia/Response/Model/Topic.php | 6 ++++ .../e2e/Services/Messaging/MessagingBase.php | 28 +++++++++++++++++-- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 8f4edef99f..4f492471d6 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1629,7 +1629,7 @@ $commonCollections = [ 'size' => 0, 'signed' => true, 'required' => false, - 'default' => null, + 'default' => 0, 'array' => false, 'filters' => [], ], @@ -1719,6 +1719,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('total'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('targets'), 'type' => Database::VAR_STRING, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 830e2aef3f..4a2bc34776 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1491,7 +1491,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') try { $subscriber = $dbForProject->createDocument('subscribers', $subscriber); - $dbForProject->deleteCachedDocument('topics', $topicId); + Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('topics', $topicId, 'total', 1)); } catch (DuplicateException) { throw new Exception(Exception::SUBSCRIBER_ALREADY_EXISTS); } @@ -1610,8 +1610,9 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') if ($subscriber->isEmpty() || $subscriber->getAttribute('topicId') !== $topicId) { throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } + $subscriber = $dbForProject->deleteDocument('subscribers', $subscriberId); - $dbForProject->deleteCachedDocument('topics', $topicId); + Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('topics', $topicId, 'total', 1)); $response ->setStatusCode(Response::STATUS_CODE_NOCONTENT) diff --git a/composer.lock b/composer.lock index 7212a951a4..9ef16ead55 100644 --- a/composer.lock +++ b/composer.lock @@ -5822,5 +5822,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/src/Appwrite/Utopia/Response/Model/Topic.php b/src/Appwrite/Utopia/Response/Model/Topic.php index 3a6e832f5c..6d76faf6f4 100644 --- a/src/Appwrite/Utopia/Response/Model/Topic.php +++ b/src/Appwrite/Utopia/Response/Model/Topic.php @@ -28,6 +28,12 @@ class Topic extends Model 'default' => '', 'example' => 'events', ]) + ->addRule('total', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Total count of subscribers subscribed to topic.', + 'default' => 0, + 'example' => 100, + ]) ->addRule('description', [ 'type' => self::TYPE_STRING, 'description' => 'Description of the topic.', diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index c7804d7f89..765bd91ede 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -288,6 +288,7 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('android-app', $response['body']['name']); $this->assertEquals('updated-description', $response['body']['description']); + $this->assertEquals(0, $response['body']['total']); } /** @@ -311,12 +312,23 @@ trait MessagingBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'subscriberId' => 'unique()', + 'subscriberId' => ID::unique(), 'targetId' => $target['body']['$id'], ]); $this->assertEquals(201, $response['headers']['status-code']); + + $topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(200, $topic['headers']['status-code']); + $this->assertEquals('android-app', $topic['body']['name']); + $this->assertEquals('updated-description', $topic['body']['description']); + $this->assertEquals(1, $topic['body']['total']); + return [ - 'topicId' => $topic['$id'], + 'topicId' => $topic['body']['$id'], 'targetId' => $target['body']['$id'], 'subscriberId' => $response['body']['$id'] ]; @@ -361,7 +373,19 @@ trait MessagingBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); + $this->assertEquals(204, $response['headers']['status-code']); + + $topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $topic['headers']['status-code']); + $this->assertEquals('android-app', $topic['body']['name']); + $this->assertEquals('updated-description', $topic['body']['description']); + $this->assertEquals(0, $topic['body']['total']); } /** From c2cd544948a3d831740e509ce7bd931221c66d98 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 26 Oct 2023 13:46:45 +0530 Subject: [PATCH 137/196] review changes --- app/config/events.php | 7 +- app/controllers/api/messaging.php | 91 +++++++++++------------ app/init.php | 4 +- src/Appwrite/Platform/Workers/Deletes.php | 34 --------- 4 files changed, 50 insertions(+), 86 deletions(-) diff --git a/app/config/events.php b/app/config/events.php index 8a89402184..b0db9090fb 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -267,10 +267,13 @@ return [ '$resource' => true, '$description' => 'This event triggers on any topic event.', 'create' => [ - '$description' => 'This event triggers when a provider is created.', + '$description' => 'This event triggers when a topic is created.', + ], + 'update' => [ + '$description' => 'This event triggers when a topic is updated.', ], 'delete' => [ - '$description' => 'This event triggers when a provider is deleted.' + '$description' => 'This event triggers when a topic is deleted.' ], 'subscribers' => [ '$model' => Response::MODEL_SUBSCRIBER, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 4a2bc34776..e1057a0885 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -31,7 +31,7 @@ App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -94,7 +94,7 @@ App::post('/v1/messaging/providers/sendgrid') ->desc('Create Sendgrid provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -152,7 +152,7 @@ App::post('/v1/messaging/providers/msg91') ->desc('Create Msg91 provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -212,7 +212,7 @@ App::post('/v1/messaging/providers/telesign') ->desc('Create Telesign provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -272,7 +272,7 @@ App::post('/v1/messaging/providers/textmagic') ->desc('Create TextMagic provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -332,7 +332,7 @@ App::post('/v1/messaging/providers/twilio') ->desc('Create Twilio provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -392,7 +392,7 @@ App::post('/v1/messaging/providers/vonage') ->desc('Create Vonage provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -452,7 +452,7 @@ App::post('/v1/messaging/providers/fcm') ->desc('Create FCM provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -506,7 +506,7 @@ App::post('/v1/messaging/providers/apns') ->desc('Create APNS provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -635,7 +635,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->desc('Update Mailgun provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -706,7 +706,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->desc('Update Sendgrid provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -765,7 +765,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ->desc('Update Msg91 provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -831,7 +831,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ->desc('Update Telesign provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -897,7 +897,7 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->desc('Update TextMagic provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -963,7 +963,7 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ->desc('Update Twilio provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1029,7 +1029,7 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ->desc('Update Vonage provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1095,7 +1095,7 @@ App::patch('/v1/messaging/providers/fcm/:providerId') ->desc('Update FCM provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1146,7 +1146,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') ->desc('Update APNS provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1219,8 +1219,8 @@ App::patch('/v1/messaging/providers/apns/:providerId') App::delete('/v1/messaging/providers/:providerId') ->desc('Delete provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.delete') - ->label('audits.resource', 'providers/{request.id}') + ->label('audits.event', 'provider.delete') + ->label('audits.resource', 'provider/{request.id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1230,20 +1230,15 @@ App::delete('/v1/messaging/providers/:providerId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) ->param('providerId', '', new UID(), 'Provider ID.') - ->inject('queueForDeletes') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, Delete $queueForDeletes, Database $dbForProject, Response $response) { + ->action(function (string $providerId, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } - $queueForDeletes - ->setType(DELETE_TYPE_PROVIDER) - ->setDocument($provider); - $dbForProject->deleteDocument('providers', $provider->getId()); $response @@ -1254,8 +1249,8 @@ App::delete('/v1/messaging/providers/:providerId') App::post('/v1/messaging/topics') ->desc('Create a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'topics.create') - ->label('audits.resource', 'topics/{response.$id}') + ->label('audits.event', 'topic.create') + ->label('audits.resource', 'topic/{response.$id}') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1373,8 +1368,8 @@ App::get('/v1/messaging/topics/:topicId') App::patch('/v1/messaging/topics/:topicId') ->desc('Update a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'topics.update') - ->label('audits.resource', 'topics/{response.$id}') + ->label('audits.event', 'topic.update') + ->label('audits.resource', 'topic/{response.$id}') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1412,8 +1407,8 @@ App::patch('/v1/messaging/topics/:topicId') App::delete('/v1/messaging/topics/:topicId') ->desc('Delete a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'topics.delete') - ->label('audits.resource', 'topics/{request.topicId}') + ->label('audits.event', 'topic.delete') + ->label('audits.resource', 'topic/{request.topicId}') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1447,8 +1442,8 @@ App::delete('/v1/messaging/topics/:topicId') App::post('/v1/messaging/topics/:topicId/subscribers') ->desc('Adds a subscriber to a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'subscribers.create') - ->label('audits.resource', 'subscribers/{response.$id}') + ->label('audits.event', 'subscriber.create') + ->label('audits.resource', 'subscriber/{response.$id}') ->label('scope', 'subscribers.write') ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1584,8 +1579,8 @@ App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->desc('Delete a subscriber from a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'subscribers.delete') - ->label('audits.resource', 'subscribers/{request.subscriberId}') + ->label('audits.event', 'subscriber.delete') + ->label('audits.resource', 'subscriber/{request.subscriberId}') ->label('scope', 'subscribers.write') ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1622,8 +1617,8 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') App::post('/v1/messaging/messages/email') ->desc('Create an email.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.create') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.create') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1688,8 +1683,8 @@ App::post('/v1/messaging/messages/email') App::post('/v1/messaging/messages/sms') ->desc('Create an SMS.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.create') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.create') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1751,8 +1746,8 @@ App::post('/v1/messaging/messages/sms') App::post('/v1/messaging/messages/push') ->desc('Create a push notification.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.create') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.create') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1920,8 +1915,8 @@ App::get('/v1/messaging/messages/:messageId') App::patch('/v1/messaging/messages/email/:messageId') ->desc('Update an email.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.update') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.update') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -2007,8 +2002,8 @@ App::patch('/v1/messaging/messages/email/:messageId') App::patch('/v1/messaging/messages/sms/:messageId') ->desc('Update an SMS.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.update') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.update') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -2084,8 +2079,8 @@ App::patch('/v1/messaging/messages/sms/:messageId') App::patch('/v1/messaging/messages/push/:messageId') ->desc('Update a push notification.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.update') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.update') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') diff --git a/app/init.php b/app/init.php index 136ecd25cb..a60dcb2079 100644 --- a/app/init.php +++ b/app/init.php @@ -98,6 +98,7 @@ const APP_LIMIT_COMPRESSION = 20000000; //20MB const APP_LIMIT_ARRAY_PARAMS_SIZE = 100; // Default maximum of how many elements can there be in API parameter that expects array value const APP_LIMIT_ARRAY_ELEMENT_SIZE = 4096; // Default maximum length of element in array parameter represented by maximum URL length. const APP_LIMIT_SUBQUERY = 1000; +const APP_LIMIT_SUBSCRIBERS_SUBQUERY = 1000000; const APP_LIMIT_WRITE_RATE_DEFAULT = 60; // Default maximum write rate per rate period const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60; // Default maximum write rate period in seconds const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return in list API calls @@ -168,7 +169,6 @@ const DELETE_TYPE_SESSIONS = 'sessions'; const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp'; const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; const DELETE_TYPE_SCHEDULES = 'schedules'; -const DELETE_TYPE_PROVIDER = 'provider'; const DELETE_TYPE_TOPIC = 'topic'; // Compression type const COMPRESSION_TYPE_NONE = 'none'; @@ -548,7 +548,7 @@ Database::addFilter( $database ->find('subscribers', [ Query::equal('topicInternalId', [$document->getInternalId()]), - Query::limit(1000000) + Query::limit(APP_LIMIT_SUBSCRIBERS_SUBQUERY) ]) )); if (\count($targetIds) > 0) { diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 6f33679aca..a22f7840f7 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -150,9 +150,6 @@ class Deletes extends Action case DELETE_TYPE_SCHEDULES: $this->deleteSchedules($dbForConsole, $getProjectDB, $datetime); break; - case DELETE_TYPE_PROVIDER: - $this->deleteProvider($project, $getProjectDB, $document); - break; case DELETE_TYPE_TOPIC: $this->deleteTopic($project, $getProjectDB, $document); break; @@ -199,37 +196,6 @@ class Deletes extends Action ); } - /** - * @param Document $project - * @param callable $getProjectDB - * @param Document $provider - * @throws Exception - */ - protected function deleteProvider(Document $project, callable $getProjectDB, Document $provider) - { - if ($provider->isEmpty()) { - Console::error('Failed to delete topics, subscribers and messages. Provider not found'); - return; - } - - $dbForProject = $getProjectDB($project); - $topics = $dbForProject->find('topics', [Query::equal('providerInternalId', [$provider->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY)]); - - $this->deleteByGroup('topics', [ - Query::equal('providerInternalId', [$provider->getInternalId()]) - ], $dbForProject); - - foreach ($topics as $topic) { - $this->deleteByGroup('subscribers', [ - Query::equal('topicInternalId', [$topic->getInternalId()]) - ], $dbForProject); - } - - $this->deleteByGroup('messages', [ - Query::equal('providerInternalId', [$provider->getInternalId()]) - ], $dbForProject); - } - /** * @param Document $project * @param callable $getProjectDB From 5a9b1f0c241c7d7ebb85a94abee081c3da0180ef Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 26 Oct 2023 19:44:06 +0530 Subject: [PATCH 138/196] removes provider from topics --- app/config/collections.php | 72 ------------ app/controllers/api/account.php | 4 - app/controllers/api/messaging.php | 62 ++-------- composer.lock | 12 +- src/Appwrite/Platform/Workers/Messaging.php | 107 ++++++++++-------- .../Utopia/Response/Model/Message.php | 6 - src/Appwrite/Utopia/Response/Model/Topic.php | 6 - tests/e2e/Services/GraphQL/Base.php | 28 ++--- tests/e2e/Services/GraphQL/MessagingTest.php | 63 ++++------- .../e2e/Services/Messaging/MessagingBase.php | 40 +++---- 10 files changed, 121 insertions(+), 279 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 4f492471d6..54b6b3bec3 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1523,28 +1523,6 @@ $commonCollections = [ '$id' => ID::custom('messages'), 'name' => 'Messages', 'attributes' => [ - [ - '$id' => ID::custom('providerId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('providerInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('description'), 'type' => Database::VAR_STRING, @@ -1646,20 +1624,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_providerId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerId'], - 'lengths' => [], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_providerInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerInternalId'], - 'lengths' => [], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_search'), 'type' => Database::INDEX_FULLTEXT, @@ -1675,28 +1639,6 @@ $commonCollections = [ '$id' => ID::custom('topics'), 'name' => 'Topics', 'attributes' => [ - [ - '$id' => ID::custom('providerId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('providerInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('name'), 'type' => Database::VAR_STRING, @@ -1754,20 +1696,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_providerId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerId'], - 'lengths' => [], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_providerInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['providerInternalId'], - 'lengths' => [], - 'orders' => [Database::ORDER_ASC], - ], [ '$id' => ID::custom('_key_name'), 'type' => Database::INDEX_FULLTEXT, diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index f119d33414..4c7411d978 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1351,8 +1351,6 @@ App::post('/v1/account/sessions/phone') 'data' => [ 'content' => $message, ], - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), ])); $queueForMessaging @@ -2986,8 +2984,6 @@ App::post('/v1/account/verification/phone') 'data' => [ 'content' => $message, ], - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), ])); $queueForMessaging diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index e1057a0885..b9bfbefdb7 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1260,23 +1260,15 @@ App::post('/v1/messaging/topics') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TOPIC) ->param('topicId', '', new CustomId(), 'Topic ID. Choose a custom Topic ID or a new Topic ID.') - ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Topic Name.') ->param('description', '', new Text(2048), 'Topic Description.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $topicId, string $providerId, string $name, string $description, Database $dbForProject, Response $response) { + ->action(function (string $topicId, string $name, string $description, Database $dbForProject, Response $response) { $topicId = $topicId == 'unique()' ? ID::unique() : $topicId; - $provider = $dbForProject->getDocument('providers', $providerId); - - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } $topic = new Document([ '$id' => $topicId, - 'providerId' => $providerId, - 'providerInternalId' => $provider->getInternalId(), 'name' => $name, ]); @@ -1628,7 +1620,6 @@ App::post('/v1/messaging/messages/email') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('providerId', '', new UID(), 'Email Provider ID.') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(998), 'Email Subject.') ->param('content', '', new Text(64230), 'Email Content.') @@ -1640,23 +1631,11 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $subject, string $content, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $to, string $subject, string $content, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; - $provider = $dbForProject->getDocument('providers', $providerId); - - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - - if ($provider->getAttribute('type') !== 'email') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); - } - $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), 'to' => $to, 'description' => $description, 'data' => [ @@ -1665,7 +1644,7 @@ App::post('/v1/messaging/messages/email') 'html' => $html, ], 'status' => $status, - 'search' => $messageId . ' ' . $description . ' ' . $subject . ' ' . $providerId, + 'search' => $messageId . ' ' . $description . ' ' . $subject, ])); if ($status === 'processing') { @@ -1694,7 +1673,6 @@ App::post('/v1/messaging/messages/sms') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('providerId', '', new UID(), 'SMS Provider ID.') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('content', '', new Text(64230), 'SMS Content.') ->param('description', '', new Text(256), 'Description for Message.', true) @@ -1704,31 +1682,18 @@ App::post('/v1/messaging/messages/sms') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $content, string $description, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $to, string $content, string $description, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; - $provider = $dbForProject->getDocument('providers', $providerId); - - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - - if ($provider->getAttribute('type') !== 'sms') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); - } - $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), 'to' => $to, 'description' => $description, - 'deliveryTime' => $deliveryTime, 'data' => [ 'content' => $content, ], 'status' => $status, - 'search' => $messageId . ' ' . $description . ' ' . $providerId, + 'search' => $messageId . ' ' . $description, ])); if ($status === 'processing') { @@ -1757,7 +1722,6 @@ App::post('/v1/messaging/messages/push') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('providerId', '', new UID(), 'Push Provider ID.') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('title', '', new Text(256), 'Title for push notification.') ->param('body', '', new Text(64230), 'Body for push notification.') @@ -1775,19 +1739,9 @@ App::post('/v1/messaging/messages/push') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $title, string $body, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $to, string $title, string $body, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; - $provider = $dbForProject->getDocument('providers', $providerId); - - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - - if ($provider->getAttribute('type') !== 'push') { - throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); - } - $pushData = [ 'title' => $title, 'body' => $body, @@ -1823,14 +1777,12 @@ App::post('/v1/messaging/messages/push') $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), 'to' => $to, 'description' => $description, 'deliveryTime' => $deliveryTime, 'data' => $pushData, 'status' => $status, - 'search' => $messageId . ' ' . $description . ' ' . $title . ' ' . $providerId, + 'search' => $messageId . ' ' . $description . ' ' . $title, ])); if ($status === 'processing') { diff --git a/composer.lock b/composer.lock index 9ef16ead55..66e5e5a11b 100644 --- a/composer.lock +++ b/composer.lock @@ -1906,16 +1906,16 @@ }, { "name": "utopia-php/database", - "version": "0.44.3", + "version": "0.44.4", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "b2d403c25a77506e03db5736335b0cae52bcc18a" + "reference": "b0c3fd8ecfedc3646d7780f2d6b38955a66baf48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/b2d403c25a77506e03db5736335b0cae52bcc18a", - "reference": "b2d403c25a77506e03db5736335b0cae52bcc18a", + "url": "https://api.github.com/repos/utopia-php/database/zipball/b0c3fd8ecfedc3646d7780f2d6b38955a66baf48", + "reference": "b0c3fd8ecfedc3646d7780f2d6b38955a66baf48", "shasum": "" }, "require": { @@ -1956,9 +1956,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.44.3" + "source": "https://github.com/utopia-php/database/tree/0.44.4" }, - "time": "2023-10-24T10:13:48+00:00" + "time": "2023-10-26T07:08:12+00:00" }, { "name": "utopia-php/domains", diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index b542dccaf2..0c101b26e0 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -36,7 +36,6 @@ class Messaging extends Action return "messaging"; } - /** * @throws Exception */ @@ -64,24 +63,19 @@ class Messaging extends Action return; } - $message = $dbForProject->getDocument('messages', $payload['messageId']); - $provider = $dbForProject->getDocument('providers', $message->getAttribute('providerId')); - - $this->processMessage($dbForProject, $message, $provider); + $this->processMessage($dbForProject, $message); } - private function processMessage(Database $dbForProject, Document $message, Document $provider): void + private function processMessage(Database $dbForProject, Document $message): void { - $adapter = match ($provider->getAttribute('type')) { - 'sms' => $this->sms($provider), - 'push' => $this->push($provider), - 'email' => $this->email($provider), - default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) - }; + $recipientsId = $message->getAttribute('to', []); - $recipientsId = $message->getAttribute('to'); + if (\count($recipientsId) < 1) { + Console::error('Recipients not found'); + return; + } /** * @var Document[] $recipients @@ -100,44 +94,65 @@ class Messaging extends Action $targets = $dbForProject->find('targets', [Query::equal('$id', $recipientsId)]); $recipients = \array_merge($recipients, $targets); - $recipients = \array_filter($recipients, function (Document $recipient) use ($provider) { - return $recipient->getAttribute('providerId') === $provider->getId(); - }); - $identifiers = \array_map(function (Document $recipient) { - return $recipient->getAttribute('identifier'); - }, $recipients); + $providers = []; + foreach ($recipients as $recipient) { + $providerId = $recipient->getAttribute('providerId'); + if (!isset($providers[$providerId])) { + $providers[$providerId] = []; + } + $providers[$providerId][] = $recipient->getAttribute('identifier'); + } - $maxBatchSize = $adapter->getMaxMessagesPerRequest(); - $batches = \array_chunk($identifiers, $maxBatchSize); - $batchIndex = 0; - - $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex) { - return function () use ($batch, $message, $provider, $adapter, $batchIndex) { - $deliveredTo = 0; - $deliveryErrors = []; - $messageData = clone $message; - $messageData->setAttribute('to', $batch); - $data = match ($provider->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($messageData, $provider), - 'push' => $this->buildPushMessage($messageData), - 'email' => $this->buildEmailMessage($messageData, $provider), + /** + * @var array[] $results + */ + $results = batch(\array_map(function ($providerId) use ($providers, $message, $dbForProject) { + return function () use ($providerId, $providers, $message, $dbForProject) { + $provider = $dbForProject->getDocument('providers', $providerId); + $identifiers = $providers[$providerId]; + $adapter = match ($provider->getAttribute('type')) { + 'sms' => $this->sms($provider), + 'push' => $this->push($provider), + 'email' => $this->email($provider), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; - try { - $adapter->send($data); - $deliveredTo += \count($batch); - } catch (\Exception $e) { - $deliveryErrors[] = 'Failed sending to targets ' . $batchIndex + 1 . '-' . \count($batch) . ' with error: ' . $e->getMessage(); - } finally { - $batchIndex++; - return [ - 'deliveredTo' => $deliveredTo, - 'deliveryErrors' => $deliveryErrors, - ]; - } + $maxBatchSize = $adapter->getMaxMessagesPerRequest(); + $batches = \array_chunk($identifiers, $maxBatchSize); + $batchIndex = 0; + + $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex) { + return function () use ($batch, $message, $provider, $adapter, $batchIndex) { + $deliveredTo = 0; + $deliveryErrors = []; + $messageData = clone $message; + $messageData->setAttribute('to', $batch); + $data = match ($provider->getAttribute('type')) { + 'sms' => $this->buildSMSMessage($messageData, $provider), + 'push' => $this->buildPushMessage($messageData), + 'email' => $this->buildEmailMessage($messageData, $provider), + default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) + }; + try { + $adapter->send($data); + $deliveredTo += \count($batch); + } catch (\Exception $e) { + $deliveryErrors[] = 'Failed sending to targets ' . $batchIndex + 1 . '-' . \count($batch) . ' with error: ' . $e->getMessage(); + } finally { + $batchIndex++; + return [ + 'deliveredTo' => $deliveredTo, + 'deliveryErrors' => $deliveryErrors, + ]; + } + }; + }, $batches)); + + return $results; }; - }, $batches)); + }, \array_keys($providers))); + + $results = array_merge(...$results); $deliveredTo = 0; $deliveryErrors = []; diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 0cadc378d9..609aa4022e 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -17,12 +17,6 @@ class Message extends Any 'default' => '', 'example' => '5e5ea5c16897e', ]) - ->addRule('providerId', [ - 'type' => self::TYPE_STRING, - 'description' => 'Provider ID for the message.', - 'default' => '', - 'example' => '5e5ea5c16897e', - ]) ->addRule('to', [ 'type' => self::TYPE_STRING, 'description' => 'Message recipients.', diff --git a/src/Appwrite/Utopia/Response/Model/Topic.php b/src/Appwrite/Utopia/Response/Model/Topic.php index 6d76faf6f4..d46d26597d 100644 --- a/src/Appwrite/Utopia/Response/Model/Topic.php +++ b/src/Appwrite/Utopia/Response/Model/Topic.php @@ -16,12 +16,6 @@ class Topic extends Model 'default' => '', 'example' => '259125845563242502', ]) - ->addRule('providerId', [ - 'type' => self::TYPE_STRING, - 'description' => 'Provider ID.', - 'default' => '', - 'example' => '259125845563242502', - ]) ->addRule('name', [ 'type' => self::TYPE_STRING, 'description' => 'The name of the topic.', diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 745a64c0e7..bf6ae84f7f 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -2013,11 +2013,10 @@ trait Base } }'; case self::$CREATE_TOPIC: - return 'mutation createTopic($providerId: String!, $topicId: String!, $name: String!, $description: String!) { - messagingCreateTopic(providerId: $providerId, topicId: $topicId, name: $name, description: $description) { + return 'mutation createTopic($topicId: String!, $name: String!, $description: String!) { + messagingCreateTopic(topicId: $topicId, name: $name, description: $description) { _id name - providerId description } }'; @@ -2028,7 +2027,6 @@ trait Base topics { _id name - providerId description } } @@ -2038,7 +2036,6 @@ trait Base messagingGetTopic(topicId: $topicId) { _id name - providerId description } }'; @@ -2047,7 +2044,6 @@ trait Base messagingUpdateTopic(topicId: $topicId, name: $name, description: $description) { _id name - providerId description } }'; @@ -2091,10 +2087,9 @@ trait Base } }'; case self::$CREATE_EMAIL: - return 'mutation createEmail($messageId: String!, $providerId: String!, $to: [String!]!, $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { - messagingCreateEmail(messageId: $messageId, providerId: $providerId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + return 'mutation createEmail($messageId: String!, $to: [String!]!, $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { + messagingCreateEmail(messageId: $messageId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { _id - providerId to deliveryTime deliveredAt @@ -2105,10 +2100,9 @@ trait Base } }'; case self::$CREATE_SMS: - return 'mutation createSMS($messageId: String!, $providerId: String!, $to: [String!]!, $content: String!, $status: String, $description: String, $deliveryTime: String) { - messagingCreateSMS(messageId: $messageId, providerId: $providerId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation createSMS($messageId: String!, $to: [String!]!, $content: String!, $status: String, $description: String, $deliveryTime: String) { + messagingCreateSMS(messageId: $messageId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - providerId to deliveryTime deliveredAt @@ -2119,10 +2113,9 @@ trait Base } }'; case self::$CREATE_PUSH_NOTIFICATION: - return 'mutation createPushNotification($messageId: String!, $providerId: String!, $to: [String!]!, $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { - messagingCreatePushNotification(messageId: $messageId, providerId: $providerId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation createPushNotification($messageId: String!, $to: [String!]!, $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { + messagingCreatePushNotification(messageId: $messageId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - providerId to deliveryTime deliveredAt @@ -2138,7 +2131,6 @@ trait Base total messages { _id - providerId to deliveryTime deliveredAt @@ -2153,7 +2145,6 @@ trait Base return 'query getMessage($messageId: String!) { messagingGetMessage(messageId: $messageId) { _id - providerId to deliveryTime deliveredAt @@ -2167,7 +2158,6 @@ trait Base return 'mutation updateEmail($messageId: String!, $to: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { messagingUpdateEmail(messageId: $messageId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { _id - providerId to deliveryTime deliveredAt @@ -2181,7 +2171,6 @@ trait Base return 'mutation updateSMS($messageId: String!, $to: [String!], $content: String, $status: String, $description: String, $deliveryTime: String) { messagingUpdateSMS(messageId: $messageId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - providerId to deliveryTime deliveredAt @@ -2195,7 +2184,6 @@ trait Base return 'mutation updatePushNotification($messageId: String!, $to: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { messagingUpdatePushNotification(messageId: $messageId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - providerId to deliveryTime deliveredAt diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 4478a4d75b..82f697f7ec 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -96,7 +96,6 @@ class MessagingTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), $graphQLPayload); - var_dump($response['body']); \array_push($providers, $response['body']['data']['messagingCreate' . $key . 'Provider']); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($providersParams[$key]['name'], $response['body']['data']['messagingCreate' . $key . 'Provider']['name']); @@ -268,32 +267,10 @@ class MessagingTest extends Scope public function testCreateTopic() { - $providerParam = [ - 'sendgrid' => [ - 'providerId' => ID::unique(), - 'name' => 'Sengrid1', - 'apiKey' => 'my-apikey', - 'from' => 'sender-email@my-domain.com', - ] - ]; - $query = $this->getQuery(self::$CREATE_SENDGRID_PROVIDER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => $providerParam['sendgrid'], - ]; - $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $providerId = $response['body']['data']['messagingCreateSendgridProvider']['_id']; - $query = $this->getQuery(self::$CREATE_TOPIC); $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'providerId' => $providerId, 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Active users', @@ -391,13 +368,34 @@ class MessagingTest extends Scope $userId = $this->getUser()['$id']; + $providerParam = [ + 'sendgrid' => [ + 'providerId' => ID::unique(), + 'name' => 'Sengrid1', + 'apiKey' => 'my-apikey', + 'from' => 'sender-email@my-domain.com', + ] + ]; + $query = $this->getQuery(self::$CREATE_SENDGRID_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => $providerParam['sendgrid'], + ]; + $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $providerId = $response['body']['data']['messagingCreateSendgridProvider']['_id']; + $query = $this->getQuery(self::$CREATE_USER_TARGET); $graphQLPayload = [ 'query' => $query, 'variables' => [ 'targetId' => ID::unique(), 'userId' => $userId, - 'providerId' => $topic['providerId'], + 'providerId' => $providerId, 'identifier' => 'token', ], ]; @@ -546,7 +544,7 @@ class MessagingTest extends Scope 'apiKey' => $apiKey, 'domain' => $domain, 'from' => $from, - 'isEuRegion' => $isEuRegion, + 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), ], ]; $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -563,7 +561,6 @@ class MessagingTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'providerId' => $providerId, 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Active users', @@ -634,7 +631,6 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'providerId' => $providerId, 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', @@ -693,7 +689,7 @@ class MessagingTest extends Scope 'apiKey' => $apiKey, 'domain' => $domain, 'from' => $from, - 'isEuRegion' => $isEuRegion, + 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), ], ]; $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -710,7 +706,6 @@ class MessagingTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'providerId' => $providerId, 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Active users', @@ -781,7 +776,6 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'providerId' => $providerId, 'status' => 'draft', 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'subject' => 'Khali beats Undertaker', @@ -867,7 +861,6 @@ class MessagingTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'providerId' => $providerId, 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Active users', @@ -938,7 +931,6 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'providerId' => $providerId, 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'content' => '454665', ], @@ -1010,7 +1002,6 @@ class MessagingTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'providerId' => $providerId, 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Active users', @@ -1081,7 +1072,6 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'providerId' => $providerId, 'status' => 'draft', 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'content' => '345463', @@ -1162,7 +1152,6 @@ class MessagingTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'providerId' => $providerId, 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Active users', @@ -1233,7 +1222,6 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'providerId' => $providerId, 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'title' => 'Push Notification Title', 'body' => 'Push Notifiaction Body', @@ -1296,14 +1284,12 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $provider['headers']['status-code']); - var_dump($provider['body']); $providerId = $provider['body']['data']['messagingCreateFcmProvider']['_id']; $query = $this->getQuery(self::$CREATE_TOPIC); $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'providerId' => $providerId, 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Active users', @@ -1374,7 +1360,6 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'providerId' => $providerId, 'status' => 'draft', 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'title' => 'Push Notification Title', diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 765bd91ede..01138c6412 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -218,23 +218,11 @@ trait MessagingBase public function testCreateTopic(): array { - $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), [ - 'providerId' => 'unique()', - 'name' => 'Sendgrid1', - 'apiKey' => 'my-apikey', - 'from' => 'sender-email@my-domain.com', - ]); - $this->assertEquals(201, $provider['headers']['status-code']); $response = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'providerId' => $provider['body']['$id'], 'topicId' => 'unique()', 'name' => 'my-app', 'description' => 'web app' @@ -297,13 +285,27 @@ trait MessagingBase public function testCreateSubscriber(array $topic) { $userId = $this->getUser()['$id']; + + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'Sendgrid1', + 'apiKey' => 'my-apikey', + 'from' => 'sender-email@my-domain.com', + ]); + + $this->assertEquals(201, $provider['headers']['status-code']); + $target = $this->client->call(Client::METHOD_POST, '/users/' . $userId . '/targets', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'targetId' => ID::unique(), - 'providerId' => $topic['providerId'], + 'providerId' => $provider['body']['$id'], 'identifier' => 'my-token', ]); $this->assertEquals(201, $target['headers']['status-code']); @@ -433,7 +435,6 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'providerId' => $provider['body']['$id'], 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Test Topic' @@ -485,7 +486,6 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'providerId' => $provider['body']['$id'], 'to' => [$topic['body']['$id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', @@ -553,7 +553,6 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'providerId' => $provider['body']['$id'], 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Test Topic' @@ -605,7 +604,6 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'providerId' => $provider['body']['$id'], 'status' => 'draft', 'to' => [$topic['body']['$id']], 'subject' => 'Khali beats Undertaker', @@ -668,7 +666,6 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'providerId' => $provider['body']['$id'], 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Test Topic' @@ -720,7 +717,6 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'providerId' => $provider['body']['$id'], 'to' => [$topic['body']['$id']], 'content' => '064763', ]); @@ -785,7 +781,6 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'providerId' => $provider['body']['$id'], 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Test Topic' @@ -837,7 +832,6 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'providerId' => $provider['body']['$id'], 'status' => 'draft', 'to' => [$topic['body']['$id']], 'content' => '047487', @@ -895,7 +889,6 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'providerId' => $provider['body']['$id'], 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Test Topic' @@ -947,7 +940,6 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'providerId' => $provider['body']['$id'], 'to' => [$topic['body']['$id']], 'title' => 'Test-Notification', 'body' => 'Test-Notification-Body', @@ -1009,7 +1001,6 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'providerId' => $provider['body']['$id'], 'topicId' => ID::unique(), 'name' => 'topic1', 'description' => 'Test Topic' @@ -1061,7 +1052,6 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'providerId' => $provider['body']['$id'], 'status' => 'draft', 'to' => [$topic['body']['$id']], 'title' => 'Test-Notification', From bc6df4bab71bbe79e035ce3e81e9a9e6c9343646 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 27 Oct 2023 13:42:27 +0530 Subject: [PATCH 139/196] add recipients array check in API instead of worker --- app/controllers/api/messaging.php | 12 ++++++------ src/Appwrite/Platform/Workers/Messaging.php | 5 ----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index b9bfbefdb7..1dbb371a7f 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1620,7 +1620,7 @@ App::post('/v1/messaging/messages/email') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(998), 'Email Subject.') ->param('content', '', new Text(64230), 'Email Content.') ->param('description', '', new Text(256), 'Description for message.', true) @@ -1673,7 +1673,7 @@ App::post('/v1/messaging/messages/sms') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('content', '', new Text(64230), 'SMS Content.') ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) @@ -1722,7 +1722,7 @@ App::post('/v1/messaging/messages/push') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('title', '', new Text(256), 'Title for push notification.') ->param('body', '', new Text(64230), 'Body for push notification.') ->param('description', '', new Text(256), 'Description for Message.', true) @@ -1878,7 +1878,7 @@ App::patch('/v1/messaging/messages/email/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) ->param('subject', '', new Text(998), 'Email Subject.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) @@ -1965,7 +1965,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) @@ -2042,7 +2042,7 @@ App::patch('/v1/messaging/messages/push/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('title', '', new Text(256), 'Title for push notification.', true) ->param('body', '', new Text(64230), 'Body for push notification.', true) diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 0c101b26e0..5ca5ebfc65 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -72,11 +72,6 @@ class Messaging extends Action { $recipientsId = $message->getAttribute('to', []); - if (\count($recipientsId) < 1) { - Console::error('Recipients not found'); - return; - } - /** * @var Document[] $recipients */ From 06daa544e892b6e8b2975a4226d3045d7fc1c96a Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 30 Oct 2023 23:37:57 +0530 Subject: [PATCH 140/196] review changes --- app/config/collections.php | 42 ++- app/config/errors.php | 5 + app/controllers/api/account.php | 8 +- app/controllers/api/messaging.php | 294 ++++++++++++++---- app/controllers/api/teams.php | 4 +- composer.lock | 2 +- src/Appwrite/Extend/Exception.php | 1 + src/Appwrite/Platform/Workers/Messaging.php | 43 ++- .../Database/Validator/Queries/Messages.php | 4 +- .../Database/Validator/Queries/Providers.php | 2 +- .../Utopia/Response/Model/Message.php | 22 +- .../Utopia/Response/Model/Provider.php | 2 +- .../Account/AccountCustomClientTest.php | 5 +- tests/e2e/Services/GraphQL/AccountTest.php | 1 - tests/e2e/Services/GraphQL/Base.php | 112 ++++--- tests/e2e/Services/GraphQL/MessagingTest.php | 24 +- .../e2e/Services/Messaging/MessagingBase.php | 24 +- 17 files changed, 421 insertions(+), 174 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 54b6b3bec3..cf21df2ebf 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1417,7 +1417,7 @@ $commonCollections = [ 'filters' => [], ], [ - '$id' => ID::custom('default'), + '$id' => ID::custom('internal'), 'type' => Database::VAR_BOOLEAN, 'signed' => true, 'size' => 0, @@ -1495,16 +1495,16 @@ $commonCollections = [ 'orders' => [Database::ORDER_ASC], ], [ - '$id' => ID::custom('_key_default'), + '$id' => ID::custom('_key_internal'), 'type' => Database::INDEX_KEY, - 'attributes' => ['default'], + 'attributes' => ['internal'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ - '$id' => ID::custom('_key_default_type'), + '$id' => ID::custom('_key_internal_type'), 'type' => Database::INDEX_KEY, - 'attributes' => ['default','type'], + 'attributes' => ['internal','type'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], @@ -1557,13 +1557,35 @@ $commonCollections = [ 'filters' => ['json'], ], [ - '$id' => ID::custom('to'), + '$id' => ID::custom('topics'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 65535, + 'size' => 21845, 'signed' => true, - 'required' => true, - 'default' => null, + 'required' => false, + 'default' => [], + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('users'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 21845, + 'signed' => true, + 'required' => false, + 'default' => [], + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('targets'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 21845, + 'signed' => true, + 'required' => false, + 'default' => [], 'array' => true, 'filters' => [], ], @@ -1601,7 +1623,7 @@ $commonCollections = [ 'filters' => [], ], [ - '$id' => ID::custom('deliveredTo'), + '$id' => ID::custom('deliveredTotal'), 'type' => Database::VAR_INTEGER, 'format' => '', 'size' => 0, diff --git a/app/config/errors.php b/app/config/errors.php index 50c59b23ec..931d24d65c 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -790,6 +790,11 @@ return [ 'description' => 'Message with the requested ID could not be found.', 'code' => 404, ], + Exception::MESSAGE_MISSING_TARGET => [ + 'name' => Exception::MESSAGE_MISSING_TARGET, + 'description' => 'Message with the requested ID is missing a target (Topics or Users or Targets).', + 'code' => 400, + ], Exception::MESSAGE_ALREADY_SENT => [ 'name' => Exception::MESSAGE_ALREADY_SENT, 'description' => 'Message with the requested ID has already been sent.', diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 4c7411d978..faa8623601 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1241,7 +1241,7 @@ App::post('/v1/account/sessions/phone') ->inject('locale') ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])); if ($provider === false || $provider->isEmpty()) { @@ -1347,7 +1347,7 @@ App::post('/v1/account/sessions/phone') $messageDoc = $dbForProject->createDocument('messages', new Document([ '$id' => $token->getId(), - 'to' => [$target->getId()], + 'targets' => [$target->getId()], 'data' => [ 'content' => $message, ], @@ -2914,7 +2914,7 @@ App::post('/v1/account/verification/phone') ->inject('locale') ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])); if ($provider === false || $provider->isEmpty()) { @@ -2980,7 +2980,7 @@ App::post('/v1/account/verification/phone') $messageDoc = $dbForProject->createDocument('messages', new Document([ '$id' => $verification->getId(), - 'to' => [$target->getId()], + 'targets' => [$target->getId()], 'data' => [ 'content' => $message, ], diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 1dbb371a7f..567c8e2cd6 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -69,14 +69,14 @@ App::post('/v1/messaging/providers/mailgun') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['email']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -127,14 +127,14 @@ App::post('/v1/messaging/providers/sendgrid') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -187,14 +187,14 @@ App::post('/v1/messaging/providers/msg91') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -247,14 +247,14 @@ App::post('/v1/messaging/providers/telesign') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -307,14 +307,14 @@ App::post('/v1/messaging/providers/textmagic') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -367,14 +367,14 @@ App::post('/v1/messaging/providers/twilio') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -427,14 +427,14 @@ App::post('/v1/messaging/providers/vonage') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -481,14 +481,14 @@ App::post('/v1/messaging/providers/fcm') ], ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['push']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -543,14 +543,14 @@ App::post('/v1/messaging/providers/apns') ], ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['push']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -647,13 +647,14 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('isEuRegion', null, new Boolean(), 'Set as eu region.', true) ->param('from', '', new Text(256), 'Sender email address.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -680,6 +681,10 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if ($isEuRegion === true || $isEuRegion === false) { @@ -698,6 +703,15 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -718,11 +732,12 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->param('from', '', new Text(256), 'Sender email address.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -749,6 +764,10 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + if (!empty($apiKey)) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, @@ -757,6 +776,15 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -777,12 +805,13 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $senderId, string $authKey, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $senderId, string $authKey, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -809,6 +838,10 @@ App::patch('/v1/messaging/providers/msg91/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($senderId)) { @@ -823,6 +856,15 @@ App::patch('/v1/messaging/providers/msg91/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -843,12 +885,13 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('username', '', new Text(0), 'Telesign username.', true) ->param('password', '', new Text(0), 'Telesign password.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $password, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $password, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -875,6 +918,10 @@ App::patch('/v1/messaging/providers/telesign/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -889,6 +936,15 @@ App::patch('/v1/messaging/providers/telesign/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -909,12 +965,13 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $apiKey, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $apiKey, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -941,6 +998,10 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -955,6 +1016,15 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -975,12 +1045,13 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $accountSid, string $authToken, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $accountSid, string $authToken, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1007,6 +1078,10 @@ App::patch('/v1/messaging/providers/twilio/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($accountSid)) { @@ -1021,6 +1096,15 @@ App::patch('/v1/messaging/providers/twilio/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1041,12 +1125,13 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $apiSecret, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $apiSecret, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1073,6 +1158,10 @@ App::patch('/v1/messaging/providers/vonage/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($apiKey)) { @@ -1087,6 +1176,15 @@ App::patch('/v1/messaging/providers/vonage/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1107,10 +1205,11 @@ App::patch('/v1/messaging/providers/fcm/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $serverKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1131,12 +1230,25 @@ App::patch('/v1/messaging/providers/fcm/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + if (!empty($serverKey)) { $provider->setAttribute('credentials', ['serverKey' => $serverKey]); } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1158,6 +1270,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('authKey', '', new Text(0), 'APNS authentication key.', true) ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) ->param('teamId', '', new Text(0), 'APNS team ID.', true) @@ -1165,7 +1278,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1186,6 +1299,10 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($authKey)) { @@ -1212,6 +1329,15 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1620,9 +1746,11 @@ App::post('/v1/messaging/messages/email') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(998), 'Email Subject.') ->param('content', '', new Text(64230), 'Email Content.') + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) @@ -1631,12 +1759,18 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $subject, string $content, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { + throw new Exception(Exception::MESSAGE_MISSING_TARGET); + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, - 'to' => $to, + 'topics' => $topics, + 'users' => $users, + 'targets' => $targets, 'description' => $description, 'data' => [ 'subject' => $subject, @@ -1673,8 +1807,10 @@ App::post('/v1/messaging/messages/sms') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('content', '', new Text(64230), 'SMS Content.') + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) @@ -1682,12 +1818,18 @@ App::post('/v1/messaging/messages/sms') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $content, string $description, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { + throw new Exception(Exception::MESSAGE_MISSING_TARGET); + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, - 'to' => $to, + 'topics' => $topics, + 'users' => $users, + 'targets' => $targets, 'description' => $description, 'data' => [ 'content' => $content, @@ -1722,9 +1864,11 @@ App::post('/v1/messaging/messages/push') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('title', '', new Text(256), 'Title for push notification.') ->param('body', '', new Text(64230), 'Body for push notification.') + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true) ->param('action', '', new Text(256), 'Action for push notification.', true) @@ -1739,9 +1883,13 @@ App::post('/v1/messaging/messages/push') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $title, string $body, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { + throw new Exception(Exception::MESSAGE_MISSING_TARGET); + } + $pushData = [ 'title' => $title, 'body' => $body, @@ -1777,7 +1925,9 @@ App::post('/v1/messaging/messages/push') $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, - 'to' => $to, + 'topics' => $topics, + 'users' => $users, + 'targets' => $targets, 'description' => $description, 'deliveryTime' => $deliveryTime, 'data' => $pushData, @@ -1878,7 +2028,9 @@ App::patch('/v1/messaging/messages/email/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('subject', '', new Text(998), 'Email Subject.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) @@ -1889,7 +2041,7 @@ App::patch('/v1/messaging/messages/email/:messageId') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $topics, array $users, array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -1904,8 +2056,16 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } - if (\count($to) > 0) { - $message->setAttribute('to', $to); + if (\count($topics) > 0) { + $message->setAttribute('topics', $topics); + } + + if (\count($users) > 0) { + $message->setAttribute('users', $users); + } + + if (\count($targets) > 0) { + $message->setAttribute('targets', $targets); } $data = $message->getAttribute('data'); @@ -1965,7 +2125,9 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) @@ -1974,7 +2136,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -1989,8 +2151,16 @@ App::patch('/v1/messaging/messages/sms/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } - if (\count($to) > 0) { - $message->setAttribute('to', $to); + if (\count($topics) > 0) { + $message->setAttribute('topics', $topics); + } + + if (\count($users) > 0) { + $message->setAttribute('users', $users); + } + + if (\count($targets) > 0) { + $message->setAttribute('targets', $targets); } $data = $message->getAttribute('data'); @@ -2042,7 +2212,9 @@ App::patch('/v1/messaging/messages/push/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('title', '', new Text(256), 'Title for push notification.', true) ->param('body', '', new Text(64230), 'Body for push notification.', true) @@ -2058,7 +2230,7 @@ App::patch('/v1/messaging/messages/push/:messageId') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2073,8 +2245,16 @@ App::patch('/v1/messaging/messages/push/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } - if (\count($to) > 0) { - $message->setAttribute('to', $to); + if (\count($topics) > 0) { + $message->setAttribute('topics', $topics); + } + + if (\count($users) > 0) { + $message->setAttribute('users', $users); + } + + if (\count($targets) > 0) { + $message->setAttribute('targets', $targets); } $pushData = $message->getAttribute('data'); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index da2261fd50..a0975634d5 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -633,7 +633,7 @@ App::post('/v1/teams/:teamId/memberships') ; } elseif (!empty($phone)) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])); @@ -662,7 +662,7 @@ App::post('/v1/teams/:teamId/memberships') $messageDoc = $dbForProject->createDocument('messages', new Document([ // Here membership ID is used as message ID so that it can be used in test cases to verify the message '$id' => $membership->getId(), - 'to' => [$target->getId()], + 'targets' => [$target->getId()], 'data' => [ 'content' => $message, ], diff --git a/composer.lock b/composer.lock index 66e5e5a11b..560dfe7b20 100644 --- a/composer.lock +++ b/composer.lock @@ -5822,5 +5822,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 8d6dc6d29a..cef64ffce5 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -241,6 +241,7 @@ class Exception extends \Exception /** Message */ public const MESSAGE_NOT_FOUND = 'message_not_found'; + public const MESSAGE_MISSING_TARGET = 'message_missing_target'; public const MESSAGE_ALREADY_SENT = 'message_already_sent'; public const MESSAGE_ALREADY_SCHEDULED = 'message_already_scheduled'; diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 5ca5ebfc65..a56c98b5e5 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -10,6 +10,7 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Adapters\SMS\Mock; use Utopia\Messaging\Adapters\SMS\Msg91; @@ -70,25 +71,33 @@ class Messaging extends Action private function processMessage(Database $dbForProject, Document $message): void { - $recipientsId = $message->getAttribute('to', []); + $topicsId = $message->getAttribute('topics', []); + $targetsId = $message->getAttribute('targets', []); + $usersId = $message->getAttribute('users', []); /** * @var Document[] $recipients */ $recipients = []; - $topics = $dbForProject->find('topics', [Query::equal('$id', $recipientsId)]); - foreach ($topics as $topic) { - $recipients = \array_merge($recipients, $topic->getAttribute('targets')); + if (\count($topicsId) > 0) { + $topics = $dbForProject->find('topics', [Query::equal('$id', $topicsId)]); + foreach ($topics as $topic) { + $recipients = \array_merge($recipients, $topic->getAttribute('targets')); + } } - $users = $dbForProject->find('users', [Query::equal('$id', $recipientsId)]); - foreach ($users as $user) { - $recipients = \array_merge($recipients, $user->getAttribute('targets')); + if (\count($usersId) > 0) { + $users = $dbForProject->find('users', [Query::equal('$id', $usersId)]); + foreach ($users as $user) { + $recipients = \array_merge($recipients, $user->getAttribute('targets')); + } } - $targets = $dbForProject->find('targets', [Query::equal('$id', $recipientsId)]); - $recipients = \array_merge($recipients, $targets); + if (\count($targetsId) > 0) { + $targets = $dbForProject->find('targets', [Query::equal('$id', $targetsId)]); + $recipients = \array_merge($recipients, $targets); + } $providers = []; foreach ($recipients as $recipient) { @@ -104,7 +113,7 @@ class Messaging extends Action */ $results = batch(\array_map(function ($providerId) use ($providers, $message, $dbForProject) { return function () use ($providerId, $providers, $message, $dbForProject) { - $provider = $dbForProject->getDocument('providers', $providerId); + $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); $identifiers = $providers[$providerId]; $adapter = match ($provider->getAttribute('type')) { 'sms' => $this->sms($provider), @@ -118,7 +127,7 @@ class Messaging extends Action $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex) { return function () use ($batch, $message, $provider, $adapter, $batchIndex) { - $deliveredTo = 0; + $deliveredTotal = 0; $deliveryErrors = []; $messageData = clone $message; $messageData->setAttribute('to', $batch); @@ -130,13 +139,13 @@ class Messaging extends Action }; try { $adapter->send($data); - $deliveredTo += \count($batch); + $deliveredTotal += \count($batch); } catch (\Exception $e) { $deliveryErrors[] = 'Failed sending to targets ' . $batchIndex + 1 . '-' . \count($batch) . ' with error: ' . $e->getMessage(); } finally { $batchIndex++; return [ - 'deliveredTo' => $deliveredTo, + 'deliveredTotal' => $deliveredTotal, 'deliveryErrors' => $deliveryErrors, ]; } @@ -149,10 +158,10 @@ class Messaging extends Action $results = array_merge(...$results); - $deliveredTo = 0; + $deliveredTotal = 0; $deliveryErrors = []; foreach ($results as $result) { - $deliveredTo += $result['deliveredTo']; + $deliveredTotal += $result['deliveredTotal']; $deliveryErrors = \array_merge($deliveryErrors, $result['deliveryErrors']); } $message->setAttribute('deliveryErrors', $deliveryErrors); @@ -162,8 +171,8 @@ class Messaging extends Action } else { $message->setAttribute('status', 'sent'); } - $message->setAttribute('to', $recipientsId); - $message->setAttribute('deliveredTo', $deliveredTo); + $message->removeAttribute('to'); + $message->setAttribute('deliveredTotal', $deliveredTotal); $message->setAttribute('deliveredAt', DateTime::now()); $dbForProject->updateDocument('messages', $message->getId(), $message); diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php index 4bff13ae19..dd043474a8 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php @@ -5,7 +5,9 @@ namespace Appwrite\Utopia\Database\Validator\Queries; class Messages extends Base { public const ALLOWED_ATTRIBUTES = [ - 'to', + 'topics', + 'users', + 'targets', 'providerId', 'deliveredAt', 'deliveredTo', diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php index 1fd6c9e9f8..7760acbdad 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php @@ -8,7 +8,7 @@ class Providers extends Base 'name', 'provider', 'type', - 'default', + 'internal', 'enabled', ]; diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 609aa4022e..7816c4bf5d 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -17,12 +17,26 @@ class Message extends Any 'default' => '', 'example' => '5e5ea5c16897e', ]) - ->addRule('to', [ + ->addRule('topics', [ 'type' => self::TYPE_STRING, - 'description' => 'Message recipients.', + 'description' => 'Topic IDs set as recipients.', 'default' => '', 'array' => true, - 'example' => ['user-1'], + 'example' => ['5e5ea5c16897e'], + ]) + ->addRule('users', [ + 'type' => self::TYPE_STRING, + 'description' => 'User IDs set as recipients.', + 'default' => '', + 'array' => true, + 'example' => ['5e5ea5c16897e'], + ]) + ->addRule('targets', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target IDs set as recipients.', + 'default' => '', + 'array' => true, + 'example' => ['5e5ea5c16897e'], ]) ->addRule('deliveryTime', [ 'type' => self::TYPE_DATETIME, @@ -46,7 +60,7 @@ class Message extends Any 'array' => true, 'example' => ['Failed to send message to target 5e5ea5c16897e: Credentials not valid.'], ]) - ->addRule('deliveredTo', [ + ->addRule('deliveredTotal', [ 'type' => self::TYPE_INTEGER, 'description' => 'Number of recipients the message was delivered to.', 'default' => 0, diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index 552e9783e8..ba522951e7 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -28,7 +28,7 @@ class Provider extends Model 'default' => '', 'example' => 'mailgun', ]) - ->addRule('default', [ + ->addRule('internal', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Is this a pre-configured provider instance?', 'default' => false, diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 7f4cb84b05..c138f4049a 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -762,7 +762,6 @@ class AccountCustomClientTest extends Scope 'name' => 'Sms provider', 'senderId' => $senderId, 'authKey' => $authKey, - 'default' => true, 'from' => $from, ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -810,7 +809,7 @@ class AccountCustomClientTest extends Scope ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); @@ -1040,7 +1039,7 @@ class AccountCustomClientTest extends Scope ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); return \array_merge($data, [ diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 801be808c9..e42fe1bc6c 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -142,7 +142,6 @@ class AccountTest extends Scope 'from' => $from, 'senderId' => $senderId, 'authKey' => $authKey, - 'default' => true, ], ]; diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index bf6ae84f7f..45fc148497 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1790,7 +1790,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1801,7 +1801,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1812,7 +1812,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1823,7 +1823,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1834,7 +1834,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1845,7 +1845,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1856,7 +1856,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1867,7 +1867,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1878,7 +1878,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1891,7 +1891,7 @@ trait Base name provider type - default + internal enabled } } @@ -1903,7 +1903,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1914,7 +1914,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1925,7 +1925,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1936,7 +1936,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1947,7 +1947,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1958,7 +1958,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1969,7 +1969,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1980,7 +1980,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1991,7 +1991,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -2002,7 +2002,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -2087,40 +2087,46 @@ trait Base } }'; case self::$CREATE_EMAIL: - return 'mutation createEmail($messageId: String!, $to: [String!]!, $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { - messagingCreateEmail(messageId: $messageId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + return 'mutation createEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { + messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$CREATE_SMS: - return 'mutation createSMS($messageId: String!, $to: [String!]!, $content: String!, $status: String, $description: String, $deliveryTime: String) { - messagingCreateSMS(messageId: $messageId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation createSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String!, $status: String, $description: String, $deliveryTime: String) { + messagingCreateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$CREATE_PUSH_NOTIFICATION: - return 'mutation createPushNotification($messageId: String!, $to: [String!]!, $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { - messagingCreatePushNotification(messageId: $messageId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation createPushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { + messagingCreatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } @@ -2131,11 +2137,13 @@ trait Base total messages { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } @@ -2145,50 +2153,58 @@ trait Base return 'query getMessage($messageId: String!) { messagingGetMessage(messageId: $messageId) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$UPDATE_EMAIL: - return 'mutation updateEmail($messageId: String!, $to: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { - messagingUpdateEmail(messageId: $messageId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + return 'mutation updateEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { + messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$UPDATE_SMS: - return 'mutation updateSMS($messageId: String!, $to: [String!], $content: String, $status: String, $description: String, $deliveryTime: String) { - messagingUpdateSMS(messageId: $messageId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation updateSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String, $status: String, $description: String, $deliveryTime: String) { + messagingUpdateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$UPDATE_PUSH_NOTIFICATION: - return 'mutation updatePushNotification($messageId: String!, $to: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { - messagingUpdatePushNotification(messageId: $messageId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation updatePushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { + messagingUpdatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 82f697f7ec..004f7b2ec0 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -631,7 +631,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ], @@ -660,7 +660,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); return $message['body']['data']['messagingGetMessage']; @@ -777,7 +777,7 @@ class MessagingTest extends Scope 'variables' => [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ], @@ -822,7 +822,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); } @@ -931,7 +931,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'content' => '454665', ], ]; @@ -959,7 +959,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); return $message['body']['data']['messagingGetMessage']; } @@ -1073,7 +1073,7 @@ class MessagingTest extends Scope 'variables' => [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'content' => '345463', ], ]; @@ -1117,7 +1117,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); } @@ -1222,7 +1222,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'title' => 'Push Notification Title', 'body' => 'Push Notifiaction Body', ], @@ -1251,7 +1251,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); return $message['body']['data']['messagingGetMessage']; @@ -1361,7 +1361,7 @@ class MessagingTest extends Scope 'variables' => [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'title' => 'Push Notification Title', 'body' => 'Push Notifiaction Body', ], @@ -1406,7 +1406,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); } } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 01138c6412..b3a075d579 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -486,7 +486,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ]); @@ -503,7 +503,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); return $message; @@ -605,7 +605,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ]); @@ -632,7 +632,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } @@ -717,7 +717,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'content' => '064763', ]); @@ -733,7 +733,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); return $message; @@ -833,7 +833,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'content' => '047487', ]); @@ -859,7 +859,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } @@ -940,7 +940,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'title' => 'Test-Notification', 'body' => 'Test-Notification-Body', ]); @@ -957,7 +957,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); return $message; @@ -1053,7 +1053,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'title' => 'Test-Notification', 'body' => 'Test-Notification-Body', ]); @@ -1080,7 +1080,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } } From a01d361886d728b5e985e8cdd6c5e53546d1e024 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 31 Oct 2023 01:12:31 +0530 Subject: [PATCH 141/196] review changes --- app/config/collections.php | 2 +- app/controllers/api/messaging.php | 13 +++++++++++++ tests/e2e/Services/Messaging/MessagingBase.php | 4 +++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index cf21df2ebf..33a60fce44 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1728,7 +1728,7 @@ $commonCollections = [ [ '$id' => ID::custom('_key_search'), 'type' => Database::INDEX_FULLTEXT, - 'attributes' => ['name'], + 'attributes' => ['search'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], ] diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 567c8e2cd6..0147e472bb 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1400,6 +1400,9 @@ App::post('/v1/messaging/topics') if ($description) { $topic->setAttribute('description', $description); + $topic->setAttribute('search', $topic->getId() . ' ' . $name . ' ' . $description); + } else { + $topic->setAttribute('search', $topic->getId() . ' ' . $name); } try { @@ -1516,6 +1519,16 @@ App::patch('/v1/messaging/topics/:topicId') $topic->setAttribute('description', $description); } + if (!empty($name) || !empty($description)) { + if (!empty($name) && !empty($description)) { + $topic->setAttribute('search', $topic->getId() . ' ' . $name . ' ' . $description); + } elseif (!empty($name)) { + $topic->setAttribute('search', $topic->getId() . ' ' . $name . ' ' . $topic->getAttribute('description')); + } else { + $topic->setAttribute('search', $topic->getId() . ' ' . $topic->getAttribute('name') . ' ' . $description); + } + } + $topic = $dbForProject->updateDocument('topics', $topicId, $topic); $response diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index b3a075d579..65e196db30 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -223,7 +223,7 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'topicId' => 'unique()', + 'topicId' => ID::unique(), 'name' => 'my-app', 'description' => 'web app' ]); @@ -258,6 +258,8 @@ trait MessagingBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'search' => 'updated-description', ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, \count($response['body']['topics'])); From 0dafc59cc2c2c127081e8fad7da8375fc7fd71a9 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 31 Oct 2023 02:05:50 +0530 Subject: [PATCH 142/196] converted env vars to dsn format --- .env | 14 +---- docker-compose.yml | 14 +---- .../Account/AccountCustomClientTest.php | 10 ++-- tests/e2e/Services/GraphQL/AccountTest.php | 10 ++-- tests/e2e/Services/GraphQL/MessagingTest.php | 57 ++++++++++++------- .../e2e/Services/Messaging/MessagingBase.php | 57 ++++++++++++------- 6 files changed, 88 insertions(+), 74 deletions(-) diff --git a/.env b/.env index 127efd2e4a..07d953af57 100644 --- a/.env +++ b/.env @@ -99,14 +99,6 @@ _APP_VCS_GITHUB_WEBHOOK_SECRET= _APP_MIGRATIONS_FIREBASE_CLIENT_ID= _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET= _APP_ASSISTANT_OPENAI_API_KEY= -_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID= -_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY= -_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM= -_APP_MESSAGE_SMS_PROVIDER_MSG91_TO= -_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY= -_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN= -_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM= -_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL= -_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION= -_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY= -_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN= +_APP_MESSAGE_SMS_TEST_DSN= +_APP_MESSAGE_EMAIL_TEST_DSN= +_APP_MESSAGE_PUSH_TEST_DSN= diff --git a/docker-compose.yml b/docker-compose.yml index c0013f7385..94e8a8bd7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -188,17 +188,9 @@ services: - _APP_MIGRATIONS_FIREBASE_CLIENT_ID - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET - _APP_ASSISTANT_OPENAI_API_KEY - - _APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID - - _APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY - - _APP_MESSAGE_SMS_PROVIDER_MSG91_FROM - - _APP_MESSAGE_SMS_PROVIDER_MSG91_TO - - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY - - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN - - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM - - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL - - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION - - _APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY - - _APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN + - _APP_MESSAGE_SMS_TEST_DSN + - _APP_MESSAGE_EMAIL_TEST_DSN + - _APP_MESSAGE_PUSH_TEST_DSN appwrite-realtime: entrypoint: realtime <<: *x-logging diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index c138f4049a..1e716fc634 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -11,6 +11,7 @@ use Utopia\App; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; +use Utopia\DSN\DSN; use function sleep; @@ -743,10 +744,11 @@ class AccountCustomClientTest extends Scope public function testCreatePhone(): array { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); - $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); - $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); - $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); + $to = $smsDSN->getParam('to'); + $from = $smsDSN->getParam('from'); + $authKey = $smsDSN->getPassword(); + $senderId = $smsDSN->getUser(); if (empty($to) || empty($from) || empty($authKey) || empty($senderId)) { $this->markTestSkipped('SMS provider not configured'); diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index e42fe1bc6c..292d7d7db4 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -8,6 +8,7 @@ use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\App; use Utopia\Database\Helpers\ID; +use Utopia\DSN\DSN; class AccountTest extends Scope { @@ -123,10 +124,11 @@ class AccountTest extends Scope */ public function testCreatePhoneVerification(): array { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); - $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); - $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); - $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); + $to = $smsDSN->getParam('to'); + $from = $smsDSN->getParam('from'); + $authKey = $smsDSN->getPassword(); + $senderId = $smsDSN->getUser(); if (empty($to) || empty($from) || empty($authKey) || empty($senderId)) { $this->markTestSkipped('SMS provider not configured'); diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 004f7b2ec0..892fb51dce 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -8,6 +8,7 @@ use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; use Utopia\App; use Utopia\Database\Helpers\ID; +use Utopia\DSN\DSN; class MessagingTest extends Scope { @@ -526,11 +527,13 @@ class MessagingTest extends Scope public function testSendEmail() { - $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); - $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); - $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); - $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); - $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); + $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); + $to = $emailDSN->getParam('to'); + $from = $emailDSN->getParam('from'); + $isEuRegion = $emailDSN->getParam('isEuRegion'); + $apiKey = $emailDSN->getPassword(); + $domain = $emailDSN->getUser(); + if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { $this->markTestSkipped('Email provider not configured'); } @@ -671,11 +674,13 @@ class MessagingTest extends Scope */ public function testUpdateEmail(array $email) { - $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); - $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); - $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); - $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); - $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); + $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); + $to = $emailDSN->getParam('to'); + $from = $emailDSN->getParam('from'); + $isEuRegion = $emailDSN->getParam('isEuRegion'); + $apiKey = $emailDSN->getPassword(); + $domain = $emailDSN->getUser(); + if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { $this->markTestSkipped('Email provider not configured'); } @@ -828,10 +833,12 @@ class MessagingTest extends Scope public function testSendSMS() { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); - $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); - $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); - $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); + $to = $smsDSN->getParam('to'); + $from = $smsDSN->getParam('from'); + $authKey = $smsDSN->getPassword(); + $senderId = $smsDSN->getUser(); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { $this->markTestSkipped('SMS provider not configured'); } @@ -969,10 +976,12 @@ class MessagingTest extends Scope */ public function testUpdateSMS(array $sms) { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); - $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); - $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); - $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); + $to = $smsDSN->getParam('to'); + $from = $smsDSN->getParam('from'); + $authKey = $smsDSN->getPassword(); + $senderId = $smsDSN->getUser(); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { $this->markTestSkipped('SMS provider not configured'); } @@ -1123,8 +1132,10 @@ class MessagingTest extends Scope public function testSendPushNotification() { - $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); - $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); + $to = $pushDSN->getParam('to'); + $serverKey = $pushDSN->getPassword(); + if (empty($to) || empty($serverKey)) { $this->markTestSkipped('Push provider not configured'); } @@ -1262,8 +1273,10 @@ class MessagingTest extends Scope */ public function testUpdatePushNotification(array $push) { - $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); - $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); + $to = $pushDSN->getParam('to'); + $serverKey = $pushDSN->getPassword(); + if (empty($to) || empty($serverKey)) { $this->markTestSkipped('Push provider not configured'); } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 65e196db30..720de96052 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -5,6 +5,7 @@ namespace Tests\E2E\Services\Messaging; use Tests\E2E\Client; use Utopia\App; use Utopia\Database\Helpers\ID; +use Utopia\DSN\DSN; trait MessagingBase { @@ -407,11 +408,13 @@ trait MessagingBase public function testSendEmail() { - $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); - $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); - $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); - $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); - $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); + $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); + $to = $emailDSN->getParam('to'); + $from = $emailDSN->getParam('from'); + $isEuRegion = $emailDSN->getParam('isEuRegion'); + $apiKey = $emailDSN->getPassword(); + $domain = $emailDSN->getUser(); + if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { $this->markTestSkipped('Email provider not configured'); } @@ -516,11 +519,13 @@ trait MessagingBase */ public function testUpdateEmail(array $email) { - $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); - $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); - $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); - $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); - $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); + $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); + $to = $emailDSN->getParam('to'); + $from = $emailDSN->getParam('from'); + $isEuRegion = $emailDSN->getParam('isEuRegion'); + $apiKey = $emailDSN->getPassword(); + $domain = $emailDSN->getUser(); + if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { $this->markTestSkipped('Email provider not configured'); } @@ -640,10 +645,12 @@ trait MessagingBase public function testSendSMS() { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); - $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); - $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); - $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); + $to = $smsDSN->getParam('to'); + $from = $smsDSN->getParam('from'); + $authKey = $smsDSN->getPassword(); + $senderId = $smsDSN->getUser(); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { $this->markTestSkipped('SMS provider not configured'); } @@ -746,10 +753,12 @@ trait MessagingBase */ public function testUpdateSMS(array $sms) { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); - $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); - $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); - $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); + $to = $smsDSN->getParam('to'); + $from = $smsDSN->getParam('from'); + $authKey = $smsDSN->getPassword(); + $senderId = $smsDSN->getUser(); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { $this->markTestSkipped('SMS provider not configured'); } @@ -867,8 +876,10 @@ trait MessagingBase public function testSendPushNotification() { - $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); - $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); + $to = $pushDSN->getParam('to'); + $serverKey = $pushDSN->getPassword(); + if (empty($to) || empty($serverKey)) { $this->markTestSkipped('Push provider not configured'); } @@ -970,8 +981,10 @@ trait MessagingBase */ public function testUpdatePushNotification(array $push) { - $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); - $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); + $to = $pushDSN->getParam('to'); + $serverKey = $pushDSN->getPassword(); + if (empty($to) || empty($serverKey)) { $this->markTestSkipped('Push provider not configured'); } From a4c8d852a5c21aad931275e0d304cb599e8a5d65 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 31 Oct 2023 02:34:18 +0530 Subject: [PATCH 143/196] adds test skip condition if dsn not provided --- .../Account/AccountCustomClientTest.php | 4 ++++ tests/e2e/Services/GraphQL/AccountTest.php | 4 ++++ tests/e2e/Services/GraphQL/MessagingTest.php | 24 +++++++++++++++++++ .../e2e/Services/Messaging/MessagingBase.php | 24 +++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 1e716fc634..336d6f317c 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -744,6 +744,10 @@ class AccountCustomClientTest extends Scope public function testCreatePhone(): array { + if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { + $this->markTestSkipped('SMS DSN not provided'); + } + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); $to = $smsDSN->getParam('to'); $from = $smsDSN->getParam('from'); diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 292d7d7db4..9d1da09feb 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -124,6 +124,10 @@ class AccountTest extends Scope */ public function testCreatePhoneVerification(): array { + if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { + $this->markTestSkipped('SMS DSN not provided'); + } + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); $to = $smsDSN->getParam('to'); $from = $smsDSN->getParam('from'); diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 892fb51dce..c0322372ba 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -527,6 +527,10 @@ class MessagingTest extends Scope public function testSendEmail() { + if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) { + $this->markTestSkipped('Email DSN not provided'); + } + $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); $to = $emailDSN->getParam('to'); $from = $emailDSN->getParam('from'); @@ -674,6 +678,10 @@ class MessagingTest extends Scope */ public function testUpdateEmail(array $email) { + if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) { + $this->markTestSkipped('Email DSN not provided'); + } + $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); $to = $emailDSN->getParam('to'); $from = $emailDSN->getParam('from'); @@ -833,6 +841,10 @@ class MessagingTest extends Scope public function testSendSMS() { + if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { + $this->markTestSkipped('SMS DSN not provided'); + } + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); $to = $smsDSN->getParam('to'); $from = $smsDSN->getParam('from'); @@ -976,6 +988,10 @@ class MessagingTest extends Scope */ public function testUpdateSMS(array $sms) { + if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { + $this->markTestSkipped('SMS DSN not provided'); + } + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); $to = $smsDSN->getParam('to'); $from = $smsDSN->getParam('from'); @@ -1132,6 +1148,10 @@ class MessagingTest extends Scope public function testSendPushNotification() { + if (empty(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'))) { + $this->markTestSkipped('Push DSN empty'); + } + $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); $to = $pushDSN->getParam('to'); $serverKey = $pushDSN->getPassword(); @@ -1273,6 +1293,10 @@ class MessagingTest extends Scope */ public function testUpdatePushNotification(array $push) { + if (empty(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'))) { + $this->markTestSkipped('Push DSN empty'); + } + $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); $to = $pushDSN->getParam('to'); $serverKey = $pushDSN->getPassword(); diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 720de96052..221617a1d1 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -408,6 +408,10 @@ trait MessagingBase public function testSendEmail() { + if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) { + $this->markTestSkipped('Email DSN not provided'); + } + $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); $to = $emailDSN->getParam('to'); $from = $emailDSN->getParam('from'); @@ -519,6 +523,10 @@ trait MessagingBase */ public function testUpdateEmail(array $email) { + if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) { + $this->markTestSkipped('Email DSN not provided'); + } + $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); $to = $emailDSN->getParam('to'); $from = $emailDSN->getParam('from'); @@ -645,6 +653,10 @@ trait MessagingBase public function testSendSMS() { + if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { + $this->markTestSkipped('SMS DSN not provided'); + } + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); $to = $smsDSN->getParam('to'); $from = $smsDSN->getParam('from'); @@ -753,6 +765,10 @@ trait MessagingBase */ public function testUpdateSMS(array $sms) { + if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { + $this->markTestSkipped('SMS DSN not provided'); + } + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); $to = $smsDSN->getParam('to'); $from = $smsDSN->getParam('from'); @@ -876,6 +892,10 @@ trait MessagingBase public function testSendPushNotification() { + if (empty(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'))) { + $this->markTestSkipped('Push DSN empty'); + } + $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); $to = $pushDSN->getParam('to'); $serverKey = $pushDSN->getPassword(); @@ -981,6 +1001,10 @@ trait MessagingBase */ public function testUpdatePushNotification(array $push) { + if (empty(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'))) { + $this->markTestSkipped('Push DSN empty'); + } + $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); $to = $pushDSN->getParam('to'); $serverKey = $pushDSN->getPassword(); From a58f473b29b7d86a1bdaa3eab0fac6ca851d63d1 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 31 Oct 2023 14:01:42 +0530 Subject: [PATCH 144/196] adds createdAt and updatedAt in messaging models --- src/Appwrite/Utopia/Response/Model/Message.php | 12 ++++++++++++ src/Appwrite/Utopia/Response/Model/Provider.php | 12 ++++++++++++ src/Appwrite/Utopia/Response/Model/Subscriber.php | 12 ++++++++++++ src/Appwrite/Utopia/Response/Model/Target.php | 12 ++++++++++++ src/Appwrite/Utopia/Response/Model/Topic.php | 12 ++++++++++++ 5 files changed, 60 insertions(+) diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 7816c4bf5d..0341ebdfa0 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -17,6 +17,18 @@ class Message extends Any 'default' => '', 'example' => '5e5ea5c16897e', ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket creation time in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) ->addRule('topics', [ 'type' => self::TYPE_STRING, 'description' => 'Topic IDs set as recipients.', diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index ba522951e7..3f1e2d6c6b 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -16,6 +16,18 @@ class Provider extends Model 'default' => '', 'example' => '5e5ea5c16897e', ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket creation time in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) ->addRule('name', [ 'type' => self::TYPE_STRING, 'description' => 'The name for the provider instance.', diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index 2f34619cb4..68bb4ef180 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -16,6 +16,18 @@ class Subscriber extends Model 'default' => '', 'example' => '259125845563242502', ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket creation time in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) ->addRule('targetId', [ 'type' => self::TYPE_STRING, 'description' => 'Target ID.', diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php index 5750f57eba..4547e25e54 100644 --- a/src/Appwrite/Utopia/Response/Model/Target.php +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -16,6 +16,18 @@ class Target extends Model 'default' => '', 'example' => '259125845563242502', ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket creation time in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) ->addRule('userId', [ 'type' => self::TYPE_STRING, 'description' => 'User ID.', diff --git a/src/Appwrite/Utopia/Response/Model/Topic.php b/src/Appwrite/Utopia/Response/Model/Topic.php index d46d26597d..9f8c378576 100644 --- a/src/Appwrite/Utopia/Response/Model/Topic.php +++ b/src/Appwrite/Utopia/Response/Model/Topic.php @@ -16,6 +16,18 @@ class Topic extends Model 'default' => '', 'example' => '259125845563242502', ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket creation time in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Bucket update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) ->addRule('name', [ 'type' => self::TYPE_STRING, 'description' => 'The name of the topic.', From a719c3f46b0a2ac5e07af0ca8446062ac292039a Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 31 Oct 2023 23:17:58 +0530 Subject: [PATCH 145/196] adds event label to create providers endpoint --- app/controllers/api/messaging.php | 65 ++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 0147e472bb..abf97ce34d 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1,6 +1,7 @@ groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[provider].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -47,9 +49,10 @@ App::post('/v1/messaging/providers/mailgun') ->param('domain', '', new Text(0), 'Mailgun Domain.') ->param('isEuRegion', false, new Boolean(), 'Set as EU region.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $apiKey, string $domain, bool $isEuRegion, bool $enabled, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, string $domain, bool $isEuRegion, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ @@ -85,6 +88,9 @@ App::post('/v1/messaging/providers/mailgun') throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('provider', 'mailgun'); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -95,6 +101,7 @@ App::post('/v1/messaging/providers/sendgrid') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[provider].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -108,9 +115,10 @@ App::post('/v1/messaging/providers/sendgrid') ->param('from', '', new Text(256), 'Sender email address.') ->param('apiKey', '', new Text(0), 'Sendgrid API key.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $apiKey, bool $enabled, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -143,6 +151,9 @@ App::post('/v1/messaging/providers/sendgrid') throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('provider', 'sendgrid'); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -154,6 +165,7 @@ App::post('/v1/messaging/providers/msg91') ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') + ->label('event', 'providers.[provider].create') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createMsg91Provider') @@ -167,9 +179,10 @@ App::post('/v1/messaging/providers/msg91') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $senderId, string $authKey, bool $enabled, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $senderId, string $authKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -203,6 +216,9 @@ App::post('/v1/messaging/providers/msg91') throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('provider', 'msg91'); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -213,6 +229,7 @@ App::post('/v1/messaging/providers/telesign') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[provider].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -227,9 +244,10 @@ App::post('/v1/messaging/providers/telesign') ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $username, string $password, bool $enabled, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $username, string $password, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -263,6 +281,9 @@ App::post('/v1/messaging/providers/telesign') throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('provider', 'telesign'); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -273,6 +294,8 @@ App::post('/v1/messaging/providers/textmagic') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') + ->inject('queueForEvents') + ->label('event', 'providers.[provider].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -287,9 +310,10 @@ App::post('/v1/messaging/providers/textmagic') ->param('username', '', new Text(0), 'Textmagic username.') ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $username, string $apiKey, bool $enabled, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $username, string $apiKey, bool $enabled, Event $queueForEvents Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -323,6 +347,9 @@ App::post('/v1/messaging/providers/textmagic') throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('provider', 'textmagic'); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -333,6 +360,7 @@ App::post('/v1/messaging/providers/twilio') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[provider].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -347,9 +375,10 @@ App::post('/v1/messaging/providers/twilio') ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $accountSid, string $authToken, bool $enabled, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $accountSid, string $authToken, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -383,6 +412,9 @@ App::post('/v1/messaging/providers/twilio') throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('provider', 'twilio'); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -393,6 +425,7 @@ App::post('/v1/messaging/providers/vonage') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[provider].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -407,9 +440,10 @@ App::post('/v1/messaging/providers/vonage') ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $apiKey, string $apiSecret, bool $enabled, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, string $apiSecret, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -443,6 +477,9 @@ App::post('/v1/messaging/providers/vonage') throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('provider', 'vonage'); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -453,6 +490,7 @@ App::post('/v1/messaging/providers/fcm') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[provider].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -465,9 +503,10 @@ App::post('/v1/messaging/providers/fcm') ->param('name', '', new Text(128), 'Provider name.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('serverKey', '', new Text(0), 'FCM server key.') + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $serverKey, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -497,6 +536,9 @@ App::post('/v1/messaging/providers/fcm') throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('provider', 'fcm'); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); @@ -507,6 +549,7 @@ App::post('/v1/messaging/providers/apns') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[provider].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -523,9 +566,10 @@ App::post('/v1/messaging/providers/apns') ->param('teamId', '', new Text(0), 'APNS team ID.') ->param('bundleId', '', new Text(0), 'APNS bundle ID.') ->param('endpoint', '', new Text(0), 'APNS endpoint.') + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -559,6 +603,9 @@ App::post('/v1/messaging/providers/apns') throw new Exception(Exception::PROVIDER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('provider', 'apns'); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($provider, Response::MODEL_PROVIDER); From f7529140bd648f157adb278f8d7003dcedef4aae Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 31 Oct 2023 23:53:46 +0530 Subject: [PATCH 146/196] adds event label to remaining messaging api --- app/controllers/api/messaging.php | 191 +++++++++++++++++++++++------- app/controllers/api/users.php | 26 +++- 2 files changed, 171 insertions(+), 46 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index abf97ce34d..46675dc5f0 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -33,7 +33,7 @@ App::post('/v1/messaging/providers/mailgun') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') - ->label('event', 'providers.[provider].create') + ->label('event', 'providers.[providerId].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -89,7 +89,7 @@ App::post('/v1/messaging/providers/mailgun') } $queueForEvents - ->setParam('provider', 'mailgun'); + ->setParam('providerId', $provider->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -101,7 +101,7 @@ App::post('/v1/messaging/providers/sendgrid') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') - ->label('event', 'providers.[provider].create') + ->label('event', 'providers.[providerId].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -152,7 +152,7 @@ App::post('/v1/messaging/providers/sendgrid') } $queueForEvents - ->setParam('provider', 'sendgrid'); + ->setParam('providerId', $provider->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -165,7 +165,7 @@ App::post('/v1/messaging/providers/msg91') ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') - ->label('event', 'providers.[provider].create') + ->label('event', 'providers.[providerId].create') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'createMsg91Provider') @@ -217,7 +217,7 @@ App::post('/v1/messaging/providers/msg91') } $queueForEvents - ->setParam('provider', 'msg91'); + ->setParam('providerId', $provider->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -229,7 +229,7 @@ App::post('/v1/messaging/providers/telesign') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') - ->label('event', 'providers.[provider].create') + ->label('event', 'providers.[providerId].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -282,7 +282,7 @@ App::post('/v1/messaging/providers/telesign') } $queueForEvents - ->setParam('provider', 'telesign'); + ->setParam('providerId', $provider->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -295,7 +295,7 @@ App::post('/v1/messaging/providers/textmagic') ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') ->inject('queueForEvents') - ->label('event', 'providers.[provider].create') + ->label('event', 'providers.[providerId].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -313,7 +313,7 @@ App::post('/v1/messaging/providers/textmagic') ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $username, string $apiKey, bool $enabled, Event $queueForEvents Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $username, string $apiKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -348,7 +348,7 @@ App::post('/v1/messaging/providers/textmagic') } $queueForEvents - ->setParam('provider', 'textmagic'); + ->setParam('providerId', $provider->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -360,7 +360,7 @@ App::post('/v1/messaging/providers/twilio') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') - ->label('event', 'providers.[provider].create') + ->label('event', 'providers.[providerId].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -413,7 +413,7 @@ App::post('/v1/messaging/providers/twilio') } $queueForEvents - ->setParam('provider', 'twilio'); + ->setParam('providerId', $provider->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -425,7 +425,7 @@ App::post('/v1/messaging/providers/vonage') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') - ->label('event', 'providers.[provider].create') + ->label('event', 'providers.[providerId].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -478,7 +478,7 @@ App::post('/v1/messaging/providers/vonage') } $queueForEvents - ->setParam('provider', 'vonage'); + ->setParam('providerId', $provider->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -490,7 +490,7 @@ App::post('/v1/messaging/providers/fcm') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') - ->label('event', 'providers.[provider].create') + ->label('event', 'providers.[providerId].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -537,7 +537,7 @@ App::post('/v1/messaging/providers/fcm') } $queueForEvents - ->setParam('provider', 'fcm'); + ->setParam('providerId', $provider->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -549,7 +549,7 @@ App::post('/v1/messaging/providers/apns') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') - ->label('event', 'providers.[provider].create') + ->label('event', 'providers.[providerId].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -604,7 +604,7 @@ App::post('/v1/messaging/providers/apns') } $queueForEvents - ->setParam('provider', 'apns'); + ->setParam('providerId', $provider->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -683,6 +683,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[providerId].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -699,9 +700,10 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->param('from', '', new Text(256), 'Sender email address.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -759,6 +761,9 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); } + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -768,6 +773,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[providerId].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -782,9 +788,10 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->param('from', '', new Text(256), 'Sender email address.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -832,6 +839,9 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); } + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -841,6 +851,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[provider].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -856,9 +867,10 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) ->param('from', '', new Text(256), 'Sender number.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $senderId, string $authKey, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $senderId, string $authKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -912,6 +924,9 @@ App::patch('/v1/messaging/providers/msg91/:providerId') $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); } + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -921,6 +936,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[providerId].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -936,9 +952,10 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ->param('username', '', new Text(0), 'Telesign username.', true) ->param('password', '', new Text(0), 'Telesign password.', true) ->param('from', '', new Text(256), 'Sender number.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $password, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $password, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -992,6 +1009,9 @@ App::patch('/v1/messaging/providers/telesign/:providerId') $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); } + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1001,6 +1021,7 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[providerId].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1016,9 +1037,10 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) ->param('from', '', new Text(256), 'Sender number.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $apiKey, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1072,6 +1094,9 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); } + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1081,6 +1106,7 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[providerId].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1096,9 +1122,10 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) ->param('from', '', new Text(256), 'Sender number.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $accountSid, string $authToken, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $accountSid, string $authToken, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1152,6 +1179,9 @@ App::patch('/v1/messaging/providers/twilio/:providerId') $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); } + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1161,6 +1191,7 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[providerId].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1176,9 +1207,10 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) ->param('from', '', new Text(256), 'Sender number.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $apiSecret, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $apiSecret, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1232,6 +1264,9 @@ App::patch('/v1/messaging/providers/vonage/:providerId') $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); } + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1241,6 +1276,7 @@ App::patch('/v1/messaging/providers/fcm/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[providerId].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1254,9 +1290,10 @@ App::patch('/v1/messaging/providers/fcm/:providerId') ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $serverKey, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1296,6 +1333,9 @@ App::patch('/v1/messaging/providers/fcm/:providerId') $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); } + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1306,6 +1346,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') + ->label('event', 'providers.[providerId].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1323,9 +1364,10 @@ App::patch('/v1/messaging/providers/apns/:providerId') ->param('teamId', '', new Text(0), 'APNS team ID.', true) ->param('bundleId', '', new Text(0), 'APNS bundle ID.', true) ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1385,6 +1427,9 @@ App::patch('/v1/messaging/providers/apns/:providerId') $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); } + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1394,6 +1439,7 @@ App::delete('/v1/messaging/providers/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.delete') ->label('audits.resource', 'provider/{request.id}') + ->label('event', 'providers.[providerId].delete') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1403,9 +1449,10 @@ App::delete('/v1/messaging/providers/:providerId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) ->param('providerId', '', new UID(), 'Provider ID.') + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, Database $dbForProject, Response $response) { + ->action(function (string $providerId, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1414,6 +1461,9 @@ App::delete('/v1/messaging/providers/:providerId') $dbForProject->deleteDocument('providers', $provider->getId()); + $queueForEvents + ->setParam('providerId', $provider->getId()); + $response ->setStatusCode(Response::STATUS_CODE_NOCONTENT) ->noContent(); @@ -1422,8 +1472,9 @@ App::delete('/v1/messaging/providers/:providerId') App::post('/v1/messaging/topics') ->desc('Create a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'topic.create') + ->label('audits.event', 'topic.[topicId].create') ->label('audits.resource', 'topic/{response.$id}') + ->label('event', 'topics.create') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1435,9 +1486,10 @@ App::post('/v1/messaging/topics') ->param('topicId', '', new CustomId(), 'Topic ID. Choose a custom Topic ID or a new Topic ID.') ->param('name', '', new Text(128), 'Topic Name.') ->param('description', '', new Text(2048), 'Topic Description.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $topicId, string $name, string $description, Database $dbForProject, Response $response) { + ->action(function (string $topicId, string $name, string $description, Event $queueForEvents, Database $dbForProject, Response $response) { $topicId = $topicId == 'unique()' ? ID::unique() : $topicId; $topic = new Document([ @@ -1458,6 +1510,9 @@ App::post('/v1/messaging/topics') throw new Exception(Exception::TOPIC_ALREADY_EXISTS); } + $queueForEvents + ->setParam('topicId', $topic->getId()); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($topic, Response::MODEL_TOPIC); @@ -1538,6 +1593,7 @@ App::patch('/v1/messaging/topics/:topicId') ->groups(['api', 'messaging']) ->label('audits.event', 'topic.update') ->label('audits.resource', 'topic/{response.$id}') + ->label('event', 'topics.[topicId].update') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1549,9 +1605,10 @@ App::patch('/v1/messaging/topics/:topicId') ->param('topicId', '', new UID(), 'Topic ID.') ->param('name', '', new Text(128), 'Topic Name.', true) ->param('description', '', new Text(2048), 'Topic Description.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $topicId, string $name, string $description, Database $dbForProject, Response $response) { + ->action(function (string $topicId, string $name, string $description, Event $queueForEvents, Database $dbForProject, Response $response) { $topic = $dbForProject->getDocument('topics', $topicId); if ($topic->isEmpty()) { @@ -1578,6 +1635,9 @@ App::patch('/v1/messaging/topics/:topicId') $topic = $dbForProject->updateDocument('topics', $topicId, $topic); + $queueForEvents + ->setParam('topicId', $topic->getId()); + $response ->dynamic($topic, Response::MODEL_TOPIC); }); @@ -1587,6 +1647,7 @@ App::delete('/v1/messaging/topics/:topicId') ->groups(['api', 'messaging']) ->label('audits.event', 'topic.delete') ->label('audits.resource', 'topic/{request.topicId}') + ->label('event', 'topics.[topicId].delete') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1596,10 +1657,11 @@ App::delete('/v1/messaging/topics/:topicId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) ->param('topicId', '', new UID(), 'Topic ID.') + ->inject('queueForEvents') ->inject('dbForProject') ->inject('queueForDeletes') ->inject('response') - ->action(function (string $topicId, Database $dbForProject, Delete $queueForDeletes, Response $response) { + ->action(function (string $topicId, Event $queueForEvents, Database $dbForProject, Delete $queueForDeletes, Response $response) { $topic = $dbForProject->getDocument('topics', $topicId); if ($topic->isEmpty()) { @@ -1612,6 +1674,9 @@ App::delete('/v1/messaging/topics/:topicId') ->setType(DELETE_TYPE_TOPIC) ->setDocument($topic); + $queueForEvents + ->setParam('topicId', $topic->getId()); + $response ->setStatusCode(Response::STATUS_CODE_NOCONTENT) ->noContent(); @@ -1622,6 +1687,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->groups(['api', 'messaging']) ->label('audits.event', 'subscriber.create') ->label('audits.resource', 'subscriber/{response.$id}') + ->label('event', 'topics.[topicId].subscribers.[subscriberId].create') ->label('scope', 'subscribers.write') ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1633,9 +1699,10 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->param('subscriberId', '', new CustomId(), 'Subscriber ID. Choose a custom Topic ID or a new Topic ID.') ->param('topicId', '', new UID(), 'Topic ID.') ->param('targetId', '', new UID(), 'Target ID.') + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $subscriberId, string $topicId, string $targetId, Database $dbForProject, Response $response) { + ->action(function (string $subscriberId, string $topicId, string $targetId, Event $queueForEvents, Database $dbForProject, Response $response) { $subscriberId = $subscriberId == 'unique()' ? ID::unique() : $subscriberId; $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); @@ -1669,6 +1736,10 @@ App::post('/v1/messaging/topics/:topicId/subscribers') throw new Exception(Exception::SUBSCRIBER_ALREADY_EXISTS); } + $queueForEvents + ->setParam('topicId', $topic->getId()) + ->setParam('subscriberId', $subscriber->getId()); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); @@ -1759,6 +1830,7 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->groups(['api', 'messaging']) ->label('audits.event', 'subscriber.delete') ->label('audits.resource', 'subscriber/{request.subscriberId}') + ->label('event', 'topics.[topicId].subscribers.[subscriberId].delete') ->label('scope', 'subscribers.write') ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1769,9 +1841,10 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->label('sdk.response.model', Response::MODEL_NONE) ->param('topicId', '', new UID(), 'Topic ID.') ->param('subscriberId', '', new UID(), 'Subscriber ID.') + ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $topicId, string $subscriberId, Database $dbForProject, Response $response) { + ->action(function (string $topicId, string $subscriberId, Event $queueForEvents, Database $dbForProject, Response $response) { $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { @@ -1784,9 +1857,13 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } - $subscriber = $dbForProject->deleteDocument('subscribers', $subscriberId); + $dbForProject->deleteDocument('subscribers', $subscriberId); Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('topics', $topicId, 'total', 1)); + $queueForEvents + ->setParam('topicId', $topic->getId()) + ->setParam('subscriberId', $subscriber->getId()); + $response ->setStatusCode(Response::STATUS_CODE_NOCONTENT) ->noContent(); @@ -1797,6 +1874,7 @@ App::post('/v1/messaging/messages/email') ->groups(['api', 'messaging']) ->label('audits.event', 'message.create') ->label('audits.resource', 'message/{response.$id}') + ->label('event', 'messages.[messageId].create') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1815,11 +1893,12 @@ App::post('/v1/messaging/messages/email') ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, string $status, bool $html, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { @@ -1848,6 +1927,9 @@ App::post('/v1/messaging/messages/email') ->trigger(); } + $queueForEvents + ->setParam('messageId', $message->getId()); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($message, Response::MODEL_MESSAGE); @@ -1858,6 +1940,7 @@ App::post('/v1/messaging/messages/sms') ->groups(['api', 'messaging']) ->label('audits.event', 'message.create') ->label('audits.resource', 'message/{response.$id}') + ->label('event', 'messages.[messageId].create') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1874,11 +1957,12 @@ App::post('/v1/messaging/messages/sms') ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { @@ -1905,6 +1989,9 @@ App::post('/v1/messaging/messages/sms') ->trigger(); } + $queueForEvents + ->setParam('messageId', $message->getId()); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($message, Response::MODEL_MESSAGE); @@ -1915,6 +2002,7 @@ App::post('/v1/messaging/messages/push') ->groups(['api', 'messaging']) ->label('audits.event', 'message.create') ->label('audits.resource', 'message/{response.$id}') + ->label('event', 'messages.[messageId].create') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1939,11 +2027,12 @@ App::post('/v1/messaging/messages/push') ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { @@ -2002,6 +2091,9 @@ App::post('/v1/messaging/messages/push') ->trigger(); } + $queueForEvents + ->setParam('messageId', $message->getId()); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($message, Response::MODEL_MESSAGE); @@ -2079,6 +2171,7 @@ App::patch('/v1/messaging/messages/email/:messageId') ->groups(['api', 'messaging']) ->label('audits.event', 'message.update') ->label('audits.resource', 'message/{response.$id}') + ->label('event', 'messages.[messageId].update') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -2097,11 +2190,12 @@ App::patch('/v1/messaging/messages/email/:messageId') ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $topics, array $users, array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $topics, array $users, array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2167,6 +2261,9 @@ App::patch('/v1/messaging/messages/email/:messageId') ->trigger(); } + $queueForEvents + ->setParam('messageId', $message->getId()); + $response ->dynamic($message, Response::MODEL_MESSAGE); }); @@ -2176,6 +2273,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->groups(['api', 'messaging']) ->label('audits.event', 'message.update') ->label('audits.resource', 'message/{response.$id}') + ->label('event', 'messages.[messageId].update') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -2192,11 +2290,12 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $content, string $status, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2254,6 +2353,9 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->trigger(); } + $queueForEvents + ->setParam('messageId', $message->getId()); + $response ->dynamic($message, Response::MODEL_MESSAGE); }); @@ -2263,6 +2365,7 @@ App::patch('/v1/messaging/messages/push/:messageId') ->groups(['api', 'messaging']) ->label('audits.event', 'message.update') ->label('audits.resource', 'message/{response.$id}') + ->label('event', 'messages.[messageId].update') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -2286,11 +2389,12 @@ App::patch('/v1/messaging/messages/push/:messageId') ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2380,6 +2484,9 @@ App::patch('/v1/messaging/messages/push/:messageId') ->trigger(); } + $queueForEvents + ->setParam('messageId', $message->getId()); + $response ->dynamic($message, Response::MODEL_MESSAGE); }); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 7c9253684e..023cef3641 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -384,6 +384,7 @@ App::post('/v1/users/:userId/targets') ->groups(['api', 'users']) ->label('audits.event', 'target.create') ->label('audits.resource', 'target/response.$id') + ->label('event', 'users.[userId].targets.[targetId].create') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -396,9 +397,10 @@ App::post('/v1/users/:userId/targets') ->param('targetId', '', new UID(), 'Target ID.') ->param('providerId', '', new UID(), 'Provider ID.') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') + ->inject('queueForEvents') ->inject('response') ->inject('dbForProject') - ->action(function (string $userId, string $targetId, string $providerId, string $identifier, Response $response, Database $dbForProject) { + ->action(function (string $userId, string $targetId, string $providerId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -431,6 +433,10 @@ App::post('/v1/users/:userId/targets') } $dbForProject->deleteCachedDocument('users', $user->getId()); + $queueForEvents + ->setParam('userId', $user->getId()) + ->setParam('targetId', $target->getId()); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($target, Response::MODEL_TARGET); @@ -1203,6 +1209,7 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->groups(['api', 'users']) ->label('audits.event', 'target.update') ->label('audits.resource', 'target/{response.$id}') + ->label('event', 'users.[userId].targets.[targetId].update') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -1214,9 +1221,10 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->param('userId', '', new UID(), 'User ID.') ->param('targetId', '', new UID(), 'Target ID.') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') + ->inject('queueForEvents') ->inject('response') ->inject('dbForProject') - ->action(function (string $userId, string $targetId, string $identifier, Response $response, Database $dbForProject) { + ->action(function (string $userId, string $targetId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) { $user = $dbForProject->getDocument('users', $userId); @@ -1239,6 +1247,10 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') $target = $dbForProject->updateDocument('targets', $target->getId(), $target); $dbForProject->deleteCachedDocument('users', $user->getId()); + $queueForEvents + ->setParam('userId', $user->getId()) + ->setParam('targetId', $target->getId()); + $response ->dynamic($target, Response::MODEL_TARGET); }); @@ -1378,6 +1390,7 @@ App::delete('/v1/users/:userId/targets/:targetId') ->groups(['api', 'users']) ->label('audits.event', 'target.delete') ->label('audits.resource', 'target/{request.$targetId}') + ->label('event', 'users.[userId].targets.[targetId].delete') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') @@ -1388,9 +1401,10 @@ App::delete('/v1/users/:userId/targets/:targetId') ->label('sdk.response.model', Response::MODEL_NONE) ->param('userId', '', new UID(), 'User ID.') ->param('targetId', '', new UID(), 'Target ID.') + ->inject('queueForEvents') ->inject('response') ->inject('dbForProject') - ->action(function (string $userId, string $targetId, Response $response, Database $dbForProject) { + ->action(function (string $userId, string $targetId, Event $queueForEvents, Response $response, Database $dbForProject) { $user = $dbForProject->getDocument('users', $userId); @@ -1408,9 +1422,13 @@ App::delete('/v1/users/:userId/targets/:targetId') throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - $target = $dbForProject->deleteDocument('targets', $target->getId()); + $dbForProject->deleteDocument('targets', $target->getId()); $dbForProject->deleteCachedDocument('users', $user->getId()); + $queueForEvents + ->setParam('userId', $user->getId()) + ->setParam('targetId', $target->getId()); + $response->noContent(); }); From 2aa5c5742b4f13f1d4aeba149af434bed5d805b4 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Wed, 1 Nov 2023 12:09:00 +0530 Subject: [PATCH 147/196] remove unnecessary injection --- app/controllers/api/messaging.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 46675dc5f0..d154302832 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -294,7 +294,6 @@ App::post('/v1/messaging/providers/textmagic') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') - ->inject('queueForEvents') ->label('event', 'providers.[providerId].create') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) From fda4e6a8bddd05a303434737a8ba43220fc09093 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 1 Nov 2023 14:33:13 +0530 Subject: [PATCH 148/196] fixes typo in event label --- app/controllers/api/messaging.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index d154302832..cbabb2d0e5 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -850,7 +850,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') - ->label('event', 'providers.[provider].update') + ->label('event', 'providers.[providerId].update') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1473,7 +1473,7 @@ App::post('/v1/messaging/topics') ->groups(['api', 'messaging']) ->label('audits.event', 'topic.[topicId].create') ->label('audits.resource', 'topic/{response.$id}') - ->label('event', 'topics.create') + ->label('event', 'topics.[topicId].create') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') From 76d7369314e93159b73adf3661ead0fc3103aad1 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 2 Nov 2023 12:20:15 +0530 Subject: [PATCH 149/196] fixes description for messaging service models --- src/Appwrite/Utopia/Response/Model/Message.php | 4 ++-- src/Appwrite/Utopia/Response/Model/Provider.php | 4 ++-- src/Appwrite/Utopia/Response/Model/Subscriber.php | 4 ++-- src/Appwrite/Utopia/Response/Model/Target.php | 4 ++-- src/Appwrite/Utopia/Response/Model/Topic.php | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 0341ebdfa0..27c70d7073 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -19,13 +19,13 @@ class Message extends Any ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket creation time in ISO 8601 format.', + 'description' => 'Message creation time in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket update date in ISO 8601 format.', + 'description' => 'Message update date in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index 3f1e2d6c6b..a121753275 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -18,13 +18,13 @@ class Provider extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket creation time in ISO 8601 format.', + 'description' => 'Provider creation time in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket update date in ISO 8601 format.', + 'description' => 'Provider update date in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index 68bb4ef180..65bbd38f0e 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -18,13 +18,13 @@ class Subscriber extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket creation time in ISO 8601 format.', + 'description' => 'Subscriber creation time in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket update date in ISO 8601 format.', + 'description' => 'Subscriber update date in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php index 4547e25e54..c6c5929ee3 100644 --- a/src/Appwrite/Utopia/Response/Model/Target.php +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -18,13 +18,13 @@ class Target extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket creation time in ISO 8601 format.', + 'description' => 'Target creation time in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket update date in ISO 8601 format.', + 'description' => 'Target update date in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) diff --git a/src/Appwrite/Utopia/Response/Model/Topic.php b/src/Appwrite/Utopia/Response/Model/Topic.php index 9f8c378576..096ddb347f 100644 --- a/src/Appwrite/Utopia/Response/Model/Topic.php +++ b/src/Appwrite/Utopia/Response/Model/Topic.php @@ -18,13 +18,13 @@ class Topic extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket creation time in ISO 8601 format.', + 'description' => 'Topic creation time in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Bucket update date in ISO 8601 format.', + 'description' => 'Topic update date in ISO 8601 format.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) From 270e6e7c151e10ad05e1237b1d525f8619ca7772 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 2 Nov 2023 16:43:24 +0530 Subject: [PATCH 150/196] review changes --- app/controllers/api/messaging.php | 42 +++++++++---------- composer.lock | 2 +- docker-compose.yml | 1 + src/Appwrite/Platform/Workers/Messaging.php | 2 +- .../Account/AccountCustomClientTest.php | 4 +- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 0147e472bb..0207708b8b 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -2041,9 +2041,9 @@ App::patch('/v1/messaging/messages/email/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) - ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) - ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) + ->param('topics', null, new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs.', true) + ->param('users', null, new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) + ->param('targets', null, new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Targets IDs.', true) ->param('subject', '', new Text(998), 'Email Subject.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) @@ -2054,7 +2054,7 @@ App::patch('/v1/messaging/messages/email/:messageId') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $topics, array $users, array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2069,15 +2069,15 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } - if (\count($topics) > 0) { + if (!\is_null($topics)) { $message->setAttribute('topics', $topics); } - if (\count($users) > 0) { + if (!\is_null($users)) { $message->setAttribute('users', $users); } - if (\count($targets) > 0) { + if (!\is_null($targets)) { $message->setAttribute('targets', $targets); } @@ -2138,9 +2138,9 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) - ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) - ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) + ->param('topics', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) @@ -2149,7 +2149,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2164,15 +2164,15 @@ App::patch('/v1/messaging/messages/sms/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } - if (\count($topics) > 0) { + if (!\is_null($topics)) { $message->setAttribute('topics', $topics); } - if (\count($users) > 0) { + if (!\is_null($users)) { $message->setAttribute('users', $users); } - if (\count($targets) > 0) { + if (!\is_null($targets)) { $message->setAttribute('targets', $targets); } @@ -2225,9 +2225,9 @@ App::patch('/v1/messaging/messages/push/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) - ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) - ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) + ->param('topics', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('title', '', new Text(256), 'Title for push notification.', true) ->param('body', '', new Text(64230), 'Body for push notification.', true) @@ -2243,7 +2243,7 @@ App::patch('/v1/messaging/messages/push/:messageId') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2258,15 +2258,15 @@ App::patch('/v1/messaging/messages/push/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } - if (\count($topics) > 0) { + if (!\is_null($topics)) { $message->setAttribute('topics', $topics); } - if (\count($users) > 0) { + if (!\is_null($users)) { $message->setAttribute('users', $users); } - if (\count($targets) > 0) { + if (!\is_null($targets)) { $message->setAttribute('targets', $targets); } diff --git a/composer.lock b/composer.lock index 560dfe7b20..66e5e5a11b 100644 --- a/composer.lock +++ b/composer.lock @@ -5822,5 +5822,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/docker-compose.yml b/docker-compose.yml index 94e8a8bd7c..8255508356 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -570,6 +570,7 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE + - _APP_OPENSSL_KEY_V1 - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index a56c98b5e5..63e0ff651a 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -113,7 +113,7 @@ class Messaging extends Action */ $results = batch(\array_map(function ($providerId) use ($providers, $message, $dbForProject) { return function () use ($providerId, $providers, $message, $dbForProject) { - $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); + $provider = $dbForProject->getDocument('providers', $providerId); $identifiers = $providers[$providerId]; $adapter = match ($provider->getAttribute('type')) { 'sms' => $this->sms($provider), diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 336d6f317c..d56f93a42c 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -1018,6 +1018,8 @@ class AccountCustomClientTest extends Scope public function testPhoneVerification(array $data): array { $session = $data['session'] ?? ''; + $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); + $from = $smsDSN->getParam('from'); /** * Test for SUCCESS @@ -1028,7 +1030,7 @@ class AccountCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), ['from' => App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM')]); + ]), ['from' => $from]); $this->assertEquals(201, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); From f97d1fa9e3bb7e04f1e8627e9e31d190e571a3e5 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 2 Nov 2023 18:00:17 +0530 Subject: [PATCH 151/196] adds log api in messaging controller --- app/controllers/api/messaging.php | 342 ++++++++++++++++++ app/controllers/api/users.php | 29 +- .../Database/Validator/Queries/Targets.php | 21 ++ 3 files changed, 387 insertions(+), 5 deletions(-) create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Targets.php diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 3521402a24..1d778f2c76 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1,5 +1,6 @@ desc('List provider logs') + ->groups(['api', 'messaging']) + ->label('scope', 'providers.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listProviderLogs') + ->label('sdk.description', '/docs/references/messaging/providers/get-logs.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_LOG_LIST) + ->param('providerId', '', new UID(), 'Provider ID.') + ->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true) + ->inject('response') + ->inject('dbForProject') + ->inject('locale') + ->inject('geodb') + ->action(function (string $providerId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $queries = Query::parseQueries($queries); + $grouped = Query::groupByType($queries); + $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; + $offset = $grouped['offset'] ?? 0; + + $audit = new Audit($dbForProject); + $resource = 'provider/' . $providerId; + $logs = $audit->getLogsByResource($resource, $limit, $offset); + + $output = []; + + foreach ($logs as $i => &$log) { + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + + $detector = new Detector($log['userAgent']); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + $output[$i] = new Document([ + 'event' => $log['event'], + 'userId' => ID::custom($log['data']['userId']), + 'userEmail' => $log['data']['userEmail'] ?? null, + 'userName' => $log['data']['userName'] ?? null, + 'mode' => $log['data']['mode'] ?? null, + 'ip' => $log['ip'], + 'time' => $log['time'], + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ]); + + $record = $geodb->get($log['ip']); + + if ($record) { + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + } else { + $output[$i]['countryCode'] = '--'; + $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); + } + } + + $response->dynamic(new Document([ + 'total' => $audit->countLogsByResource($resource), + 'logs' => $output, + ]), Response::MODEL_LOG_LIST); + }); + App::get('/v1/messaging/providers/:providerId') ->desc('Get provider') ->groups(['api', 'messaging']) @@ -1560,6 +1650,90 @@ App::get('/v1/messaging/topics') ]), Response::MODEL_TOPIC_LIST); }); +App::get('/v1/messaging/topics/:topicId/logs') + ->desc('List topic logs') + ->groups(['api', 'messaging']) + ->label('scope', 'topics.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listTopicLogs') + ->label('sdk.description', '/docs/references/messaging/topics/get-logs.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_LOG_LIST) + ->param('topicId', '', new UID(), 'Topic ID.') + ->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true) + ->inject('response') + ->inject('dbForProject') + ->inject('locale') + ->inject('geodb') + ->action(function (string $topicId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $topic = $dbForProject->getDocument('topics', $topicId); + + if ($topic->isEmpty()) { + throw new Exception(Exception::TOPIC_NOT_FOUND); + } + + $queries = Query::parseQueries($queries); + $grouped = Query::groupByType($queries); + $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; + $offset = $grouped['offset'] ?? 0; + + $audit = new Audit($dbForProject); + $resource = 'topic/' . $topicId; + $logs = $audit->getLogsByResource($resource, $limit, $offset); + + $output = []; + + foreach ($logs as $i => &$log) { + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + + $detector = new Detector($log['userAgent']); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + $output[$i] = new Document([ + 'event' => $log['event'], + 'userId' => ID::custom($log['data']['userId']), + 'userEmail' => $log['data']['userEmail'] ?? null, + 'userName' => $log['data']['userName'] ?? null, + 'mode' => $log['data']['mode'] ?? null, + 'ip' => $log['ip'], + 'time' => $log['time'], + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ]); + + $record = $geodb->get($log['ip']); + + if ($record) { + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + } else { + $output[$i]['countryCode'] = '--'; + $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); + } + } + + $response->dynamic(new Document([ + 'total' => $audit->countLogsByResource($resource), + 'logs' => $output, + ]), Response::MODEL_LOG_LIST); + }); + App::get('/v1/messaging/topics/:topicId') ->desc('Get a topic.') ->groups(['api', 'messaging']) @@ -1792,6 +1966,90 @@ App::get('/v1/messaging/topics/:topicId/subscribers') ]), Response::MODEL_SUBSCRIBER_LIST); }); +App::get('/v1/messaging/subscribers/:subscriberId/logs') + ->desc('List subscriber logs') + ->groups(['api', 'messaging']) + ->label('scope', 'subscribers.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listSubscriberLogs') + ->label('sdk.description', '/docs/references/messaging/subscribers/get-logs.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_LOG_LIST) + ->param('subscriberId', '', new UID(), 'Subscriber ID.') + ->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true) + ->inject('response') + ->inject('dbForProject') + ->inject('locale') + ->inject('geodb') + ->action(function (string $subscriberId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $subscriber = $dbForProject->getDocument('subscribers', $subscriberId); + + if ($subscriber->isEmpty()) { + throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); + } + + $queries = Query::parseQueries($queries); + $grouped = Query::groupByType($queries); + $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; + $offset = $grouped['offset'] ?? 0; + + $audit = new Audit($dbForProject); + $resource = 'subscriber/' . $subscriberId; + $logs = $audit->getLogsByResource($resource, $limit, $offset); + + $output = []; + + foreach ($logs as $i => &$log) { + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + + $detector = new Detector($log['userAgent']); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + $output[$i] = new Document([ + 'event' => $log['event'], + 'userId' => ID::custom($log['data']['userId']), + 'userEmail' => $log['data']['userEmail'] ?? null, + 'userName' => $log['data']['userName'] ?? null, + 'mode' => $log['data']['mode'] ?? null, + 'ip' => $log['ip'], + 'time' => $log['time'], + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ]); + + $record = $geodb->get($log['ip']); + + if ($record) { + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + } else { + $output[$i]['countryCode'] = '--'; + $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); + } + } + + $response->dynamic(new Document([ + 'total' => $audit->countLogsByResource($resource), + 'logs' => $output, + ]), Response::MODEL_LOG_LIST); + }); + App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->desc('Get a topic\'s subscriber.') ->groups(['api', 'messaging']) @@ -2141,6 +2399,90 @@ App::get('/v1/messaging/messages') ]), Response::MODEL_MESSAGE_LIST); }); +App::get('/v1/messaging/messages/:messageId/logs') + ->desc('List message logs') + ->groups(['api', 'messaging']) + ->label('scope', 'messages.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listMessageLogs') + ->label('sdk.description', '/docs/references/messaging/messages/get-logs.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_LOG_LIST) + ->param('messageId', '', new UID(), 'Message ID.') + ->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true) + ->inject('response') + ->inject('dbForProject') + ->inject('locale') + ->inject('geodb') + ->action(function (string $messageId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $message = $dbForProject->getDocument('messages', $messageId); + + if ($message->isEmpty()) { + throw new Exception(Exception::MESSAGE_NOT_FOUND); + } + + $queries = Query::parseQueries($queries); + $grouped = Query::groupByType($queries); + $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; + $offset = $grouped['offset'] ?? 0; + + $audit = new Audit($dbForProject); + $resource = 'message/' . $messageId; + $logs = $audit->getLogsByResource($resource, $limit, $offset); + + $output = []; + + foreach ($logs as $i => &$log) { + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + + $detector = new Detector($log['userAgent']); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + $output[$i] = new Document([ + 'event' => $log['event'], + 'userId' => ID::custom($log['data']['userId']), + 'userEmail' => $log['data']['userEmail'] ?? null, + 'userName' => $log['data']['userName'] ?? null, + 'mode' => $log['data']['mode'] ?? null, + 'ip' => $log['ip'], + 'time' => $log['time'], + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ]); + + $record = $geodb->get($log['ip']); + + if ($record) { + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + } else { + $output[$i]['countryCode'] = '--'; + $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); + } + } + + $response->dynamic(new Document([ + 'total' => $audit->countLogsByResource($resource), + 'logs' => $output, + ]), Response::MODEL_LOG_LIST); + }); + App::get('/v1/messaging/messages/:messageId') ->desc('Get a message') ->groups(['api', 'messaging']) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 023cef3641..51c4b3330f 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -9,6 +9,7 @@ use Appwrite\Event\Event; use Appwrite\Network\Validator\Email; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Database\Validator\Queries\Identities; +use Appwrite\Utopia\Database\Validator\Queries\Targets; use Utopia\Database\Validator\Queries; use Appwrite\Utopia\Database\Validator\Queries\Users; use Utopia\Database\Validator\Query\Limit; @@ -753,20 +754,38 @@ App::get('/v1/users/:userId/targets') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET_LIST) ->param('userId', '', new UID(), 'User ID.') + ->param('queries', [], new Targets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('dbForProject') - ->action(function (string $userId, Response $response, Database $dbForProject) { - + ->action(function (string $userId, array $queries, Response $response, Database $dbForProject) { $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); } - $targets = $user->getAttribute('targets', []); + $queries = Query::parseQueries($queries); + + $queries[] = Query::equal('userId', [$userId]); + + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); + + if ($cursor) { + $targetId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Target '{$targetId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + $response->dynamic(new Document([ - 'targets' => $targets, - 'total' => \count($targets), + 'targets' => $dbForProject->find('targets', $queries), + 'total' => $dbForProject->count('targets', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_TARGET_LIST); }); diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Targets.php b/src/Appwrite/Utopia/Database/Validator/Queries/Targets.php new file mode 100644 index 0000000000..1099604b78 --- /dev/null +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Targets.php @@ -0,0 +1,21 @@ + Date: Wed, 8 Nov 2023 23:26:46 +0530 Subject: [PATCH 152/196] added tests for logs endpoint --- app/controllers/api/messaging.php | 1 + composer.lock | 14 +- .../e2e/Services/Messaging/MessagingBase.php | 440 ++++++++++++++++++ 3 files changed, 448 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 1d778f2c76..6545ebb25c 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -32,6 +32,7 @@ use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\JSON; use Utopia\Validator\Text; +use MaxMind\Db\Reader; use Utopia\Validator\WhiteList; App::post('/v1/messaging/providers/mailgun') diff --git a/composer.lock b/composer.lock index 66e5e5a11b..32f63111d3 100644 --- a/composer.lock +++ b/composer.lock @@ -2318,16 +2318,16 @@ }, { "name": "utopia-php/migration", - "version": "0.3.5", + "version": "0.3.6", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "b2fd3a8310296f4e44ff0e85b0eb0230ad9a2f83" + "reference": "f78273b38bade23db5866e5c7cb5f55427ba82af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/b2fd3a8310296f4e44ff0e85b0eb0230ad9a2f83", - "reference": "b2fd3a8310296f4e44ff0e85b0eb0230ad9a2f83", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/f78273b38bade23db5866e5c7cb5f55427ba82af", + "reference": "f78273b38bade23db5866e5c7cb5f55427ba82af", "shasum": "" }, "require": { @@ -2360,9 +2360,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.3.5" + "source": "https://github.com/utopia-php/migration/tree/0.3.6" }, - "time": "2023-09-25T16:51:47+00:00" + "time": "2023-11-02T15:13:03+00:00" }, { "name": "utopia-php/mongo", @@ -5822,5 +5822,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 221617a1d1..da2134addf 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -202,6 +202,116 @@ trait MessagingBase $this->assertEquals($providers[0]['name'], $response['body']['name']); } + /** + * @depends testUpdateProviders + */ + public function testGetProviderLogs(array $providers): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } + /** * @depends testUpdateProviders */ @@ -282,6 +392,116 @@ trait MessagingBase $this->assertEquals(0, $response['body']['total']); } + /** + * @depends testUpdateTopic + */ + public function testGetTopicLogs(string $topicId): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } + /** * @depends testCreateTopic */ @@ -369,6 +589,116 @@ trait MessagingBase $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); } + /** + * @depends testCreateSubscriber + */ + public function testGetSubscriberLogs(array $data): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } + /** * @depends testCreateSubscriber */ @@ -651,6 +981,116 @@ trait MessagingBase $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } + /** + * @depends testSendEmail + */ + public function testGetMessageLogs(array $email): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } + public function testSendSMS() { if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { From 8d5bfdabc6b51457143838d720c4ce9c9792de9a Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 9 Nov 2023 12:29:16 +0530 Subject: [PATCH 153/196] revert wrong aduits.event label --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 3521402a24..36508a0817 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1471,7 +1471,7 @@ App::delete('/v1/messaging/providers/:providerId') App::post('/v1/messaging/topics') ->desc('Create a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'topic.[topicId].create') + ->label('audits.event', 'topic.create') ->label('audits.resource', 'topic/{response.$id}') ->label('event', 'topics.[topicId].create') ->label('scope', 'topics.write') From 3654799cc781ca30dca502938e3a6e9d92c63d2d Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 9 Nov 2023 14:53:42 +0530 Subject: [PATCH 154/196] links ISO 8601, move params in messaging controllers --- app/controllers/api/databases.php | 2 +- app/controllers/api/messaging.php | 46 +++++++++++++++---------------- app/controllers/api/projects.php | 4 +-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index aaf30e00c3..3c372cb76e 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -1571,7 +1571,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new DatetimeValidator(), 'Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.', true) + ->param('default', null, new DatetimeValidator(), 'Default value for the attribute in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) ->inject('response') ->inject('dbForProject') diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 6545ebb25c..4634135ecf 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -507,12 +507,12 @@ App::post('/v1/messaging/providers/fcm') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('serverKey', '', new Text(0), 'FCM server key.') + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $enabled, string $serverKey, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $serverKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -566,16 +566,16 @@ App::post('/v1/messaging/providers/apns') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('authKey', '', new Text(0), 'APNS authentication key.') ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') ->param('teamId', '', new Text(0), 'APNS team ID.') ->param('bundleId', '', new Text(0), 'APNS bundle ID.') ->param('endpoint', '', new Text(0), 'APNS endpoint.') + ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -786,7 +786,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) - ->param('isEuRegion', null, new Boolean(), 'Set as eu region.', true) + ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) ->param('from', '', new Text(256), 'Sender email address.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) @@ -1857,7 +1857,7 @@ App::delete('/v1/messaging/topics/:topicId') }); App::post('/v1/messaging/topics/:topicId/subscribers') - ->desc('Adds a subscriber to a topic.') + ->desc('Create a subscriber.') ->groups(['api', 'messaging']) ->label('audits.event', 'subscriber.create') ->label('audits.resource', 'subscriber/{response.$id}') @@ -1870,9 +1870,9 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_SUBSCRIBER) - ->param('subscriberId', '', new CustomId(), 'Subscriber ID. Choose a custom Topic ID or a new Topic ID.') - ->param('topicId', '', new UID(), 'Topic ID.') - ->param('targetId', '', new UID(), 'Target ID.') + ->param('subscriberId', '', new CustomId(), 'Subscriber ID. Choose a custom Subscriber ID or a new Subscriber ID.') + ->param('topicId', '', new UID(), 'Topic ID. The topic ID to subscribe to.') + ->param('targetId', '', new UID(), 'Target ID. The target ID to link to the specified Topic ID.') ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -1920,7 +1920,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') }); App::get('/v1/messaging/topics/:topicId/subscribers') - ->desc('List topic\'s subscribers.') + ->desc('List subscribers.') ->groups(['api', 'messaging']) ->label('scope', 'subscribers.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1930,7 +1930,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_SUBSCRIBER_LIST) - ->param('topicId', '', new UID(), 'Topic ID.') + ->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.') ->param('queries', [], new Subscribers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) ->inject('dbForProject') ->inject('response') @@ -2051,8 +2051,8 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs') ]), Response::MODEL_LOG_LIST); }); -App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') - ->desc('Get a topic\'s subscriber.') +App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') + ->desc('Get a subscriber.') ->groups(['api', 'messaging']) ->label('scope', 'subscribers.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -2062,7 +2062,7 @@ App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_SUBSCRIBER) - ->param('topicId', '', new UID(), 'Topic ID.') + ->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.') ->param('subscriberId', '', new UID(), 'Subscriber ID.') ->inject('dbForProject') ->inject('response') @@ -2083,8 +2083,8 @@ App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); }); -App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') - ->desc('Delete a subscriber from a topic.') +App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') + ->desc('Delete a subscriber.') ->groups(['api', 'messaging']) ->label('audits.event', 'subscriber.delete') ->label('audits.resource', 'subscriber/{request.subscriberId}') @@ -2097,7 +2097,7 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('topicId', '', new UID(), 'Topic ID.') + ->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.') ->param('subscriberId', '', new UID(), 'Subscriber ID.') ->inject('queueForEvents') ->inject('dbForProject') @@ -2150,7 +2150,7 @@ App::post('/v1/messaging/messages/email') ->param('description', '', new Text(256), 'Description for message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') @@ -2214,7 +2214,7 @@ App::post('/v1/messaging/messages/sms') ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') @@ -2284,7 +2284,7 @@ App::post('/v1/messaging/messages/push') ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') @@ -2531,7 +2531,7 @@ App::patch('/v1/messaging/messages/email/:messageId') ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') @@ -2631,7 +2631,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') @@ -2730,7 +2730,7 @@ App::patch('/v1/messaging/messages/push/:messageId') ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index de9cc82b84..e59371cdfc 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1166,7 +1166,7 @@ App::post('/v1/projects/:projectId/keys') ->param('projectId', '', new UID(), 'Project unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.') - ->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true) + ->param('expire', null, new DatetimeValidator(), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.', true) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) { @@ -1283,7 +1283,7 @@ App::put('/v1/projects/:projectId/keys/:keyId') ->param('keyId', '', new UID(), 'Key unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') - ->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true) + ->param('expire', null, new DatetimeValidator(), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.', true) ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $keyId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) { From 76ed15f2a1fd24f50a7a8d2341588bad0490753e Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 10 Nov 2023 02:20:55 +0530 Subject: [PATCH 155/196] adds more assertion in logs tests --- app/controllers/api/messaging.php | 15 ++-- composer.lock | 2 +- .../e2e/Services/Messaging/MessagingBase.php | 83 ++++++++++++++++++- 3 files changed, 89 insertions(+), 11 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index a86aba81bc..0f892ad98b 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -664,7 +664,7 @@ App::get('/v1/messaging/providers/:providerId/logs') ->desc('List provider logs') ->groups(['api', 'messaging']) ->label('scope', 'providers.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'listProviderLogs') ->label('sdk.description', '/docs/references/messaging/providers/get-logs.md') @@ -692,7 +692,6 @@ App::get('/v1/messaging/providers/:providerId/logs') $audit = new Audit($dbForProject); $resource = 'provider/' . $providerId; $logs = $audit->getLogsByResource($resource, $limit, $offset); - $output = []; foreach ($logs as $i => &$log) { @@ -1528,7 +1527,7 @@ App::delete('/v1/messaging/providers/:providerId') ->desc('Delete provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.delete') - ->label('audits.resource', 'provider/{request.id}') + ->label('audits.resource', 'provider/{request.$providerId}') ->label('event', 'providers.[providerId].delete') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1655,7 +1654,7 @@ App::get('/v1/messaging/topics/:topicId/logs') ->desc('List topic logs') ->groups(['api', 'messaging']) ->label('scope', 'topics.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'listTopicLogs') ->label('sdk.description', '/docs/references/messaging/topics/get-logs.md') @@ -1820,7 +1819,7 @@ App::delete('/v1/messaging/topics/:topicId') ->desc('Delete a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'topic.delete') - ->label('audits.resource', 'topic/{request.topicId}') + ->label('audits.resource', 'topic/{request.$topicId}') ->label('event', 'topics.[topicId].delete') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1971,7 +1970,7 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs') ->desc('List subscriber logs') ->groups(['api', 'messaging']) ->label('scope', 'subscribers.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'listSubscriberLogs') ->label('sdk.description', '/docs/references/messaging/subscribers/get-logs.md') @@ -2087,7 +2086,7 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->desc('Delete a subscriber from a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'subscriber.delete') - ->label('audits.resource', 'subscriber/{request.subscriberId}') + ->label('audits.resource', 'subscriber/{request.$subscriberId}') ->label('event', 'topics.[topicId].subscribers.[subscriberId].delete') ->label('scope', 'subscribers.write') ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -2404,7 +2403,7 @@ App::get('/v1/messaging/messages/:messageId/logs') ->desc('List message logs') ->groups(['api', 'messaging']) ->label('scope', 'messages.read') - ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'listMessageLogs') ->label('sdk.description', '/docs/references/messaging/messages/get-logs.md') diff --git a/composer.lock b/composer.lock index 32f63111d3..f320e31e38 100644 --- a/composer.lock +++ b/composer.lock @@ -5822,5 +5822,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index da2134addf..18af4e7994 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -220,6 +220,29 @@ trait MessagingBase $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/sendgrid/' . $providers[0]['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'sendgrid' => [ + 'name' => 'Sendgrid3', + 'apiKey' => 'my-apikey', + ]]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + $this->assertCount(2, $logs['body']['logs']); + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -410,6 +433,27 @@ trait MessagingBase $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/topics/' . $topicId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'description' => 'updated-description-1' + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertCount(2, $logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -549,7 +593,7 @@ trait MessagingBase ]); $this->assertEquals(200, $topic['headers']['status-code']); $this->assertEquals('android-app', $topic['body']['name']); - $this->assertEquals('updated-description', $topic['body']['description']); + $this->assertEquals('updated-description-1', $topic['body']['description']); $this->assertEquals(1, $topic['body']['total']); return [ @@ -719,7 +763,7 @@ trait MessagingBase $this->assertEquals(200, $topic['headers']['status-code']); $this->assertEquals('android-app', $topic['body']['name']); - $this->assertEquals('updated-description', $topic['body']['description']); + $this->assertEquals('updated-description-1', $topic['body']['description']); $this->assertEquals(0, $topic['body']['total']); } @@ -999,6 +1043,41 @@ trait MessagingBase $this->assertIsArray($logs['body']['logs']); $this->assertIsNumeric($logs['body']['total']); + $email = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'status' => 'draft', + 'topics' => [ID::unique()], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ]); + + $this->assertEquals(201, $email['headers']['status-code']); + + $email = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'subject' => 'Khali beats John Cena!', + ]); + + $this->assertEquals(200, $email['headers']['status-code']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + $this->assertCount(2,$logs['body']['logs']); + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], From 3b5379a0cbccaab54d7ff9a8039151c45d74d4a3 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 10 Nov 2023 12:31:21 +0530 Subject: [PATCH 156/196] added more assertions in logs test and moved them to console --- .../e2e/Services/Messaging/MessagingBase.php | 429 +----------------- .../Messaging/MessagingConsoleClientTest.php | 399 ++++++++++++++++ 2 files changed, 415 insertions(+), 413 deletions(-) diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 18af4e7994..78f2330b96 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -184,8 +184,11 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(\count($providers), \count($response['body']['providers'])); + + return $providers; } /** @@ -202,139 +205,6 @@ trait MessagingBase $this->assertEquals($providers[0]['name'], $response['body']['name']); } - /** - * @depends testUpdateProviders - */ - public function testGetProviderLogs(array $providers): void - { - /** - * Test for SUCCESS - */ - $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); - - $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/sendgrid/' . $providers[0]['$id'], [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'sendgrid' => [ - 'name' => 'Sendgrid3', - 'apiKey' => 'my-apikey', - ]]); - - $this->assertEquals(200, $response['headers']['status-code']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); - $this->assertCount(2, $logs['body']['logs']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['limit(1)'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); - $this->assertIsNumeric($logs['body']['total']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['offset(1)'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['limit(1)', 'offset(1)'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); - $this->assertIsNumeric($logs['body']['total']); - - /** - * Test for FAILURE - */ - $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['limit(-1)'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['offset(-1)'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['equal("$id", "asdf")'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['orderAsc("$id")'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['cursorAsc("$id")'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - } - /** * @depends testUpdateProviders */ @@ -386,7 +256,10 @@ trait MessagingBase return $response['body']['$id']; } - public function testListTopic() + /** + * @depends testUpdateTopic + */ + public function testListTopic(string $topicId) { $response = $this->client->call(Client::METHOD_GET, '/messaging/topics', [ 'content-type' => 'application/json', @@ -395,8 +268,11 @@ trait MessagingBase ], [ 'search' => 'updated-description', ]); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, \count($response['body']['topics'])); + + return $topicId; } /** @@ -415,137 +291,6 @@ trait MessagingBase $this->assertEquals(0, $response['body']['total']); } - /** - * @depends testUpdateTopic - */ - public function testGetTopicLogs(string $topicId): void - { - /** - * Test for SUCCESS - */ - $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); - - $response = $this->client->call(Client::METHOD_PATCH, '/messaging/topics/' . $topicId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'description' => 'updated-description-1' - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertCount(2, $logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['limit(1)'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); - $this->assertIsNumeric($logs['body']['total']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['offset(1)'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['limit(1)', 'offset(1)'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); - $this->assertIsNumeric($logs['body']['total']); - - /** - * Test for FAILURE - */ - $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['limit(-1)'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['offset(-1)'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['equal("$id", "asdf")'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['orderAsc("$id")'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['cursorAsc("$id")'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - } - /** * @depends testCreateTopic */ @@ -593,7 +338,7 @@ trait MessagingBase ]); $this->assertEquals(200, $topic['headers']['status-code']); $this->assertEquals('android-app', $topic['body']['name']); - $this->assertEquals('updated-description-1', $topic['body']['description']); + $this->assertEquals('updated-description', $topic['body']['description']); $this->assertEquals(1, $topic['body']['total']); return [ @@ -628,13 +373,16 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ])); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); + + return $data; } /** - * @depends testCreateSubscriber + * @depends testListSubscribers */ public function testGetSubscriberLogs(array $data): void { @@ -763,7 +511,7 @@ trait MessagingBase $this->assertEquals(200, $topic['headers']['status-code']); $this->assertEquals('android-app', $topic['body']['name']); - $this->assertEquals('updated-description-1', $topic['body']['description']); + $this->assertEquals('updated-description', $topic['body']['description']); $this->assertEquals(0, $topic['body']['total']); } @@ -1025,151 +773,6 @@ trait MessagingBase $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } - /** - * @depends testSendEmail - */ - public function testGetMessageLogs(array $email): void - { - /** - * Test for SUCCESS - */ - $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); - - $email = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'messageId' => ID::unique(), - 'status' => 'draft', - 'topics' => [ID::unique()], - 'subject' => 'Khali beats Undertaker', - 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', - ]); - - $this->assertEquals(201, $email['headers']['status-code']); - - $email = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'subject' => 'Khali beats John Cena!', - ]); - - $this->assertEquals(200, $email['headers']['status-code']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); - $this->assertCount(2,$logs['body']['logs']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['limit(1)'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); - $this->assertIsNumeric($logs['body']['total']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['offset(1)'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); - - $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['limit(1)', 'offset(1)'], - ]); - - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); - $this->assertIsNumeric($logs['body']['total']); - - /** - * Test for FAILURE - */ - $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['limit(-1)'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['offset(-1)'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['equal("$id", "asdf")'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['orderAsc("$id")'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - - $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'queries' => ['cursorAsc("$id")'] - ]); - - $this->assertEquals($response['headers']['status-code'], 400); - } - public function testSendSMS() { if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { diff --git a/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php b/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php index 0d533c139b..0baa465b48 100644 --- a/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php +++ b/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php @@ -2,13 +2,412 @@ namespace Tests\E2E\Services\Messaging; +use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; +use Utopia\Database\Helpers\ID; class MessagingConsoleClientTest extends Scope { use MessagingBase; use ProjectCustom; use SideConsole; + + /** + * @depends testListProviders + */ + public function testGetProviderLogs(array $providers): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid/', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'providerId' => ID::unique(), + 'name' => 'Sengrid1', + 'apiKey' => 'my-apikey', + 'from' => 'sender-email@my-domain.com', + ]); + + $this->assertEquals(201, $provider['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/sendgrid/' . $provider['body']['$id'], \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'sendgrid' => [ + 'name' => 'Sendgrid2', + ]]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + $this->assertCount(2, $logs['body']['logs']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } + + /** + * @depends testListTopic + */ + public function testGetTopicLogs(string $topicId): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'topicId' => ID::unique(), + 'name' => 'my-app', + 'description' => 'web app' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/topics/' . $topic['body']['$id'], \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'description' => 'updated-description' + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertCount(2, $logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } + + /** + * @depends testSendEmail + */ + public function testGetMessageLogs(array $email): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $email = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'messageId' => ID::unique(), + 'status' => 'draft', + 'topics' => [ID::unique()], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ]); + + $this->assertEquals(201, $email['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subject' => 'Khali beats John Cena!', + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + $this->assertCount(2, $logs['body']['logs']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } } From 1b99f47f21cc796b50a1fed176f166a7b89433ad Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 10 Nov 2023 13:28:39 +0530 Subject: [PATCH 157/196] lint fix --- app/config/errors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/errors.php b/app/config/errors.php index 1e62cae54d..1117f20e48 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -827,5 +827,5 @@ return [ 'description' => 'Message with the requested ID has already been scheduled for delivery.', 'code' => 400, ], - + ]; From f84a00dded4dd3a527540138d3495b09f0843517 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 14 Nov 2023 14:07:52 +0530 Subject: [PATCH 158/196] adds search attribute filter --- app/config/collections.php | 12 ++-- app/controllers/api/messaging.php | 44 +------------ app/init.php | 64 +++++++++++++++++++ composer.lock | 4 +- .../e2e/Services/Messaging/MessagingBase.php | 4 +- 5 files changed, 76 insertions(+), 52 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 33a60fce44..aa6afffb17 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1467,9 +1467,9 @@ $commonCollections = [ 'size' => 65535, 'signed' => true, 'required' => false, - 'default' => null, + 'default' => '', 'array' => false, - 'filters' => [], + 'filters' => ['providerSearch'], ], ], 'indexes' => [ @@ -1640,9 +1640,9 @@ $commonCollections = [ 'size' => 16384, 'signed' => true, 'required' => false, - 'default' => null, + 'default' => '', 'array' => false, - 'filters' => [], + 'filters' => ['messageSearch'], ], ], 'indexes' => [ @@ -1712,9 +1712,9 @@ $commonCollections = [ 'size' => 16384, 'signed' => true, 'required' => false, - 'default' => null, + 'default' => '', 'array' => false, - 'filters' => [], + 'filters' => ['topicSearch'], ], ], 'indexes' => [ diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 340961c3ac..7bac2abf88 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -68,7 +68,6 @@ App::post('/v1/messaging/providers/mailgun') 'provider' => 'mailgun', 'type' => 'email', 'enabled' => $enabled, - 'search' => $providerId . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email', 'credentials' => [ 'apiKey' => $apiKey, 'domain' => $domain, @@ -133,7 +132,6 @@ App::post('/v1/messaging/providers/sendgrid') 'provider' => 'sendgrid', 'type' => 'email', 'enabled' => $enabled, - 'search' => $providerId . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email', 'credentials' => [ 'apiKey' => $apiKey, ], @@ -196,7 +194,6 @@ App::post('/v1/messaging/providers/msg91') 'name' => $name, 'provider' => 'msg91', 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms', 'enabled' => $enabled, 'credentials' => [ 'senderId' => $senderId, @@ -261,7 +258,6 @@ App::post('/v1/messaging/providers/telesign') 'name' => $name, 'provider' => 'telesign', 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms', 'enabled' => $enabled, 'credentials' => [ 'username' => $username, @@ -324,9 +320,8 @@ App::post('/v1/messaging/providers/textmagic') $provider = new Document([ '$id' => $providerId, 'name' => $name, - 'provider' => 'text-magic', + 'provider' => 'textmagic', 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'text-magic' . ' ' . 'sms', 'enabled' => $enabled, 'credentials' => [ 'username' => $username, @@ -391,7 +386,6 @@ App::post('/v1/messaging/providers/twilio') 'name' => $name, 'provider' => 'twilio', 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms', 'enabled' => $enabled, 'credentials' => [ 'accountSid' => $accountSid, @@ -456,7 +450,6 @@ App::post('/v1/messaging/providers/vonage') 'name' => $name, 'provider' => 'vonage', 'type' => 'sms', - 'search' => $providerId . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms', 'enabled' => $enabled, 'credentials' => [ 'apiKey' => $apiKey, @@ -519,7 +512,6 @@ App::post('/v1/messaging/providers/fcm') 'name' => $name, 'provider' => 'fcm', 'type' => 'push', - 'search' => $providerId . ' ' . $name . ' ' . 'fcm' . ' ' . 'push', 'enabled' => $enabled, 'credentials' => [ 'serverKey' => $serverKey, @@ -582,7 +574,6 @@ App::post('/v1/messaging/providers/apns') 'name' => $name, 'provider' => 'apns', 'type' => 'push', - 'search' => $providerId . ' ' . $name . ' ' . 'apns' . ' ' . 'push', 'enabled' => $enabled, 'credentials' => [ 'authKey' => $authKey, @@ -806,7 +797,6 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') if (!empty($name)) { $provider->setAttribute('name', $name); - $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email'); } if (!empty($from)) { @@ -894,7 +884,6 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') if (!empty($name)) { $provider->setAttribute('name', $name); - $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email'); } if (!empty($from)) { @@ -973,7 +962,6 @@ App::patch('/v1/messaging/providers/msg91/:providerId') if (!empty($name)) { $provider->setAttribute('name', $name); - $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms'); } if (!empty($from)) { @@ -1058,7 +1046,6 @@ App::patch('/v1/messaging/providers/telesign/:providerId') if (!empty($name)) { $provider->setAttribute('name', $name); - $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms'); } if (!empty($from)) { @@ -1137,13 +1124,12 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') } $providerAttr = $provider->getAttribute('provider'); - if ($providerAttr !== 'text-magic') { + if ($providerAttr !== 'textmagic') { throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } if (!empty($name)) { $provider->setAttribute('name', $name); - $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'textmagic' . ' ' . 'sms'); } if (!empty($from)) { @@ -1228,7 +1214,6 @@ App::patch('/v1/messaging/providers/twilio/:providerId') if (!empty($name)) { $provider->setAttribute('name', $name); - $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms'); } if (!empty($from)) { @@ -1313,7 +1298,6 @@ App::patch('/v1/messaging/providers/vonage/:providerId') if (!empty($name)) { $provider->setAttribute('name', $name); - $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms'); } if (!empty($from)) { @@ -1396,7 +1380,6 @@ App::patch('/v1/messaging/providers/fcm/:providerId') if (!empty($name)) { $provider->setAttribute('name', $name); - $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'fcm' . ' ' . 'push'); } if ($enabled === true || $enabled === false) { @@ -1470,7 +1453,6 @@ App::patch('/v1/messaging/providers/apns/:providerId') if (!empty($name)) { $provider->setAttribute('name', $name); - $provider->setAttribute('search', $provider->getId() . ' ' . $name . ' ' . 'apns' . ' ' . 'push'); } if ($enabled === true || $enabled === false) { @@ -1588,9 +1570,6 @@ App::post('/v1/messaging/topics') if ($description) { $topic->setAttribute('description', $description); - $topic->setAttribute('search', $topic->getId() . ' ' . $name . ' ' . $description); - } else { - $topic->setAttribute('search', $topic->getId() . ' ' . $name); } try { @@ -1796,16 +1775,6 @@ App::patch('/v1/messaging/topics/:topicId') $topic->setAttribute('description', $description); } - if (!empty($name) || !empty($description)) { - if (!empty($name) && !empty($description)) { - $topic->setAttribute('search', $topic->getId() . ' ' . $name . ' ' . $description); - } elseif (!empty($name)) { - $topic->setAttribute('search', $topic->getId() . ' ' . $name . ' ' . $topic->getAttribute('description')); - } else { - $topic->setAttribute('search', $topic->getId() . ' ' . $topic->getAttribute('name') . ' ' . $description); - } - } - $topic = $dbForProject->updateDocument('topics', $topicId, $topic); $queueForEvents @@ -2174,7 +2143,6 @@ App::post('/v1/messaging/messages/email') 'html' => $html, ], 'status' => $status, - 'search' => $messageId . ' ' . $description . ' ' . $subject, ])); if ($status === 'processing') { @@ -2236,7 +2204,6 @@ App::post('/v1/messaging/messages/sms') 'content' => $content, ], 'status' => $status, - 'search' => $messageId . ' ' . $description, ])); if ($status === 'processing') { @@ -2338,7 +2305,6 @@ App::post('/v1/messaging/messages/push') 'deliveryTime' => $deliveryTime, 'data' => $pushData, 'status' => $status, - 'search' => $messageId . ' ' . $description . ' ' . $title, ])); if ($status === 'processing') { @@ -2583,8 +2549,6 @@ App::patch('/v1/messaging/messages/email/:messageId') $message->setAttribute('description', $description); } - $message->setAttribute('search', $message->getId() . ' ' . $message->getAttribute('description') . ' ' . $data['subject'] . ' ' . $message->getAttribute('providerId')); - if (!empty($status)) { $message->setAttribute('status', $status); } @@ -2683,8 +2647,6 @@ App::patch('/v1/messaging/messages/sms/:messageId') $message->setAttribute('deliveryTime', $deliveryTime); } - $message->setAttribute('search', $message->getId() . ' ' . $message->getAttribute('description') . ' ' . $message->getAttribute('providerId')); - $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { @@ -2814,8 +2776,6 @@ App::patch('/v1/messaging/messages/push/:messageId') $message->setAttribute('deliveryTime', $deliveryTime); } - $message->setAttribute('search', $message->getId() . ' ' . $message->getAttribute('description') . ' ' . $pushData['title'] . ' ' . $message->getAttribute('providerId')); - $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { diff --git a/app/init.php b/app/init.php index 094ca412fe..2e0aa36eb0 100644 --- a/app/init.php +++ b/app/init.php @@ -557,6 +557,70 @@ Database::addFilter( return []; } ); + +Database::addFilter( + 'providerSearch', + function (mixed $value, Document $provider) { + $searchValues = [ + $provider->getId(), + $provider->getAttribute('name', ''), + $provider->getAttribute('provider', ''), + $provider->getAttribute('type', '') + ]; + + $search = implode(' ', \array_filter($searchValues)); + + return $search; + }, + function (mixed $value) { + return $value; + } +); + +Database::addFilter( + 'topicSearch', + function (mixed $value, Document $topic) { + $searchValues = [ + $topic->getId(), + $topic->getAttribute('name', ''), + $topic->getAttribute('description', ''), + ]; + + $search = implode(' ', \array_filter($searchValues)); + + return $search; + }, + function (mixed $value) { + return $value; + } +); + +Database::addFilter( + 'messageSearch', + function (mixed $value, Document $message) { + $searchValues = [ + $message->getId(), + $message->getAttribute('description', ''), + $message->getAttribute('status', ''), + ]; + + if (\array_key_exists('subject', $message->getAttribute('data'))) { + $searchValues[] = \array_merge($searchValues, [$message->getAttribute('data')['subject'], 'email']); + } else if (\array_key_exists('content', $message->getAttribute('data'))) { + $searchValues[] = \array_merge($searchValues, [$message->getAttribute('data')['content'], 'sms']); + } else { + $searchValues[] = \array_merge($searchValues, [$message->getAttribute('data')['title'], 'push']); + } + + $search = implode(' ', \array_filter($searchValues)); + + return $search; + }, + function (mixed $value) { + return $value; + } +); + /** * DB Formats */ diff --git a/composer.lock b/composer.lock index 25f0c3964d..7cddef8715 100644 --- a/composer.lock +++ b/composer.lock @@ -1958,7 +1958,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/0.45.1" }, - "time": "2023-11-01T08:30:19+00:00" + "time": "2023-11-09T22:39:48+00:00" }, { "name": "utopia-php/domains", @@ -5822,5 +5822,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 78f2330b96..21d22827f0 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -353,7 +353,7 @@ trait MessagingBase */ public function testGetSubscriber(array $data) { - $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'] . '/subscriber/' . $data['subscriberId'], \array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'] . '/subscribers/' . $data['subscriberId'], \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -496,7 +496,7 @@ trait MessagingBase */ public function testDeleteSubscriber(array $data) { - $response = $this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $data['topicId'] . '/subscriber/' . $data['subscriberId'], \array_merge([ + $response = $this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $data['topicId'] . '/subscribers/' . $data['subscriberId'], \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); From c5aaa670a90d2de4e29d51ce64e7abd82a54561b Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 14 Nov 2023 15:20:21 +0530 Subject: [PATCH 159/196] adds provider details in message search attribute --- app/controllers/api/messaging.php | 13 ++++----- app/init.php | 18 +++++++------ src/Appwrite/Platform/Workers/Messaging.php | 29 +++++++++++++++------ 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 7bac2abf88..2cc9639fbd 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1,5 +1,6 @@ label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Text(256), 'Sender email address.') + ->param('from', '', new Email(), 'Sender email address.') ->param('apiKey', '', new Text(0), 'Sendgrid API key.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') @@ -180,7 +181,7 @@ App::post('/v1/messaging/providers/msg91') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Text(256), 'Sender number.') + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) @@ -244,7 +245,7 @@ App::post('/v1/messaging/providers/telesign') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Text(256), 'Sender number.') + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) @@ -308,7 +309,7 @@ App::post('/v1/messaging/providers/textmagic') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Text(256), 'Sender number.') + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') ->param('username', '', new Text(0), 'Textmagic username.') ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) @@ -372,7 +373,7 @@ App::post('/v1/messaging/providers/twilio') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Text(256), 'Sender number.') + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) @@ -436,7 +437,7 @@ App::post('/v1/messaging/providers/vonage') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Text(256), 'Sender number.') + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') ->param('enabled', true, new Boolean(), 'Set as enabled.', true) diff --git a/app/init.php b/app/init.php index 2e0aa36eb0..adac72ed50 100644 --- a/app/init.php +++ b/app/init.php @@ -568,7 +568,7 @@ Database::addFilter( $provider->getAttribute('type', '') ]; - $search = implode(' ', \array_filter($searchValues)); + $search = \implode(' ', \array_filter($searchValues)); return $search; }, @@ -586,7 +586,7 @@ Database::addFilter( $topic->getAttribute('description', ''), ]; - $search = implode(' ', \array_filter($searchValues)); + $search = \implode(' ', \array_filter($searchValues)); return $search; }, @@ -604,15 +604,17 @@ Database::addFilter( $message->getAttribute('status', ''), ]; - if (\array_key_exists('subject', $message->getAttribute('data'))) { - $searchValues[] = \array_merge($searchValues, [$message->getAttribute('data')['subject'], 'email']); - } else if (\array_key_exists('content', $message->getAttribute('data'))) { - $searchValues[] = \array_merge($searchValues, [$message->getAttribute('data')['content'], 'sms']); + $data = \json_decode($message->getAttribute('data', []), true); + + if (\array_key_exists('subject', $data)) { + $searchValues = \array_merge($searchValues, [$data['subject'], 'email']); + } elseif (\array_key_exists('content', $data)) { + $searchValues = \array_merge($searchValues, [$data['content'], 'sms']); } else { - $searchValues[] = \array_merge($searchValues, [$message->getAttribute('data')['title'], 'push']); + $searchValues = \array_merge($searchValues, [$data['title'], 'push']); } - $search = implode(' ', \array_filter($searchValues)); + $search = \implode(' ', \array_filter($searchValues)); return $search; }, diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 63e0ff651a..dcef84c2df 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -10,7 +10,6 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Adapters\SMS\Mock; use Utopia\Messaging\Adapters\SMS\Msg91; @@ -99,22 +98,31 @@ class Messaging extends Action $recipients = \array_merge($recipients, $targets); } + /** + * @var array> $identifiersByProviderId + */ + $identifiersByProviderId = []; + + /** + * @var Document[] $providers + */ $providers = []; foreach ($recipients as $recipient) { $providerId = $recipient->getAttribute('providerId'); - if (!isset($providers[$providerId])) { - $providers[$providerId] = []; + if (!isset($identifiersByProviderId[$providerId])) { + $identifiersByProviderId[$providerId] = []; } - $providers[$providerId][] = $recipient->getAttribute('identifier'); + $identifiersByProviderId[$providerId][] = $recipient->getAttribute('identifier'); } /** * @var array[] $results */ - $results = batch(\array_map(function ($providerId) use ($providers, $message, $dbForProject) { - return function () use ($providerId, $providers, $message, $dbForProject) { + $results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $message, $dbForProject) { + return function () use ($providerId, $identifiersByProviderId, $providers, $message, $dbForProject) { $provider = $dbForProject->getDocument('providers', $providerId); - $identifiers = $providers[$providerId]; + $providers[] = $provider; + $identifiers = $identifiersByProviderId[$providerId]; $adapter = match ($provider->getAttribute('type')) { 'sms' => $this->sms($provider), 'push' => $this->push($provider), @@ -154,7 +162,7 @@ class Messaging extends Action return $results; }; - }, \array_keys($providers))); + }, \array_keys($identifiersByProviderId))); $results = array_merge(...$results); @@ -172,6 +180,11 @@ class Messaging extends Action $message->setAttribute('status', 'sent'); } $message->removeAttribute('to'); + + foreach ($providers as $provider) { + $message->setAttribute('search', "{$message->getAttribute('search')} {$provider->getAttribute('name')} {$provider->getAttribute('provider')} {$provider->getAttribute('type')}"); + } + $message->setAttribute('deliveredTotal', $deliveredTotal); $message->setAttribute('deliveredAt', DateTime::now()); From 7ae614fe138c85ba85a6447b09a2619d5e1371fc Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 14 Nov 2023 18:14:07 +0530 Subject: [PATCH 160/196] adds provider type in target --- app/config/collections.php | 15 ++- app/config/errors.php | 5 + app/controllers/api/account.php | 7 +- app/controllers/api/messaging.php | 103 ++++++++++++------ app/controllers/api/teams.php | 3 +- app/controllers/api/users.php | 53 ++++++--- src/Appwrite/Extend/Exception.php | 1 + src/Appwrite/Platform/Workers/Messaging.php | 30 ++++- src/Appwrite/Utopia/Response/Model/Target.php | 6 + tests/e2e/Services/GraphQL/Base.php | 12 +- tests/e2e/Services/GraphQL/MessagingTest.php | 7 ++ tests/e2e/Services/GraphQL/UsersTest.php | 3 +- .../e2e/Services/Messaging/MessagingBase.php | 19 ++++ tests/e2e/Services/Users/UsersBase.php | 8 +- 14 files changed, 202 insertions(+), 70 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index aa6afffb17..bfa8192b74 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1845,7 +1845,7 @@ $commonCollections = [ 'filters' => [], ], [ - '$id' => ID::custom('providerId'), + '$id' => ID::custom('providerType'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => Database::LENGTH_KEY, @@ -1855,13 +1855,24 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('providerId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('providerInternalId'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, - 'required' => true, + 'required' => false, 'default' => null, 'array' => false, 'filters' => [], diff --git a/app/config/errors.php b/app/config/errors.php index 1117f20e48..e915091940 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -781,6 +781,11 @@ return [ 'description' => 'Provider with the requested ID is of incorrect type: ', 'code' => 400, ], + Exception::PROVIDER_INTERNAL_UPDATE_DISABLED => [ + 'name' => Exception::PROVIDER_INTERNAL_UPDATE_DISABLED, + 'description' => 'Provider with the requested ID cannot be disabled.', + 'code' => 400, + ], /** Topic Errors */ Exception::TOPIC_NOT_FOUND => [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 96c0483cca..77ff2a27e4 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1240,6 +1240,7 @@ App::post('/v1/account/sessions/phone') Query::equal('internal', [true]), Query::equal('type', ['sms']) ])); + if ($provider === false || $provider->isEmpty()) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -1335,8 +1336,7 @@ App::post('/v1/account/sessions/phone') $target = $dbForProject->createDocument('targets', new Document([ 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), + 'providerType' => 'sms', 'identifier' => $phone, ])); } @@ -2959,8 +2959,7 @@ App::post('/v1/account/verification/phone') $target = $dbForProject->createDocument('targets', new Document([ 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), + 'providerType' => 'sms', 'identifier' => $user->getAttribute('phone'), ])); } diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 2cc9639fbd..f8d0ae16ec 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -806,14 +806,21 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if ($internal === true) { $provider->setAttribute('internal', $internal); } + if ($enabled === true || $enabled === false) { + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + } + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + } + + $provider->setAttribute('enabled', $enabled); + } + $credentials = $provider->getAttribute('credentials'); if ($isEuRegion === true || $isEuRegion === false) { @@ -893,14 +900,17 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if ($internal === true) { $provider->setAttribute('internal', $internal); } + if ($enabled === true || $enabled === false) { + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + } + $provider->setAttribute('enabled', $enabled); + } + if (!empty($apiKey)) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, @@ -971,14 +981,17 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if ($internal === true) { $provider->setAttribute('internal', $internal); } + if ($enabled === true || $enabled === false) { + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + } + $provider->setAttribute('enabled', $enabled); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($senderId)) { @@ -1055,14 +1068,17 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if ($internal === true) { $provider->setAttribute('internal', $internal); } + if ($enabled === true || $enabled === false) { + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + } + $provider->setAttribute('enabled', $enabled); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -1139,14 +1155,17 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if ($internal === true) { $provider->setAttribute('internal', $internal); } + if ($enabled === true || $enabled === false) { + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); + } + $provider->setAttribute('enabled', $enabled); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -1223,14 +1242,17 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if ($internal === true) { $provider->setAttribute('internal', $internal); } + if ($enabled === true || $enabled === false) { + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + } + $provider->setAttribute('enabled', $enabled); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($accountSid)) { @@ -1307,14 +1329,17 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if ($internal === true) { $provider->setAttribute('internal', $internal); } + if ($enabled === true || $enabled === false) { + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + } + $provider->setAttribute('enabled', $enabled); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($apiKey)) { @@ -1383,14 +1408,17 @@ App::patch('/v1/messaging/providers/fcm/:providerId') $provider->setAttribute('name', $name); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if ($internal === true) { $provider->setAttribute('internal', $internal); } + if ($enabled === true || $enabled === false) { + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + } + $provider->setAttribute('enabled', $enabled); + } + if (!empty($serverKey)) { $provider->setAttribute('credentials', ['serverKey' => $serverKey]); } @@ -1456,14 +1484,17 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider->setAttribute('name', $name); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if ($internal === true) { $provider->setAttribute('internal', $internal); } + if ($enabled === true || $enabled === false) { + if ($provider->getAttribute('internal') === true && $enabled === false) { + throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + } + $provider->setAttribute('enabled', $enabled); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($authKey)) { diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index a4ad61733f..b19080e894 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -650,8 +650,7 @@ App::post('/v1/teams/:teamId/memberships') $target = $dbForProject->createDocument('targets', new Document([ 'userId' => $invitee->getId(), 'userInternalId' => $invitee->getInternalId(), - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), + 'providerType' => 'sms', 'identifier' => $phone, ])); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 71deded08f..d9968c83a7 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -394,18 +394,25 @@ App::post('/v1/users/:userId/targets') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET) + ->param('targetId', '', new CustomId(), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('userId', '', new UID(), 'User ID.') - ->param('targetId', '', new UID(), 'Target ID.') - ->param('providerId', '', new UID(), 'Provider ID.') + ->param('providerType', '', new WhiteList(['email', 'sms', 'push']), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') + ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) ->inject('queueForEvents') ->inject('response') ->inject('dbForProject') - ->action(function (string $userId, string $targetId, string $providerId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) { - $provider = $dbForProject->getDocument('providers', $providerId); + ->action(function (string $targetId, string $userId, string $providerType, string $identifier, string $providerId, Event $queueForEvents, Response $response, Database $dbForProject) { + $targetId = $targetId == 'unique()' ? ID::unique() : $targetId; - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); + $provider = new Document(); + + if ($providerType === 'push') { + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } } $user = $dbForProject->getDocument('users', $userId); @@ -423,8 +430,9 @@ App::post('/v1/users/:userId/targets') try { $target = $dbForProject->createDocument('targets', new Document([ '$id' => $targetId, - 'providerId' => $providerId, - 'providerInternalId' => $provider->getInternalId(), + 'providerId' => $providerId ?? null, + 'providerInternalId' => $provider->getInternalId() ?? null, + 'providerType' => $providerType, 'userId' => $userId, 'userInternalId' => $user->getInternalId(), 'identifier' => $identifier, @@ -1223,8 +1231,8 @@ App::patch('/v1/users/:userId/prefs') $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); }); -App::patch('/v1/users/:userId/targets/:targetId/identifier') - ->desc('Update user target\'s identifier') +App::patch('/v1/users/:userId/targets/:targetId') + ->desc('Update User target') ->groups(['api', 'users']) ->label('audits.event', 'target.update') ->label('audits.resource', 'target/{response.$id}') @@ -1232,19 +1240,19 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'users') - ->label('sdk.method', 'updateTargetIdentifier') - ->label('sdk.description', '/docs/references/users/update-target-identifier.md') + ->label('sdk.method', 'updateTarget') + ->label('sdk.description', '/docs/references/users/update-target.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET) ->param('userId', '', new UID(), 'User ID.') ->param('targetId', '', new UID(), 'Target ID.') - ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') + ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) ->inject('queueForEvents') ->inject('response') ->inject('dbForProject') - ->action(function (string $userId, string $targetId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) { - + ->action(function (string $userId, string $targetId, string $providerId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) { $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1261,7 +1269,20 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier') throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - $target->setAttribute('identifier', $identifier); + if ($identifier) { + $target->setAttribute('identifier', $identifier); + } + + if ($providerId) { + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $target->setAttribute('providerId', $provider->getId()); + $target->setAttribute('providerInternalId', $provider->getInternalId()); + } $target = $dbForProject->updateDocument('targets', $target->getId(), $target); $dbForProject->deleteCachedDocument('users', $user->getId()); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index d887a5a520..b7043a9738 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -236,6 +236,7 @@ class Exception extends \Exception public const PROVIDER_NOT_FOUND = 'provider_not_found'; public const PROVIDER_ALREADY_EXISTS = 'provider_already_exists'; public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; + public const PROVIDER_INTERNAL_UPDATE_DISABLED = 'provider_internal_update_disabled'; /** Topic */ public const TOPIC_NOT_FOUND = 'topic_not_found'; diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index dcef84c2df..68bae1b4d0 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -98,6 +98,11 @@ class Messaging extends Action $recipients = \array_merge($recipients, $targets); } + $internalProvider = $dbForProject->findOne('providers', [ + Query::equal('internal', [true]), + Query::equal('type', [$recipients[0]->getAttribute('providerType')]), + ]); + /** * @var array> $identifiersByProviderId */ @@ -109,6 +114,11 @@ class Messaging extends Action $providers = []; foreach ($recipients as $recipient) { $providerId = $recipient->getAttribute('providerId'); + + if (!$providerId) { + $providerId = $internalProvider->getId(); + } + if (!isset($identifiersByProviderId[$providerId])) { $identifiersByProviderId[$providerId] = []; } @@ -118,17 +128,26 @@ class Messaging extends Action /** * @var array[] $results */ - $results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $message, $dbForProject) { - return function () use ($providerId, $identifiersByProviderId, $providers, $message, $dbForProject) { - $provider = $dbForProject->getDocument('providers', $providerId); + $results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $internalProvider, $message, $dbForProject) { + return function () use ($providerId, $identifiersByProviderId, $providers, $internalProvider, $message, $dbForProject) { + $provider = new Document(); + + if ($internalProvider->getId() === $providerId) { + $provider = $internalProvider; + } else { + $provider = $dbForProject->getDocument('providers', $providerId); + } + $providers[] = $provider; $identifiers = $identifiersByProviderId[$providerId]; + $adapter = match ($provider->getAttribute('type')) { 'sms' => $this->sms($provider), 'push' => $this->push($provider), 'email' => $this->email($provider), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; + $maxBatchSize = $adapter->getMaxMessagesPerRequest(); $batches = \array_chunk($identifiers, $maxBatchSize); $batchIndex = 0; @@ -139,12 +158,14 @@ class Messaging extends Action $deliveryErrors = []; $messageData = clone $message; $messageData->setAttribute('to', $batch); + $data = match ($provider->getAttribute('type')) { 'sms' => $this->buildSMSMessage($messageData, $provider), 'push' => $this->buildPushMessage($messageData), 'email' => $this->buildEmailMessage($messageData, $provider), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; + try { $adapter->send($data); $deliveredTotal += \count($batch); @@ -168,10 +189,12 @@ class Messaging extends Action $deliveredTotal = 0; $deliveryErrors = []; + foreach ($results as $result) { $deliveredTotal += $result['deliveredTotal']; $deliveryErrors = \array_merge($deliveryErrors, $result['deliveryErrors']); } + $message->setAttribute('deliveryErrors', $deliveryErrors); if (\count($message->getAttribute('deliveryErrors')) > 0) { @@ -179,6 +202,7 @@ class Messaging extends Action } else { $message->setAttribute('status', 'sent'); } + $message->removeAttribute('to'); foreach ($providers as $provider) { diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php index c6c5929ee3..f6346f409a 100644 --- a/src/Appwrite/Utopia/Response/Model/Target.php +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -41,6 +41,12 @@ class Target extends Model 'default' => '', 'example' => '259125845563242502', ]) + ->addRule('providerType', [ + 'type' => self::TYPE_STRING, + 'description' => 'The target provider type. Can be one of the following: `email`, `sms` or `push`.', + 'default' => '', + 'example' => 'email', + ]) ->addRule('identifier', [ 'type' => self::TYPE_STRING, 'description' => 'The target identifier.', diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 93fd6cdc74..b57b680674 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -934,10 +934,11 @@ trait Base } }'; case self::$CREATE_USER_TARGET: - return 'mutation createUserTarget($userId: String!, $targetId: String!, $providerId: String!, $identifier: String!){ - usersCreateTarget(userId: $userId, targetId: $targetId, providerId: $providerId, identifier: $identifier) { + return 'mutation createUserTarget($userId: String!, $targetId: String!, $providerType: String!, $identifier: String! $providerId: String){ + usersCreateTarget(userId: $userId, targetId: $targetId, providerType: $providerType, identifier: $identifier, providerId: $providerId) { _id userId + providerType providerId identifier } @@ -949,6 +950,7 @@ trait Base targets { _id userId + providerType providerId identifier } @@ -959,15 +961,17 @@ trait Base usersGetTarget(userId: $userId, targetId: $targetId) { _id userId + providerType providerId identifier } }'; case self::$UPDATE_USER_TARGET: - return 'mutation updateUserTarget($userId: String!, $targetId: String!, $identifier: String!){ - usersUpdateTargetIdentifier(userId: $userId, targetId: $targetId, identifier: $identifier) { + return 'mutation updateUserTarget($userId: String!, $targetId: String!, $providerId: String, $identifier: String){ + usersUpdateTarget(userId: $userId, targetId: $targetId, providerId: $providerId, identifier: $identifier) { _id userId + providerType providerId identifier } diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index c0322372ba..57ed825a5c 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -395,6 +395,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'targetId' => ID::unique(), + 'providerType' => 'email', 'userId' => $userId, 'providerId' => $providerId, 'identifier' => 'token', @@ -604,6 +605,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'targetId' => ID::unique(), + 'providerType' => 'email', 'userId' => $user['body']['data']['usersCreate']['_id'], 'providerId' => $providerId, 'identifier' => $to, @@ -755,6 +757,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'targetId' => ID::unique(), + 'providerType' => 'email', 'userId' => $user['body']['data']['usersCreate']['_id'], 'providerId' => $providerId, 'identifier' => $to, @@ -916,6 +919,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'targetId' => ID::unique(), + 'providerType' => 'sms', 'userId' => $user['body']['data']['usersCreate']['_id'], 'providerId' => $providerId, 'identifier' => $to, @@ -1063,6 +1067,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'targetId' => ID::unique(), + 'providerType' => 'sms', 'userId' => $user['body']['data']['usersCreate']['_id'], 'providerId' => $providerId, 'identifier' => $to, @@ -1219,6 +1224,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'targetId' => ID::unique(), + 'providerType' => 'push', 'userId' => $user['body']['data']['usersCreate']['_id'], 'providerId' => $providerId, 'identifier' => $to, @@ -1363,6 +1369,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'targetId' => ID::unique(), + 'providerType' => 'push', 'userId' => $user['body']['data']['usersCreate']['_id'], 'providerId' => $providerId, 'identifier' => $to, diff --git a/tests/e2e/Services/GraphQL/UsersTest.php b/tests/e2e/Services/GraphQL/UsersTest.php index d750de5834..59c0c4a805 100644 --- a/tests/e2e/Services/GraphQL/UsersTest.php +++ b/tests/e2e/Services/GraphQL/UsersTest.php @@ -78,6 +78,7 @@ class UsersTest extends Scope 'variables' => [ 'targetId' => ID::unique(), 'userId' => $user['_id'], + 'providerType' => 'email', 'providerId' => $providerId, 'identifier' => 'identifier', ] @@ -479,7 +480,7 @@ class UsersTest extends Scope ], $this->getHeaders()), $graphQLPayload); $this->assertEquals(200, $target['headers']['status-code']); - $this->assertEquals('newidentifier', $target['body']['data']['usersUpdateTargetIdentifier']['identifier']); + $this->assertEquals('newidentifier', $target['body']['data']['usersUpdateTarget']['identifier']); } public function testDeleteUserSessions() diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 21d22827f0..707ba2f7b5 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -317,6 +317,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'targetId' => ID::unique(), + 'providerType' => 'email', 'providerId' => $provider['body']['$id'], 'identifier' => 'my-token', ]); @@ -558,6 +559,7 @@ trait MessagingBase 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), 'from' => $from ]); + $this->assertEquals(201, $provider['headers']['status-code']); // Create Topic @@ -570,6 +572,7 @@ trait MessagingBase 'name' => 'topic1', 'description' => 'Test Topic' ]); + $this->assertEquals(201, $topic['headers']['status-code']); // Create User @@ -593,6 +596,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'targetId' => ID::unique(), + 'providerType' => 'email', 'providerId' => $provider['body']['$id'], 'identifier' => $to, ]); @@ -682,6 +686,7 @@ trait MessagingBase 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), 'from' => $from ]); + $this->assertEquals(201, $provider['headers']['status-code']); // Create Topic @@ -694,6 +699,7 @@ trait MessagingBase 'name' => 'topic1', 'description' => 'Test Topic' ]); + $this->assertEquals(201, $topic['headers']['status-code']); // Create User @@ -717,6 +723,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'targetId' => ID::unique(), + 'providerType' => 'email', 'providerId' => $provider['body']['$id'], 'identifier' => $to, ]); @@ -801,6 +808,7 @@ trait MessagingBase 'authKey' => $authKey, 'from' => $from ]); + $this->assertEquals(201, $provider['headers']['status-code']); // Create Topic @@ -813,6 +821,7 @@ trait MessagingBase 'name' => 'topic1', 'description' => 'Test Topic' ]); + $this->assertEquals(201, $topic['headers']['status-code']); // Create User @@ -836,6 +845,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'targetId' => ID::unique(), + 'providerType' => 'sms', 'providerId' => $provider['body']['$id'], 'identifier' => $to, ]); @@ -922,6 +932,7 @@ trait MessagingBase 'authKey' => $authKey, 'from' => $from ]); + $this->assertEquals(201, $provider['headers']['status-code']); // Create Topic @@ -934,6 +945,7 @@ trait MessagingBase 'name' => 'topic1', 'description' => 'Test Topic' ]); + $this->assertEquals(201, $topic['headers']['status-code']); // Create User @@ -957,6 +969,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'targetId' => ID::unique(), + 'providerType' => 'sms', 'providerId' => $provider['body']['$id'], 'identifier' => $to, ]); @@ -1036,6 +1049,7 @@ trait MessagingBase 'name' => 'FCM-1', 'serverKey' => $serverKey, ]); + $this->assertEquals(201, $provider['headers']['status-code']); // Create Topic @@ -1048,6 +1062,7 @@ trait MessagingBase 'name' => 'topic1', 'description' => 'Test Topic' ]); + $this->assertEquals(201, $topic['headers']['status-code']); // Create User @@ -1071,6 +1086,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'targetId' => ID::unique(), + 'providerType' => 'push', 'providerId' => $provider['body']['$id'], 'identifier' => $to, ]); @@ -1154,6 +1170,7 @@ trait MessagingBase 'name' => 'FCM-2', 'serverKey' => $serverKey, ]); + $this->assertEquals(201, $provider['headers']['status-code']); // Create Topic @@ -1166,6 +1183,7 @@ trait MessagingBase 'name' => 'topic1', 'description' => 'Test Topic' ]); + $this->assertEquals(201, $topic['headers']['status-code']); // Create User @@ -1189,6 +1207,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'targetId' => ID::unique(), + 'providerType' => 'push', 'providerId' => $provider['body']['$id'], 'identifier' => $to, ]); diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index 9ca00aa5df..c9cb17d7b5 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -1232,7 +1232,7 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'providerId' => 'unique()', + 'providerId' => ID::unique(), 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', 'from' => 'from@domain.com', @@ -1244,6 +1244,7 @@ trait UsersBase ], $this->getHeaders()), [ 'targetId' => ID::unique(), 'providerId' => $provider['body']['$id'], + 'providerType' => 'email', 'identifier' => 'my-token', ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -1257,7 +1258,7 @@ trait UsersBase */ public function testUpdateUserTarget(array $data): array { - $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/targets/' . $data['$id'] . '/identifier', array_merge([ + $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/targets/' . $data['$id'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -1303,11 +1304,14 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); + $this->assertEquals(204, $response['headers']['status-code']); + $response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(0, $response['body']['total']); } From 1870524be5748709bf2b2d2a80f7f224fc2f1069 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 14 Nov 2023 21:34:17 +0530 Subject: [PATCH 161/196] fixes error name --- app/controllers/api/messaging.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index f8d0ae16ec..dd5ab2bd1a 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -812,10 +812,10 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') if ($enabled === true || $enabled === false) { if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } $provider->setAttribute('enabled', $enabled); @@ -906,7 +906,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') if ($enabled === true || $enabled === false) { if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } $provider->setAttribute('enabled', $enabled); } @@ -987,7 +987,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId') if ($enabled === true || $enabled === false) { if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } $provider->setAttribute('enabled', $enabled); } @@ -1074,7 +1074,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId') if ($enabled === true || $enabled === false) { if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } $provider->setAttribute('enabled', $enabled); } @@ -1248,7 +1248,7 @@ App::patch('/v1/messaging/providers/twilio/:providerId') if ($enabled === true || $enabled === false) { if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } $provider->setAttribute('enabled', $enabled); } @@ -1335,7 +1335,7 @@ App::patch('/v1/messaging/providers/vonage/:providerId') if ($enabled === true || $enabled === false) { if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } $provider->setAttribute('enabled', $enabled); } @@ -1414,7 +1414,7 @@ App::patch('/v1/messaging/providers/fcm/:providerId') if ($enabled === true || $enabled === false) { if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } $provider->setAttribute('enabled', $enabled); } @@ -1490,7 +1490,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') if ($enabled === true || $enabled === false) { if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_DISABLED); + throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } $provider->setAttribute('enabled', $enabled); } From adc76c5797c2b456743edffc909feb3ac9405b26 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 14 Nov 2023 22:46:20 +0530 Subject: [PATCH 162/196] adds target when account is created or email or phone is updated --- app/config/collections.php | 4 +-- app/controllers/api/account.php | 54 +++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index bfa8192b74..5571fd57d6 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1926,9 +1926,9 @@ $commonCollections = [ 'orders' => [], ], [ - '$id' => ID::custom('_key_identifier_providerId'), + '$id' => ID::custom('_key_identifier_userInternalId'), 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['providerId', 'identifier'], + 'attributes' => ['identifier', 'userInternalId'], 'lengths' => [], 'orders' => [], ] diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 77ff2a27e4..8a15432a25 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -147,8 +147,15 @@ App::post('/v1/account') 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), ]); + $userInternalId = $user->getInternalId(); $user->removeAttribute('$internalId'); Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([ + 'userId' => $user->getId(), + 'userInternalId' => $userInternalId, + 'providerType' => 'email', + 'identifier' => $email, + ]))); } catch (Duplicate) { throw new Exception(Exception::USER_ALREADY_EXISTS); } @@ -1329,10 +1336,10 @@ App::post('/v1/account/sessions/phone') $target = $dbForProject->findOne('targets', [ Query::equal('identifier', [$phone]), - Query::equal('providerInternalId', [$provider->getInternalId()]) + Query::equal('userInternalId', [$user->getInternalId()]) ]); - if (!$target) { + if (!$target || $target->isEmpty()) { $target = $dbForProject->createDocument('targets', new Document([ 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), @@ -1995,6 +2002,7 @@ App::patch('/v1/account/email') throw new Exception(Exception::USER_INVALID_CREDENTIALS); } + $oldEmail = $user->getAttribute('email'); $email = \strtolower($email); // Makes sure this email is not already used in another identity @@ -2019,8 +2027,23 @@ App::patch('/v1/account/email') ->setAttribute('passwordUpdate', DateTime::now()); } + $target = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$email]), + Query::equal('userInternalId', [$user->getInternalId()]) + ]); + + if ($target && !$target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + + /** + * @var Document $oldTarget + */ + $oldTarget = $user->find('identifier', $oldEmail, 'targets'); + try { $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); + $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)); } catch (Duplicate) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -2065,6 +2088,20 @@ App::patch('/v1/account/phone') throw new Exception(Exception::USER_INVALID_CREDENTIALS); } + $target = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$phone]), + Query::equal('userInternalId', [$user->getInternalId()]) + ]); + + if ($target && !$target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + + /** + * @var Document $oldTarget + */ + $oldTarget = $user->find('identifier', $user->getAttribute('phone'), 'targets'); + $user ->setAttribute('phone', $phone) ->setAttribute('phoneVerification', false) // After this user needs to confirm phone number again @@ -2080,6 +2117,7 @@ App::patch('/v1/account/phone') try { $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); + $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone)); } catch (Duplicate $th) { throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS); } @@ -2904,6 +2942,7 @@ App::post('/v1/account/verification/phone') Query::equal('internal', [true]), Query::equal('type', ['sms']) ])); + if ($provider === false || $provider->isEmpty()) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -2952,18 +2991,9 @@ App::post('/v1/account/verification/phone') $target = $dbForProject->findOne('targets', [ Query::equal('identifier', [$user->getAttribute('phone')]), - Query::equal('providerInternalId', [$provider->getInternalId()]) + Query::equal('userInternalId', [$user->getInternalId()]) ]); - if (!$target) { - $target = $dbForProject->createDocument('targets', new Document([ - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), - 'providerType' => 'sms', - 'identifier' => $user->getAttribute('phone'), - ])); - } - $messageDoc = $dbForProject->createDocument('messages', new Document([ '$id' => $verification->getId(), 'targets' => [$target->getId()], From fdca55b0de9d61f72dc8822ce1d9148de464d851 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 15 Nov 2023 01:24:55 +0530 Subject: [PATCH 163/196] fix test cases --- app/config/collections.php | 9 +- app/controllers/api/account.php | 70 +++- tests/e2e/Services/GraphQL/MessagingTest.php | 318 +----------------- .../e2e/Services/Messaging/MessagingBase.php | 247 +------------- 4 files changed, 66 insertions(+), 578 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 5571fd57d6..f2ee405c92 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1920,18 +1920,11 @@ $commonCollections = [ ], [ '$id' => ID::custom('_key_identifier'), - 'type' => Database::INDEX_KEY, + 'type' => Database::INDEX_UNIQUE, 'attributes' => ['identifier'], 'lengths' => [], 'orders' => [], ], - [ - '$id' => ID::custom('_key_identifier_userInternalId'), - 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['identifier', 'userInternalId'], - 'lengths' => [], - 'orders' => [], - ] ], ], ]; diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 8a15432a25..c5e389dd42 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -147,15 +147,21 @@ App::post('/v1/account') 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), ]); - $userInternalId = $user->getInternalId(); $user->removeAttribute('$internalId'); - Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); - Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([ + $user = Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + $target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($userId)), + Permission::delete(Role::user($userId)), + ], 'userId' => $user->getId(), - 'userInternalId' => $userInternalId, + 'userInternalId' => $user->getInternalId(), 'providerType' => 'email', 'identifier' => $email, ]))); + $user->setAttribute('targets', [$target]); + $dbForProject->deleteCachedDocument('users', $user->getId()); } catch (Duplicate) { throw new Exception(Exception::USER_ALREADY_EXISTS); } @@ -663,7 +669,18 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$internalId'); - Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + $userDoc = Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + $dbForProject->createDocument('targets', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], + 'userId' => $userDoc->getId(), + 'userInternalId' => $userDoc->getInternalId(), + 'providerType' => 'email', + 'identifier' => $email, + ])); } catch (Duplicate) { $failureRedirect(Exception::USER_ALREADY_EXISTS); } @@ -1336,16 +1353,21 @@ App::post('/v1/account/sessions/phone') $target = $dbForProject->findOne('targets', [ Query::equal('identifier', [$phone]), - Query::equal('userInternalId', [$user->getInternalId()]) ]); if (!$target || $target->isEmpty()) { $target = $dbForProject->createDocument('targets', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), 'providerType' => 'sms', 'identifier' => $phone, ])); + $dbForProject->deleteCachedDocument('users', $user->getId()); } $messageDoc = $dbForProject->createDocument('messages', new Document([ @@ -2029,7 +2051,6 @@ App::patch('/v1/account/email') $target = $dbForProject->findOne('targets', [ Query::equal('identifier', [$email]), - Query::equal('userInternalId', [$user->getInternalId()]) ]); if ($target && !$target->isEmpty()) { @@ -2041,9 +2062,16 @@ App::patch('/v1/account/email') */ $oldTarget = $user->find('identifier', $oldEmail, 'targets'); + if ($oldTarget !== false && !$oldTarget->isEmpty()) { + try { + $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)); + } catch (Duplicate) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + } + try { $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); - $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)); } catch (Duplicate) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -2090,7 +2118,6 @@ App::patch('/v1/account/phone') $target = $dbForProject->findOne('targets', [ Query::equal('identifier', [$phone]), - Query::equal('userInternalId', [$user->getInternalId()]) ]); if ($target && !$target->isEmpty()) { @@ -2115,9 +2142,16 @@ App::patch('/v1/account/phone') ->setAttribute('passwordUpdate', DateTime::now()); } + if ($oldTarget !== false && !$oldTarget->isEmpty()) { + try { + $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone)); + } catch (Duplicate) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + } + try { $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); - $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone)); } catch (Duplicate $th) { throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS); } @@ -2991,9 +3025,23 @@ App::post('/v1/account/verification/phone') $target = $dbForProject->findOne('targets', [ Query::equal('identifier', [$user->getAttribute('phone')]), - Query::equal('userInternalId', [$user->getInternalId()]) ]); + if (!$target || $target->isEmpty()) { + $target = $dbForProject->createDocument('targets', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ], + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerType' => 'sms', + 'identifier' => $user->getAttribute('phone'), + ])); + $dbForProject->deleteCachedDocument('users', $user->getId()); + } + $messageDoc = $dbForProject->createDocument('messages', new Document([ '$id' => $verification->getId(), 'targets' => [$target->getId()], diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 57ed825a5c..112e9e5633 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -680,120 +680,13 @@ class MessagingTest extends Scope */ public function testUpdateEmail(array $email) { - if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) { - $this->markTestSkipped('Email DSN not provided'); - } - - $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); - $to = $emailDSN->getParam('to'); - $from = $emailDSN->getParam('from'); - $isEuRegion = $emailDSN->getParam('isEuRegion'); - $apiKey = $emailDSN->getPassword(); - $domain = $emailDSN->getUser(); - - if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { - $this->markTestSkipped('Email provider not configured'); - } - - $query = $this->getQuery(self::$CREATE_MAILGUN_PROVIDER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'providerId' => ID::unique(), - 'name' => 'Mailgun2', - 'apiKey' => $apiKey, - 'domain' => $domain, - 'from' => $from, - 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), - ], - ]; - $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $provider['headers']['status-code']); - - $providerId = $provider['body']['data']['messagingCreateMailgunProvider']['_id']; - - $query = $this->getQuery(self::$CREATE_TOPIC); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'topicId' => ID::unique(), - 'name' => 'topic1', - 'description' => 'Active users', - ], - ]; - $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $topic['headers']['status-code']); - - $query = $this->getQuery(self::$CREATE_USER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'userId' => ID::unique(), - 'email' => 'random2-mail@mail.org', - 'password' => 'password', - 'name' => 'Messaging User', - ] - ]; - $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $user['headers']['status-code']); - - $query = $this->getQuery(self::$CREATE_USER_TARGET); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'targetId' => ID::unique(), - 'providerType' => 'email', - 'userId' => $user['body']['data']['usersCreate']['_id'], - 'providerId' => $providerId, - 'identifier' => $to, - ], - ]; - $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $target['headers']['status-code']); - - $query = $this->getQuery(self::$CREATE_SUBSCRIBER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'subscriberId' => ID::unique(), - 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], - 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], - ], - ]; - $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), $graphQLPayload); - - $this->assertEquals(200, $subscriber['headers']['status-code']); - $query = $this->getQuery(self::$CREATE_EMAIL); $graphQLPayload = [ 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), 'status' => 'draft', - 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$email['topics'][0]], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ], @@ -992,118 +885,13 @@ class MessagingTest extends Scope */ public function testUpdateSMS(array $sms) { - if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { - $this->markTestSkipped('SMS DSN not provided'); - } - - $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); - $to = $smsDSN->getParam('to'); - $from = $smsDSN->getParam('from'); - $authKey = $smsDSN->getPassword(); - $senderId = $smsDSN->getUser(); - - if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { - $this->markTestSkipped('SMS provider not configured'); - } - - $query = $this->getQuery(self::$CREATE_MSG91_PROVIDER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'providerId' => ID::unique(), - 'name' => 'Msg91-2', - 'senderId' => $senderId, - 'authKey' => $authKey, - 'from' => $from, - ], - ]; - $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $provider['headers']['status-code']); - - $providerId = $provider['body']['data']['messagingCreateMsg91Provider']['_id']; - - $query = $this->getQuery(self::$CREATE_TOPIC); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'topicId' => ID::unique(), - 'name' => 'topic1', - 'description' => 'Active users', - ], - ]; - $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $topic['headers']['status-code']); - - $query = $this->getQuery(self::$CREATE_USER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'userId' => ID::unique(), - 'email' => 'random4-email@mail.org', - 'password' => 'password', - 'name' => 'Messaging User', - ] - ]; - $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $user['headers']['status-code']); - - $query = $this->getQuery(self::$CREATE_USER_TARGET); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'targetId' => ID::unique(), - 'providerType' => 'sms', - 'userId' => $user['body']['data']['usersCreate']['_id'], - 'providerId' => $providerId, - 'identifier' => $to, - ], - ]; - $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $target['headers']['status-code']); - - $query = $this->getQuery(self::$CREATE_SUBSCRIBER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'subscriberId' => ID::unique(), - 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], - 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], - ], - ]; - $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), $graphQLPayload); - - $this->assertEquals(200, $subscriber['headers']['status-code']); - $query = $this->getQuery(self::$CREATE_SMS); $graphQLPayload = [ 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), 'status' => 'draft', - 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$sms['topics'][0]], 'content' => '345463', ], ]; @@ -1299,113 +1087,13 @@ class MessagingTest extends Scope */ public function testUpdatePushNotification(array $push) { - if (empty(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'))) { - $this->markTestSkipped('Push DSN empty'); - } - - $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); - $to = $pushDSN->getParam('to'); - $serverKey = $pushDSN->getPassword(); - - if (empty($to) || empty($serverKey)) { - $this->markTestSkipped('Push provider not configured'); - } - - $query = $this->getQuery(self::$CREATE_FCM_PROVIDER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'providerId' => ID::unique(), - 'name' => 'FCM2', - 'serverKey' => $serverKey, - ], - ]; - $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $provider['headers']['status-code']); - $providerId = $provider['body']['data']['messagingCreateFcmProvider']['_id']; - - $query = $this->getQuery(self::$CREATE_TOPIC); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'topicId' => ID::unique(), - 'name' => 'topic1', - 'description' => 'Active users', - ], - ]; - $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $topic['headers']['status-code']); - - $query = $this->getQuery(self::$CREATE_USER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'userId' => ID::unique(), - 'email' => 'random5-email@mail.org', - 'password' => 'password', - 'name' => 'Messaging User', - ] - ]; - $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $user['headers']['status-code']); - - $query = $this->getQuery(self::$CREATE_USER_TARGET); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'targetId' => ID::unique(), - 'providerType' => 'push', - 'userId' => $user['body']['data']['usersCreate']['_id'], - 'providerId' => $providerId, - 'identifier' => $to, - ], - ]; - $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), $graphQLPayload); - - $this->assertEquals(200, $target['headers']['status-code']); - - $query = $this->getQuery(self::$CREATE_SUBSCRIBER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'subscriberId' => ID::unique(), - 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], - 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], - ], - ]; - $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), $graphQLPayload); - - $this->assertEquals(200, $subscriber['headers']['status-code']); - $query = $this->getQuery(self::$CREATE_PUSH_NOTIFICATION); $graphQLPayload = [ 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), 'status' => 'draft', - 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$push['topics'][0]], 'title' => 'Push Notification Title', 'body' => 'Push Notifiaction Body', ], diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 707ba2f7b5..daafd52e8f 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -649,21 +649,6 @@ trait MessagingBase */ public function testUpdateEmail(array $email) { - if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) { - $this->markTestSkipped('Email DSN not provided'); - } - - $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); - $to = $emailDSN->getParam('to'); - $from = $emailDSN->getParam('from'); - $isEuRegion = $emailDSN->getParam('isEuRegion'); - $apiKey = $emailDSN->getPassword(); - $domain = $emailDSN->getUser(); - - if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { - $this->markTestSkipped('Email provider not configured'); - } - $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -673,74 +658,6 @@ trait MessagingBase // Test failure as the message has already been sent. $this->assertEquals(400, $message['headers']['status-code']); - // Create provider - $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/mailgun', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), [ - 'providerId' => ID::unique(), - 'name' => 'Mailgun-provider-2', - 'apiKey' => $apiKey, - 'domain' => $domain, - 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), - 'from' => $from - ]); - - $this->assertEquals(201, $provider['headers']['status-code']); - - // Create Topic - $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'topicId' => ID::unique(), - 'name' => 'topic1', - 'description' => 'Test Topic' - ]); - - $this->assertEquals(201, $topic['headers']['status-code']); - - // Create User - $user = $this->client->call(Client::METHOD_POST, '/users', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'userId' => ID::unique(), - 'email' => 'random-email@mail.org', - 'password' => 'password', - 'name' => 'Messaging User', - ]); - - $this->assertEquals(201, $user['headers']['status-code']); - - // Create Target - $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'targetId' => ID::unique(), - 'providerType' => 'email', - 'providerId' => $provider['body']['$id'], - 'identifier' => $to, - ]); - - $this->assertEquals(201, $target['headers']['status-code']); - - // Create Subscriber - $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'subscriberId' => ID::unique(), - 'targetId' => $target['body']['$id'], - ]); - - $this->assertEquals(201, $subscriber['headers']['status-code']); - // Create Email $email = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [ 'content-type' => 'application/json', @@ -749,7 +666,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'status' => 'draft', - 'topics' => [$topic['body']['$id']], + 'topics' => [$email['body']['topics'][0]], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ]); @@ -897,20 +814,6 @@ trait MessagingBase */ public function testUpdateSMS(array $sms) { - if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { - $this->markTestSkipped('SMS DSN not provided'); - } - - $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); - $to = $smsDSN->getParam('to'); - $from = $smsDSN->getParam('from'); - $authKey = $smsDSN->getPassword(); - $senderId = $smsDSN->getUser(); - - if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { - $this->markTestSkipped('SMS provider not configured'); - } - $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/sms/' . $sms['body']['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -920,73 +823,6 @@ trait MessagingBase // Test failure as the message has already been sent. $this->assertEquals(400, $message['headers']['status-code']); - // Create provider - $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/msg91', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), [ - 'providerId' => ID::unique(), - 'name' => 'Msg91-2', - 'senderId' => $senderId, - 'authKey' => $authKey, - 'from' => $from - ]); - - $this->assertEquals(201, $provider['headers']['status-code']); - - // Create Topic - $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'topicId' => ID::unique(), - 'name' => 'topic1', - 'description' => 'Test Topic' - ]); - - $this->assertEquals(201, $topic['headers']['status-code']); - - // Create User - $user = $this->client->call(Client::METHOD_POST, '/users', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'userId' => ID::unique(), - 'email' => 'random2-email@mail.org', - 'password' => 'password', - 'name' => 'Messaging User', - ]); - - $this->assertEquals(201, $user['headers']['status-code']); - - // Create Target - $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'targetId' => ID::unique(), - 'providerType' => 'sms', - 'providerId' => $provider['body']['$id'], - 'identifier' => $to, - ]); - - $this->assertEquals(201, $target['headers']['status-code']); - - // Create Subscriber - $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'subscriberId' => ID::unique(), - 'targetId' => $target['body']['$id'], - ]); - - $this->assertEquals(201, $subscriber['headers']['status-code']); - // Create SMS $sms = $this->client->call(Client::METHOD_POST, '/messaging/messages/sms', [ 'content-type' => 'application/json', @@ -995,7 +831,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'status' => 'draft', - 'topics' => [$topic['body']['$id']], + 'topics' => [$sms['body']['topics'][0]], 'content' => '047487', ]); @@ -1139,18 +975,6 @@ trait MessagingBase */ public function testUpdatePushNotification(array $push) { - if (empty(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'))) { - $this->markTestSkipped('Push DSN empty'); - } - - $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); - $to = $pushDSN->getParam('to'); - $serverKey = $pushDSN->getPassword(); - - if (empty($to) || empty($serverKey)) { - $this->markTestSkipped('Push provider not configured'); - } - $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/push/' . $push['body']['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -1160,71 +984,6 @@ trait MessagingBase // Test failure as the message has already been sent. $this->assertEquals(400, $message['headers']['status-code']); - // Create provider - $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/fcm', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), [ - 'providerId' => ID::unique(), - 'name' => 'FCM-2', - 'serverKey' => $serverKey, - ]); - - $this->assertEquals(201, $provider['headers']['status-code']); - - // Create Topic - $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'topicId' => ID::unique(), - 'name' => 'topic1', - 'description' => 'Test Topic' - ]); - - $this->assertEquals(201, $topic['headers']['status-code']); - - // Create User - $user = $this->client->call(Client::METHOD_POST, '/users', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'userId' => ID::unique(), - 'email' => 'random4-email@mail.org', - 'password' => 'password', - 'name' => 'Messaging User', - ]); - - $this->assertEquals(201, $user['headers']['status-code']); - - // Create Target - $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'targetId' => ID::unique(), - 'providerType' => 'push', - 'providerId' => $provider['body']['$id'], - 'identifier' => $to, - ]); - - $this->assertEquals(201, $target['headers']['status-code']); - - // Create Subscriber - $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'subscriberId' => ID::unique(), - 'targetId' => $target['body']['$id'], - ]); - - $this->assertEquals(201, $subscriber['headers']['status-code']); - // Create push notification $push = $this->client->call(Client::METHOD_POST, '/messaging/messages/push', [ 'content-type' => 'application/json', @@ -1233,7 +992,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'status' => 'draft', - 'topics' => [$topic['body']['$id']], + 'topics' => [$push['body']['topics'][0]], 'title' => 'Test-Notification', 'body' => 'Test-Notification-Body', ]); From 2aa8391c5e2bc37228ba016a5924b32ed9017efb Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 15 Nov 2023 12:52:27 +0530 Subject: [PATCH 164/196] review fixes --- app/controllers/api/account.php | 12 ++---------- app/controllers/api/messaging.php | 4 ---- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index c5e389dd42..1d6780f48b 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -2063,11 +2063,7 @@ App::patch('/v1/account/email') $oldTarget = $user->find('identifier', $oldEmail, 'targets'); if ($oldTarget !== false && !$oldTarget->isEmpty()) { - try { - $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)); - } catch (Duplicate) { - throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); - } + $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)); } try { @@ -2143,11 +2139,7 @@ App::patch('/v1/account/phone') } if ($oldTarget !== false && !$oldTarget->isEmpty()) { - try { - $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone)); - } catch (Duplicate) { - throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); - } + $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone)); } try { diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index dd5ab2bd1a..1f4f7b62b6 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -814,10 +814,6 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') if ($provider->getAttribute('internal') === true && $enabled === false) { throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); } - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } - $provider->setAttribute('enabled', $enabled); } From c24664f5d93042e3b3b08ed4fee74dfcca7ef5d4 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 16 Nov 2023 01:30:47 +0530 Subject: [PATCH 165/196] removes internal provider --- app/config/collections.php | 22 +- app/config/errors.php | 5 - app/config/variables.php | 2 +- app/controllers/api/account.php | 69 +---- app/controllers/api/messaging.php | 261 +----------------- app/controllers/api/teams.php | 29 +- docker-compose.yml | 2 + src/Appwrite/Event/Messaging.php | 80 +++++- src/Appwrite/Platform/Workers/Messaging.php | 87 +++++- .../Database/Validator/Queries/Providers.php | 1 - .../Utopia/Response/Model/Provider.php | 6 - .../Account/AccountCustomClientTest.php | 67 +---- tests/e2e/Services/GraphQL/AccountTest.php | 31 --- tests/e2e/Services/GraphQL/Base.php | 21 +- 14 files changed, 209 insertions(+), 474 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index f2ee405c92..0d42dfe895 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1416,17 +1416,6 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], - [ - '$id' => ID::custom('internal'), - 'type' => Database::VAR_BOOLEAN, - 'signed' => true, - 'size' => 0, - 'format' => '', - 'filters' => [], - 'required' => false, - 'default' => false, - 'array' => false, - ], [ '$id' => ID::custom('enabled'), 'type' => Database::VAR_BOOLEAN, @@ -1495,16 +1484,9 @@ $commonCollections = [ 'orders' => [Database::ORDER_ASC], ], [ - '$id' => ID::custom('_key_internal'), + '$id' => ID::custom('_key_enabled_type'), 'type' => Database::INDEX_KEY, - 'attributes' => ['internal'], - 'lengths' => [], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_internal_type'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['internal','type'], + 'attributes' => ['enabled','type'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], diff --git a/app/config/errors.php b/app/config/errors.php index e915091940..1117f20e48 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -781,11 +781,6 @@ return [ 'description' => 'Provider with the requested ID is of incorrect type: ', 'code' => 400, ], - Exception::PROVIDER_INTERNAL_UPDATE_DISABLED => [ - 'name' => Exception::PROVIDER_INTERNAL_UPDATE_DISABLED, - 'description' => 'Provider with the requested ID cannot be disabled.', - 'code' => 400, - ], /** Topic Errors */ Exception::TOPIC_NOT_FOUND => [ diff --git a/app/config/variables.php b/app/config/variables.php index 9d555bf013..6f49d4a5da 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -440,7 +440,7 @@ return [ 'variables' => [ [ 'name' => '_APP_SMS_PROVIDER', - 'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'.\n\nEnsure `[USER]` and `[SECRET]` are URL encoded if they contain any non-alphanumeric characters.\n\nAvailable providers are twilio, text-magic, telesign, msg91, and vonage.", + 'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'.\n\nEnsure `[USER]` and `[SECRET]` are URL encoded if they contain any non-alphanumeric characters.\n\nAvailable providers are twilio, textmagic, telesign, msg91, and vonage.", 'introduction' => '0.15.0', 'default' => '', 'required' => false, diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 1d6780f48b..6486147a84 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1260,12 +1260,7 @@ App::post('/v1/account/sessions/phone') ->inject('queueForMessaging') ->inject('locale') ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale) { - $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['sms']) - ])); - - if ($provider === false || $provider->isEmpty()) { + if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -1351,35 +1346,18 @@ App::post('/v1/account/sessions/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); - $target = $dbForProject->findOne('targets', [ - Query::equal('identifier', [$phone]), - ]); - if (!$target || $target->isEmpty()) { - $target = $dbForProject->createDocument('targets', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), - 'providerType' => 'sms', - 'identifier' => $phone, - ])); - $dbForProject->deleteCachedDocument('users', $user->getId()); - } - - $messageDoc = $dbForProject->createDocument('messages', new Document([ + $messageDoc = new Document([ '$id' => $token->getId(), - 'targets' => [$target->getId()], 'data' => [ 'content' => $message, ], - ])); + ]); $queueForMessaging - ->setMessageId($messageDoc->getId()) + ->setMessage($messageDoc) + ->setRecipients([$phone]) + ->setProviderType('SMS') ->setProject($project) ->trigger(); @@ -2964,12 +2942,7 @@ App::post('/v1/account/verification/phone') ->inject('project') ->inject('locale') ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale) { - $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['sms']) - ])); - - if ($provider === false || $provider->isEmpty()) { + if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -3015,35 +2988,17 @@ App::post('/v1/account/verification/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); - $target = $dbForProject->findOne('targets', [ - Query::equal('identifier', [$user->getAttribute('phone')]), - ]); - - if (!$target || $target->isEmpty()) { - $target = $dbForProject->createDocument('targets', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ], - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), - 'providerType' => 'sms', - 'identifier' => $user->getAttribute('phone'), - ])); - $dbForProject->deleteCachedDocument('users', $user->getId()); - } - - $messageDoc = $dbForProject->createDocument('messages', new Document([ + $messageDoc = new Document([ '$id' => $verification->getId(), - 'targets' => [$target->getId()], 'data' => [ 'content' => $message, ], - ])); + ]); $queueForMessaging - ->setMessageId($messageDoc->getId()) + ->setMessage($messageDoc) + ->setRecipients([$user->getAttribute('phone')]) + ->setProviderType('SMS') ->setProject($project) ->trigger(); diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 1f4f7b62b6..e1e531c1a1 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -79,16 +79,6 @@ App::post('/v1/messaging/providers/mailgun') ] ]); - // Check if a internal provider exists, if not, set this one as internal - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['email']) - ])) - ) { - $provider->setAttribute('internal', true); - } - try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { @@ -141,16 +131,6 @@ App::post('/v1/messaging/providers/sendgrid') ] ]); - // Check if a internal provider exists, if not, set this one as internal - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['sms']) - ])) - ) { - $provider->setAttribute('internal', true); - } - try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { @@ -205,16 +185,6 @@ App::post('/v1/messaging/providers/msg91') ] ]); - // Check if a internal provider exists, if not, set this one as internal - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['sms']) - ])) - ) { - $provider->setAttribute('internal', true); - } - try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { @@ -269,16 +239,6 @@ App::post('/v1/messaging/providers/telesign') ] ]); - // Check if a internal provider exists, if not, set this one as internal - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['sms']) - ])) - ) { - $provider->setAttribute('internal', true); - } - try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { @@ -333,16 +293,6 @@ App::post('/v1/messaging/providers/textmagic') ] ]); - // Check if a internal provider exists, if not, set this one as internal - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['sms']) - ])) - ) { - $provider->setAttribute('internal', true); - } - try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { @@ -397,16 +347,6 @@ App::post('/v1/messaging/providers/twilio') ] ]); - // Check if a internal provider exists, if not, set this one as internal - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['sms']) - ])) - ) { - $provider->setAttribute('internal', true); - } - try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { @@ -461,16 +401,6 @@ App::post('/v1/messaging/providers/vonage') ] ]); - // Check if a internal provider exists, if not, set this one as internal - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['sms']) - ])) - ) { - $provider->setAttribute('internal', true); - } - try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { @@ -519,16 +449,6 @@ App::post('/v1/messaging/providers/fcm') ], ]); - // Check if a internal provider exists, if not, set this one as internal - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['push']) - ])) - ) { - $provider->setAttribute('internal', true); - } - try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { @@ -585,16 +505,6 @@ App::post('/v1/messaging/providers/apns') ], ]); - // Check if a internal provider exists, if not, set this one as internal - if ( - empty($dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['push']) - ])) - ) { - $provider->setAttribute('internal', true); - } - try { $provider = $dbForProject->createDocument('providers', $provider); } catch (DuplicateException) { @@ -776,7 +686,6 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) ->param('from', '', new Text(256), 'Sender email address.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) @@ -784,7 +693,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -806,14 +715,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ]); } - if ($internal === true) { - $provider->setAttribute('internal', $internal); - } - if ($enabled === true || $enabled === false) { - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } $provider->setAttribute('enabled', $enabled); } @@ -835,15 +737,6 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - if ($internal === true) { - $internalProvider = $dbForProject->findOne('providers', [ - 'internal' => true, - 'type' => 'email', - ]); - $internalProvider->setAttribute('internal', false); - $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); - } - $queueForEvents ->setParam('providerId', $provider->getId()); @@ -868,13 +761,12 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->param('from', '', new Text(256), 'Sender email address.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -896,14 +788,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ]); } - if ($internal === true) { - $provider->setAttribute('internal', $internal); - } - if ($enabled === true || $enabled === false) { - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } $provider->setAttribute('enabled', $enabled); } @@ -915,15 +800,6 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - if ($internal === true) { - $internalProvider = $dbForProject->findOne('providers', [ - 'internal' => true, - 'type' => 'email', - ]); - $internalProvider->setAttribute('internal', false); - $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); - } - $queueForEvents ->setParam('providerId', $provider->getId()); @@ -948,14 +824,13 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $senderId, string $authKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $senderId, string $authKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -977,14 +852,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ]); } - if ($internal === true) { - $provider->setAttribute('internal', $internal); - } - if ($enabled === true || $enabled === false) { - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } $provider->setAttribute('enabled', $enabled); } @@ -1002,15 +870,6 @@ App::patch('/v1/messaging/providers/msg91/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - if ($internal === true) { - $internalProvider = $dbForProject->findOne('providers', [ - 'internal' => true, - 'type' => 'email', - ]); - $internalProvider->setAttribute('internal', false); - $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); - } - $queueForEvents ->setParam('providerId', $provider->getId()); @@ -1035,14 +894,13 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('username', '', new Text(0), 'Telesign username.', true) ->param('password', '', new Text(0), 'Telesign password.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $password, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $password, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1064,14 +922,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ]); } - if ($internal === true) { - $provider->setAttribute('internal', $internal); - } - if ($enabled === true || $enabled === false) { - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } $provider->setAttribute('enabled', $enabled); } @@ -1089,15 +940,6 @@ App::patch('/v1/messaging/providers/telesign/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - if ($internal === true) { - $internalProvider = $dbForProject->findOne('providers', [ - 'internal' => true, - 'type' => 'email', - ]); - $internalProvider->setAttribute('internal', false); - $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); - } - $queueForEvents ->setParam('providerId', $provider->getId()); @@ -1122,14 +964,13 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1151,14 +992,7 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ]); } - if ($internal === true) { - $provider->setAttribute('internal', $internal); - } - if ($enabled === true || $enabled === false) { - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } $provider->setAttribute('enabled', $enabled); } @@ -1176,15 +1010,6 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - if ($internal === true) { - $internalProvider = $dbForProject->findOne('providers', [ - 'internal' => true, - 'type' => 'email', - ]); - $internalProvider->setAttribute('internal', false); - $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); - } - $queueForEvents ->setParam('providerId', $provider->getId()); @@ -1209,14 +1034,13 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $accountSid, string $authToken, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $accountSid, string $authToken, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1238,14 +1062,7 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ]); } - if ($internal === true) { - $provider->setAttribute('internal', $internal); - } - if ($enabled === true || $enabled === false) { - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } $provider->setAttribute('enabled', $enabled); } @@ -1263,15 +1080,6 @@ App::patch('/v1/messaging/providers/twilio/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - if ($internal === true) { - $internalProvider = $dbForProject->findOne('providers', [ - 'internal' => true, - 'type' => 'email', - ]); - $internalProvider->setAttribute('internal', false); - $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); - } - $queueForEvents ->setParam('providerId', $provider->getId()); @@ -1296,14 +1104,13 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $apiSecret, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $apiSecret, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1325,14 +1132,7 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ]); } - if ($internal === true) { - $provider->setAttribute('internal', $internal); - } - if ($enabled === true || $enabled === false) { - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } $provider->setAttribute('enabled', $enabled); } @@ -1350,15 +1150,6 @@ App::patch('/v1/messaging/providers/vonage/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - if ($internal === true) { - $internalProvider = $dbForProject->findOne('providers', [ - 'internal' => true, - 'type' => 'email', - ]); - $internalProvider->setAttribute('internal', false); - $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); - } - $queueForEvents ->setParam('providerId', $provider->getId()); @@ -1383,12 +1174,11 @@ App::patch('/v1/messaging/providers/fcm/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $serverKey, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $serverKey, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1404,14 +1194,7 @@ App::patch('/v1/messaging/providers/fcm/:providerId') $provider->setAttribute('name', $name); } - if ($internal === true) { - $provider->setAttribute('internal', $internal); - } - if ($enabled === true || $enabled === false) { - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } $provider->setAttribute('enabled', $enabled); } @@ -1421,15 +1204,6 @@ App::patch('/v1/messaging/providers/fcm/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - if ($internal === true) { - $internalProvider = $dbForProject->findOne('providers', [ - 'internal' => true, - 'type' => 'email', - ]); - $internalProvider->setAttribute('internal', false); - $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); - } - $queueForEvents ->setParam('providerId', $provider->getId()); @@ -1455,7 +1229,6 @@ App::patch('/v1/messaging/providers/apns/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('authKey', '', new Text(0), 'APNS authentication key.', true) ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) ->param('teamId', '', new Text(0), 'APNS team ID.', true) @@ -1464,7 +1237,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1480,14 +1253,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider->setAttribute('name', $name); } - if ($internal === true) { - $provider->setAttribute('internal', $internal); - } - if ($enabled === true || $enabled === false) { - if ($provider->getAttribute('internal') === true && $enabled === false) { - throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED); - } $provider->setAttribute('enabled', $enabled); } @@ -1517,15 +1283,6 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); - if ($internal === true) { - $internalProvider = $dbForProject->findOne('providers', [ - 'internal' => true, - 'type' => 'email', - ]); - $internalProvider->setAttribute('internal', false); - $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); - } - $queueForEvents ->setParam('providerId', $provider->getId()); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index b19080e894..2ba27efcb3 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -628,12 +628,7 @@ App::post('/v1/teams/:teamId/memberships') ->trigger() ; } elseif (!empty($phone)) { - $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('internal', [true]), - Query::equal('type', ['sms']) - ])); - - if ($provider === false || $provider->isEmpty()) { + if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -647,27 +642,17 @@ App::post('/v1/teams/:teamId/memberships') $message = $message->setParam('{{token}}', $url); $message = $message->render(); - $target = $dbForProject->createDocument('targets', new Document([ - 'userId' => $invitee->getId(), - 'userInternalId' => $invitee->getInternalId(), - 'providerType' => 'sms', - 'identifier' => $phone, - ])); - - $messageDoc = $dbForProject->createDocument('messages', new Document([ - // Here membership ID is used as message ID so that it can be used in test cases to verify the message - '$id' => $membership->getId(), - 'targets' => [$target->getId()], + $messageDoc = new Document([ + '$id' => ID::unique(), 'data' => [ 'content' => $message, ], - 'providerId' => $provider->getId(), - 'providerInternalId' => $provider->getInternalId(), - 'deliveryTime' => Datetime::now(), - ])); + ]); $queueForMessaging - ->setMessageId($messageDoc->getId()) + ->setMessage($messageDoc) + ->setRecipients([$phone]) + ->setProviderType('SMS') ->setProject($project) ->trigger(); } diff --git a/docker-compose.yml b/docker-compose.yml index 8255508356..a570c5b619 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -582,6 +582,8 @@ services: - _APP_DB_PASS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG + - _APP_SMS_FROM + - _APP_SMS_PROVIDER appwrite-worker-migrations: entrypoint: worker-migrations diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index 76abecd1c0..354418486b 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -9,7 +9,11 @@ use Utopia\Queue\Client; class Messaging extends Event { protected ?string $messageId = null; - private ?string $deliveryTime = null; + protected ?Document $message = null; + protected ?array $recipients = null; + protected ?string $deliveryTime = null; + protected ?string $providerType = null; + public function __construct(protected Connection $connection) { @@ -20,6 +24,52 @@ class Messaging extends Event ->setClass(Event::MESSAGING_CLASS_NAME); } + /** + * Sets recipient for the messaging event. + * + * @param string[] $recipients + * @return self + */ + public function setRecipients(array $recipients): self + { + $this->recipients = $recipients; + + return $this; + } + + /** + * Returns set recipient for messaging event. + * + * @return string[] + */ + public function getRecipient(): array + { + return $this->recipients; + } + + /** + * Sets message document for the messaging event. + * + * @param Document $message + * @return self + */ + public function setMessage(Document $message): self + { + $this->message = $message; + + return $this; + } + + /** + * Returns message document for the messaging event. + * + * @return string + */ + public function getMessage(): Document + { + return $this->message; + } + /** * Sets message ID for the messaging event. * @@ -43,6 +93,29 @@ class Messaging extends Event return $this->messageId; } + /** + * Sets provider type for the messaging event. + * + * @param string $providerType + * @return self + */ + public function setProviderType(string $providerType): self + { + $this->providerType = $providerType; + + return $this; + } + + /** + * Returns set provider type for the messaging event. + * + * @return string + */ + public function getProviderType(): string + { + return $this->providerType; + } + /** * Sets Delivery time for the messaging event. * @@ -92,6 +165,9 @@ class Messaging extends Event 'project' => $this->project, 'user' => $this->user, 'messageId' => $this->messageId, + 'message' => $this->message, + 'recipients' => $this->recipients, + 'providerType' => $this->providerType, ]); } -} +} \ No newline at end of file diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 68bae1b4d0..b2b0094a88 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -3,7 +3,10 @@ namespace Appwrite\Platform\Workers; use Appwrite\Extend\Exception; +use Utopia\App; use Utopia\CLI\Console; +use Utopia\Database\Helpers\ID; +use Utopia\DSN\DSN; use Utopia\Platform\Action; use Utopia\Queue\Message; use Utopia\Database\Database; @@ -63,11 +66,19 @@ class Messaging extends Action return; } - $message = $dbForProject->getDocument('messages', $payload['messageId']); + if (!\is_null($payload['message']) && !\is_null($payload['recipients'])) { + if ($payload['providerType'] === 'SMS') { + $this->processInternalSMSMessage(new Document($payload['message']), $payload['recipients']); + } + } else { + $message = $dbForProject->getDocument('messages', $payload['messageId']); - $this->processMessage($dbForProject, $message); + $this->processMessage($dbForProject, $message); + } } + + private function processMessage(Database $dbForProject, Document $message): void { $topicsId = $message->getAttribute('topics', []); @@ -99,7 +110,7 @@ class Messaging extends Action } $internalProvider = $dbForProject->findOne('providers', [ - Query::equal('internal', [true]), + Query::equal('enabled', [true]), Query::equal('type', [$recipients[0]->getAttribute('providerType')]), ]); @@ -215,6 +226,74 @@ class Messaging extends Action $dbForProject->updateDocument('messages', $message->getId(), $message); } + private function processInternalSMSMessage(Document $message, array $recipients): void + { + if(empty(App::getEnv('_APP_SMS_PROVIDER')) || empty(App::getEnv('_APP_SMS_FROM'))) { + Console::info('Skipped SMS processing. No Phone configuration has been set.'); + return; + } + + $smsDSN = new DSN(App::getEnv('_APP_SMS_PROVIDER')); + $host = $smsDSN->getHost(); + $password = $smsDSN->getPassword(); + $user = $smsDSN->getUser(); + + $from = App::getEnv('_APP_SMS_FROM'); + + $provider = new Document([ + '$id' => ID::unique(), + 'provider' => $host, + 'type' => 'sms', + 'name' => 'Internal SMS', + 'enabled' => true, + 'credentials' => match ($host) { + 'twilio' => [ + 'accountSid' => $user, + 'authToken' => $password + ], + 'textmagic' => [ + 'username' => $user, + 'apiKey' => $password + ], + 'telesign' => [ + 'username' => $user, + 'password' => $password + ], + 'msg91' => [ + 'senderId' => $user, + 'authKey' => $password + ], + 'vonage' => [ + 'apiKey' => $user, + 'apiSecret' => $password + ], + default => null + }, + 'options' => [ + 'from' => $from + ] + ]); + $adapter = $this->sms($provider); + + $maxBatchSize = $adapter->getMaxMessagesPerRequest(); + $batches = \array_chunk($recipients, $maxBatchSize); + $batchIndex = 0; + + batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex) { + return function () use ($batch, $message, $provider, $adapter, $batchIndex) { + $message->setAttribute('to', $batch); + + $data = $this->buildSMSMessage($message, $provider); + + try { + $adapter->send($data); + } catch (\Exception $e) { + Console::error('Failed sending to targets ' . $batchIndex + 1 . '-' . \count($batch) . ' with error: ' . $e->getMessage()); + } + }; + }, $batches)); + } + public function shutdown(): void { } @@ -225,7 +304,7 @@ class Messaging extends Action return match ($provider->getAttribute('provider')) { 'mock' => new Mock('username', 'password'), 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), - 'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']), + 'textmagic' => new TextMagic($credentials['username'], $credentials['apiKey']), 'telesign' => new Telesign($credentials['username'], $credentials['password']), 'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']), 'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']), diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php index 7760acbdad..a28f5e8437 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php @@ -8,7 +8,6 @@ class Providers extends Base 'name', 'provider', 'type', - 'internal', 'enabled', ]; diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index a121753275..f8a0514020 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -40,12 +40,6 @@ class Provider extends Model 'default' => '', 'example' => 'mailgun', ]) - ->addRule('internal', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is this a pre-configured provider instance?', - 'default' => false, - 'example' => true, - ]) ->addRule('enabled', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Is provider enabled?', diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index d56f93a42c..1cc9e6c325 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -744,33 +744,8 @@ class AccountCustomClientTest extends Scope public function testCreatePhone(): array { - if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { - $this->markTestSkipped('SMS DSN not provided'); - } + $number = '+123456789'; - $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); - $to = $smsDSN->getParam('to'); - $from = $smsDSN->getParam('from'); - $authKey = $smsDSN->getPassword(); - $senderId = $smsDSN->getUser(); - - if (empty($to) || empty($from) || empty($authKey) || empty($senderId)) { - $this->markTestSkipped('SMS provider not configured'); - } - - $number = $to; - $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/msg91', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]), [ - 'providerId' => ID::unique(), - 'name' => 'Sms provider', - 'senderId' => $senderId, - 'authKey' => $authKey, - 'from' => $from, - ]); - $this->assertEquals(201, $response['headers']['status-code']); /** * Test for SUCCESS */ @@ -781,7 +756,6 @@ class AccountCustomClientTest extends Scope ]), [ 'userId' => ID::unique(), 'phone' => $number, - 'from' => $from, ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -807,19 +781,17 @@ class AccountCustomClientTest extends Scope \sleep(5); - $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $messageId, [ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]); + $smsRequest = $this->getLastRequest(); - $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTotal']); - $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + $this->assertEquals('http://request-catcher:5000/mock-sms', $smsRequest['url']); + $this->assertEquals('Appwrite Mock Message Sender', $smsRequest['headers']['User-Agent']); + $this->assertEquals('username', $smsRequest['headers']['X-Username']); + $this->assertEquals('password', $smsRequest['headers']['X-Key']); + $this->assertEquals('POST', $smsRequest['method']); + $this->assertEquals('+123456789', $smsRequest['data']['from']); + $this->assertEquals($number, $smsRequest['data']['to']); - - $data['token'] = $message['body']['data']['content']; + $data['token'] = $smsRequest['data']['message']; $data['id'] = $userId; $data['number'] = $number; @@ -1018,8 +990,6 @@ class AccountCustomClientTest extends Scope public function testPhoneVerification(array $data): array { $session = $data['session'] ?? ''; - $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); - $from = $smsDSN->getParam('from'); /** * Test for SUCCESS @@ -1030,28 +1000,19 @@ class AccountCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ]), ['from' => $from]); + ])); $this->assertEquals(201, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); $this->assertEmpty($response['body']['secret']); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['expire'])); - \sleep(3); + \sleep(2); - $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $response['body']['$id'], [ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ]); - - $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTotal']); - $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + $smsRequest = $this->getLastRequest(); return \array_merge($data, [ - 'token' => $message['body']['data']['content'] + 'token' => $smsRequest['data']['secret'] ]); } diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 9d1da09feb..3e2cfac29c 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -124,38 +124,7 @@ class AccountTest extends Scope */ public function testCreatePhoneVerification(): array { - if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) { - $this->markTestSkipped('SMS DSN not provided'); - } - - $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); - $to = $smsDSN->getParam('to'); - $from = $smsDSN->getParam('from'); - $authKey = $smsDSN->getPassword(); - $senderId = $smsDSN->getUser(); - - if (empty($to) || empty($from) || empty($authKey) || empty($senderId)) { - $this->markTestSkipped('SMS provider not configured'); - } - $projectId = $this->getProject()['$id']; - $query = $this->getQuery(self::$CREATE_MSG91_PROVIDER); - $graphQLPayload = [ - 'query' => $query, - 'variables' => [ - 'providerId' => ID::unique(), - 'name' => 'Sms Provider', - 'from' => $from, - 'senderId' => $senderId, - 'authKey' => $authKey, - ], - ]; - - $response = $this->client->call(Client::METHOD_POST, '/graphql', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $projectId, - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], $graphQLPayload); $query = $this->getQuery(self::$CREATE_PHONE_VERIFICATION); $graphQLPayload = [ diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index b57b680674..707905892c 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1796,7 +1796,6 @@ trait Base name provider type - internal enabled } }'; @@ -1807,7 +1806,6 @@ trait Base name provider type - internal enabled } }'; @@ -1818,7 +1816,6 @@ trait Base name provider type - internal enabled } }'; @@ -1829,7 +1826,6 @@ trait Base name provider type - internal enabled } }'; @@ -1840,7 +1836,6 @@ trait Base name provider type - internal enabled } }'; @@ -1851,7 +1846,6 @@ trait Base name provider type - internal enabled } }'; @@ -1862,7 +1856,6 @@ trait Base name provider type - internal enabled } }'; @@ -1873,7 +1866,6 @@ trait Base name provider type - internal enabled } }'; @@ -1884,7 +1876,6 @@ trait Base name provider type - internal enabled } }'; @@ -1897,7 +1888,7 @@ trait Base name provider type - internal + enabled } } @@ -1909,7 +1900,6 @@ trait Base name provider type - internal enabled } }'; @@ -1920,7 +1910,6 @@ trait Base name provider type - internal enabled } }'; @@ -1931,7 +1920,6 @@ trait Base name provider type - internal enabled } }'; @@ -1942,7 +1930,6 @@ trait Base name provider type - internal enabled } }'; @@ -1953,7 +1940,6 @@ trait Base name provider type - internal enabled } }'; @@ -1964,7 +1950,6 @@ trait Base name provider type - internal enabled } }'; @@ -1975,7 +1960,6 @@ trait Base name provider type - internal enabled } }'; @@ -1986,7 +1970,6 @@ trait Base name provider type - internal enabled } }'; @@ -1997,7 +1980,6 @@ trait Base name provider type - internal enabled } }'; @@ -2008,7 +1990,6 @@ trait Base name provider type - internal enabled } }'; From 549dcc493dc0703505546c473147db6d635264d0 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 16 Nov 2023 01:33:05 +0530 Subject: [PATCH 166/196] lint fix --- src/Appwrite/Event/Messaging.php | 4 ++-- src/Appwrite/Platform/Workers/Messaging.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index 354418486b..62d41f8c3b 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -13,7 +13,7 @@ class Messaging extends Event protected ?array $recipients = null; protected ?string $deliveryTime = null; protected ?string $providerType = null; - + public function __construct(protected Connection $connection) { @@ -170,4 +170,4 @@ class Messaging extends Event 'providerType' => $this->providerType, ]); } -} \ No newline at end of file +} diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index b2b0094a88..2283770e09 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -77,7 +77,7 @@ class Messaging extends Action } } - + private function processMessage(Database $dbForProject, Document $message): void { @@ -228,7 +228,7 @@ class Messaging extends Action private function processInternalSMSMessage(Document $message, array $recipients): void { - if(empty(App::getEnv('_APP_SMS_PROVIDER')) || empty(App::getEnv('_APP_SMS_FROM'))) { + if (empty(App::getEnv('_APP_SMS_PROVIDER')) || empty(App::getEnv('_APP_SMS_FROM'))) { Console::info('Skipped SMS processing. No Phone configuration has been set.'); return; } From c728d9bc8e07fd0431ffa2924158fe99052303e3 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 16 Nov 2023 01:36:22 +0530 Subject: [PATCH 167/196] lint fix --- src/Appwrite/Platform/Workers/Messaging.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 2283770e09..299ef4526f 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -77,8 +77,6 @@ class Messaging extends Action } } - - private function processMessage(Database $dbForProject, Document $message): void { $topicsId = $message->getAttribute('topics', []); @@ -273,6 +271,7 @@ class Messaging extends Action 'from' => $from ] ]); + $adapter = $this->sms($provider); $maxBatchSize = $adapter->getMaxMessagesPerRequest(); From a282ab38a6f42a718ce7c2132f134f55450d2026 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 16 Nov 2023 02:12:06 +0530 Subject: [PATCH 168/196] adds target endpoint in account controller for push tokensl --- app/config/collections.php | 11 +++ app/controllers/api/account.php | 153 ++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) diff --git a/app/config/collections.php b/app/config/collections.php index 0d42dfe895..0c67cd175f 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1870,6 +1870,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('name'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['json'], + ], ], 'indexes' => [ [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 6486147a84..71a5562ae3 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1677,6 +1677,96 @@ App::post('/v1/account/jwt') ])]), Response::MODEL_JWT); }); +App::post('/v1/account/targets') + ->desc('Create Account Target') + ->groups(['api', 'account']) + ->label('error', __DIR__ . '/../../views/general/error.phtml') + ->label('audits.event', 'target.create') + ->label('audits.resource', 'target/response.$id') + ->label('event', 'users.[userId].targets.[targetId].create') + ->label('scope', 'public') + ->label('docs', false) + ->param('targetId', '', new CustomId(), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerType', '', new WhiteList(['email', 'sms', 'push']), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.') + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') + ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) + ->param('name', '', new Text(256), 'Set Client device name manually instead of using user agent. Used to identify the client device make, model, OS, etc.', true) + ->inject('queueForEvents') + ->inject('user') + ->inject('request') + ->inject('response') + ->inject('dbForProject') + ->action(function (string $targetId, string $providerType, string $identifier, string $providerId, string $name, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { + $targetId = $targetId == 'unique()' ? ID::unique() : $targetId; + + $provider = new Document(); + + if ($providerType === 'push') { + $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + } + + if ($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); + + if (!$target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + + $detector = new Detector($request->getUserAgent()); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + try { + $target = $dbForProject->createDocument('targets', new Document([ + '$id' => $targetId, + '$permissions' => [ + Permission::read(Role::user($user->getId())), + Permission::update(Role::user($user->getId())), + ], + 'providerId' => $providerId ?? null, + 'providerInternalId' => $provider->getInternalId() ?? null, + 'providerType' => $providerType, + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'identifier' => $identifier, + 'name' => $name ?? [ + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ] + ])); + } catch (Duplicate) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + Authorization::skip(fn () => $dbForProject->deleteCachedDocument('users', $user->getId())); + + $queueForEvents + ->setParam('userId', $user->getId()) + ->setParam('targetId', $target->getId()); + + $response + ->dynamic($target, Response::MODEL_TARGET); + }); + App::get('/v1/account') ->desc('Get account') ->groups(['api', 'account']) @@ -3077,3 +3167,66 @@ App::put('/v1/account/verification/phone') $response->dynamic($verificationDocument, Response::MODEL_TOKEN); }); + +App::put('/v1/account/targets/:targetId') + ->desc('Update Account Target') + ->groups(['api', 'account']) + ->label('error', __DIR__ . '/../../views/general/error.phtml') + ->label('audits.event', 'target.update') + ->label('audits.resource', 'target/response.$id') + ->label('event', 'users.[userId].targets.[targetId].create') + ->label('scope', 'public') + ->label('docs', false) + ->param('targetId', '', new UID(), 'Target ID.') + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) + ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) + ->param('name', '', new Text(256), 'Set Client device name manually instead of using user agent. Used to identify the client device make, model, OS, etc.', true) + ->inject('queueForEvents') + ->inject('user') + ->inject('request') + ->inject('response') + ->inject('dbForProject') + ->action(function (string $targetId, string $identifier, string $providerId, string $name, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { + if ($user->isEmpty()) { + throw new Exception(Exception::USER_NOT_FOUND); + } + + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); + + if ($target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + if ($user->getId() !== $target->getAttribute('userId')) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + if ($identifier) { + $target->setAttribute('identifier', $identifier); + } + + if ($providerId) { + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $target->setAttribute('providerId', $provider->getId()); + $target->setAttribute('providerInternalId', $provider->getInternalId()); + } + + if ($name) { + $target->setAttribute('name', $name); + } + + $target = $dbForProject->updateDocument('targets', $target->getId(), $target); + Authorization::skip(fn () => $dbForProject->deleteCachedDocument('users', $user->getId())); + + $queueForEvents + ->setParam('userId', $user->getId()) + ->setParam('targetId', $target->getId()); + + $response + ->dynamic($target, Response::MODEL_TARGET); + }); From c1869bb0caf62cf89829d2e495981df4a86d72e7 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 16 Nov 2023 11:20:39 +0530 Subject: [PATCH 169/196] adds messaging in test workflow --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 842d61ff1c..14e1ac5e44 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -99,6 +99,7 @@ jobs: Users, Webhooks, VCS, + Messaging, ] steps: From f85462270584982d4b928a8fa2abb2493973ea93 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 16 Nov 2023 16:26:36 +0530 Subject: [PATCH 170/196] review changes --- app/controllers/api/account.php | 63 ++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 71a5562ae3..154e385c76 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1677,36 +1677,35 @@ App::post('/v1/account/jwt') ])]), Response::MODEL_JWT); }); -App::post('/v1/account/targets') +App::post('/v1/account/targets/push') ->desc('Create Account Target') ->groups(['api', 'account']) ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('audits.event', 'target.create') ->label('audits.resource', 'target/response.$id') ->label('event', 'users.[userId].targets.[targetId].create') - ->label('scope', 'public') + ->label('sdk.auth', [APP_AUTH_TYPE_SESSION]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'createTarget') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TARGET) ->label('docs', false) ->param('targetId', '', new CustomId(), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('providerType', '', new WhiteList(['email', 'sms', 'push']), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.') + ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') - ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) - ->param('name', '', new Text(256), 'Set Client device name manually instead of using user agent. Used to identify the client device make, model, OS, etc.', true) ->inject('queueForEvents') ->inject('user') ->inject('request') ->inject('response') ->inject('dbForProject') - ->action(function (string $targetId, string $providerType, string $identifier, string $providerId, string $name, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { + ->action(function (string $targetId, string $providerId, string $identifier, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { $targetId = $targetId == 'unique()' ? ID::unique() : $targetId; - $provider = new Document(); + $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); - if ($providerType === 'push') { - $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); - - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); } if ($user->isEmpty()) { @@ -1735,11 +1734,11 @@ App::post('/v1/account/targets') ], 'providerId' => $providerId ?? null, 'providerInternalId' => $provider->getInternalId() ?? null, - 'providerType' => $providerType, + 'providerType' => 'push', 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), 'identifier' => $identifier, - 'name' => $name ?? [ + 'name' => [ 'osCode' => $os['osCode'], 'osName' => $os['osName'], 'osVersion' => $os['osVersion'], @@ -1749,7 +1748,6 @@ App::post('/v1/account/targets') 'clientVersion' => $client['clientVersion'], 'clientEngine' => $client['clientEngine'], 'clientEngineVersion' => $client['clientEngineVersion'], - 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], 'deviceModel' => $device['deviceModel'] ] @@ -1757,13 +1755,14 @@ App::post('/v1/account/targets') } catch (Duplicate) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } - Authorization::skip(fn () => $dbForProject->deleteCachedDocument('users', $user->getId())); + $dbForProject->deleteCachedDocument('users', $user->getId()); $queueForEvents ->setParam('userId', $user->getId()) ->setParam('targetId', $target->getId()); $response + ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($target, Response::MODEL_TARGET); }); @@ -3168,7 +3167,7 @@ App::put('/v1/account/verification/phone') $response->dynamic($verificationDocument, Response::MODEL_TOKEN); }); -App::put('/v1/account/targets/:targetId') +App::put('/v1/account/targets/:targetId/push') ->desc('Update Account Target') ->groups(['api', 'account']) ->label('error', __DIR__ . '/../../views/general/error.phtml') @@ -3180,13 +3179,12 @@ App::put('/v1/account/targets/:targetId') ->param('targetId', '', new UID(), 'Target ID.') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) - ->param('name', '', new Text(256), 'Set Client device name manually instead of using user agent. Used to identify the client device make, model, OS, etc.', true) ->inject('queueForEvents') ->inject('user') ->inject('request') ->inject('response') ->inject('dbForProject') - ->action(function (string $targetId, string $identifier, string $providerId, string $name, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { + ->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { if ($user->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); } @@ -3216,12 +3214,29 @@ App::put('/v1/account/targets/:targetId') $target->setAttribute('providerInternalId', $provider->getInternalId()); } - if ($name) { - $target->setAttribute('name', $name); - } + $detector = new Detector($request->getUserAgent()); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + $target->setAttribute('name', [ + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ]); $target = $dbForProject->updateDocument('targets', $target->getId(), $target); - Authorization::skip(fn () => $dbForProject->deleteCachedDocument('users', $user->getId())); + $dbForProject->deleteCachedDocument('users', $user->getId()); $queueForEvents ->setParam('userId', $user->getId()) From bf95736da0db399588ba6f028254bab63f09c787 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 16 Nov 2023 16:47:36 +0530 Subject: [PATCH 171/196] review changes --- app/controllers/api/account.php | 61 +++++++-------------------------- 1 file changed, 13 insertions(+), 48 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 154e385c76..45beab5ec6 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1678,7 +1678,7 @@ App::post('/v1/account/jwt') }); App::post('/v1/account/targets/push') - ->desc('Create Account Target') + ->desc('Create Account\'s push target') ->groups(['api', 'account']) ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('audits.event', 'target.create') @@ -1686,7 +1686,7 @@ App::post('/v1/account/targets/push') ->label('event', 'users.[userId].targets.[targetId].create') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION]) ->label('sdk.namespace', 'account') - ->label('sdk.method', 'createTarget') + ->label('sdk.method', 'createPushTarget') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET) @@ -1721,8 +1721,6 @@ App::post('/v1/account/targets/push') $detector = new Detector($request->getUserAgent()); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) - $os = $detector->getOS(); - $client = $detector->getClient(); $device = $detector->getDevice(); try { @@ -1738,19 +1736,7 @@ App::post('/v1/account/targets/push') 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), 'identifier' => $identifier, - 'name' => [ - 'osCode' => $os['osCode'], - 'osName' => $os['osName'], - 'osVersion' => $os['osVersion'], - 'clientType' => $client['clientType'], - 'clientCode' => $client['clientCode'], - 'clientName' => $client['clientName'], - 'clientVersion' => $client['clientVersion'], - 'clientEngine' => $client['clientEngine'], - 'clientEngineVersion' => $client['clientEngineVersion'], - 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'] - ] + 'name' => "{$device['deviceBrand']} {$device['deviceModel']}" ])); } catch (Duplicate) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); @@ -3168,23 +3154,27 @@ App::put('/v1/account/verification/phone') }); App::put('/v1/account/targets/:targetId/push') - ->desc('Update Account Target') + ->desc('Update Account\'s push target') ->groups(['api', 'account']) ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('audits.event', 'target.update') ->label('audits.resource', 'target/response.$id') - ->label('event', 'users.[userId].targets.[targetId].create') - ->label('scope', 'public') + ->label('event', 'users.[userId].targets.[targetId].update') + ->label('sdk.auth', [APP_AUTH_TYPE_SESSION]) + ->label('sdk.namespace', 'account') + ->label('sdk.method', 'updatePushTarget') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TARGET) ->label('docs', false) ->param('targetId', '', new UID(), 'Target ID.') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) - ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) ->inject('queueForEvents') ->inject('user') ->inject('request') ->inject('response') ->inject('dbForProject') - ->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { + ->action(function (string $targetId, string $identifier, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) { if ($user->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); } @@ -3203,37 +3193,12 @@ App::put('/v1/account/targets/:targetId/push') $target->setAttribute('identifier', $identifier); } - if ($providerId) { - $provider = $dbForProject->getDocument('providers', $providerId); - - if ($provider->isEmpty()) { - throw new Exception(Exception::PROVIDER_NOT_FOUND); - } - - $target->setAttribute('providerId', $provider->getId()); - $target->setAttribute('providerInternalId', $provider->getInternalId()); - } - $detector = new Detector($request->getUserAgent()); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) - $os = $detector->getOS(); - $client = $detector->getClient(); $device = $detector->getDevice(); - $target->setAttribute('name', [ - 'osCode' => $os['osCode'], - 'osName' => $os['osName'], - 'osVersion' => $os['osVersion'], - 'clientType' => $client['clientType'], - 'clientCode' => $client['clientCode'], - 'clientName' => $client['clientName'], - 'clientVersion' => $client['clientVersion'], - 'clientEngine' => $client['clientEngine'], - 'clientEngineVersion' => $client['clientEngineVersion'], - 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'] - ]); + $target->setAttribute('name', "{$device['deviceBrand']} {$device['deviceModel']}"); $target = $dbForProject->updateDocument('targets', $target->getId(), $target); $dbForProject->deleteCachedDocument('users', $user->getId()); From 7536d8eb0feb3f1c097941385a4f3e7b1e85c0c6 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 16 Nov 2023 17:09:08 +0530 Subject: [PATCH 172/196] review changes --- app/config/collections.php | 4 ++-- app/controllers/api/account.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 0c67cd175f..0596faece7 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1874,12 +1874,12 @@ $commonCollections = [ '$id' => ID::custom('name'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 16384, + 'size' => Database::LENGTH_KEY, 'signed' => true, 'required' => false, 'default' => null, 'array' => false, - 'filters' => ['json'], + 'filters' => [''], ], ], 'indexes' => [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 45beab5ec6..783b8151a4 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -3168,7 +3168,7 @@ App::put('/v1/account/targets/:targetId/push') ->label('sdk.response.model', Response::MODEL_TARGET) ->label('docs', false) ->param('targetId', '', new UID(), 'Target ID.') - ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) + ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') ->inject('queueForEvents') ->inject('user') ->inject('request') From f0247930dab35a47e9f1534967cf8598ef20cd32 Mon Sep 17 00:00:00 2001 From: Prateek Banga <30731059+fanatic75@users.noreply.github.com> Date: Thu, 16 Nov 2023 17:15:08 +0530 Subject: [PATCH 173/196] Update app/config/collections.php Co-authored-by: Jake Barnby --- app/config/collections.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/collections.php b/app/config/collections.php index 0596faece7..7e715baa2c 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1879,7 +1879,7 @@ $commonCollections = [ 'required' => false, 'default' => null, 'array' => false, - 'filters' => [''], + 'filters' => [], ], ], 'indexes' => [ From 5c1cf3a526544bb2ef38f4e0461b881b9740dac1 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 20 Nov 2023 12:34:50 +0530 Subject: [PATCH 174/196] adds user name in subscriber response model --- app/config/collections.php | 36 +++++++++++++++++++ app/controllers/api/messaging.php | 36 ++++++++++++++++--- .../Utopia/Response/Model/Subscriber.php | 12 +++++++ tests/e2e/Services/GraphQL/Base.php | 3 ++ tests/e2e/Services/GraphQL/MessagingTest.php | 15 ++++++-- .../e2e/Services/Messaging/MessagingBase.php | 8 +++++ 6 files changed, 103 insertions(+), 7 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 7e715baa2c..f310c91211 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1722,6 +1722,28 @@ $commonCollections = [ '$id' => ID::custom('subscribers'), 'name' => 'Subscribers', 'attributes' => [ + [ + '$id' => ID::custom('userId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('targetId'), 'type' => Database::VAR_STRING, @@ -1768,6 +1790,20 @@ $commonCollections = [ ], ], 'indexes' => [ + [ + '$id' => ID::custom('_key_userId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_userInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userInternalId'], + 'lengths' => [], + 'orders' => [], + ], [ '$id' => ID::custom('_key_targetId'), 'type' => Database::INDEX_KEY, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index e1e531c1a1..d6b3571508 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -36,6 +36,8 @@ use Utopia\Validator\Text; use MaxMind\Db\Reader; use Utopia\Validator\WhiteList; +use function Swoole\Coroutine\batch; + App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun provider') ->groups(['api', 'messaging']) @@ -1644,12 +1646,16 @@ App::post('/v1/messaging/topics/:topicId/subscribers') throw new Exception(Exception::USER_TARGET_NOT_FOUND); } + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $subscriber = new Document([ '$id' => $subscriberId, '$permissions' => [ - Permission::read(Role::user($target->getAttribute('userId'))), + Permission::read(Role::user($user->getId())), Permission::delete(Role::user($target->getAttribute('userId'))), ], + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), 'topicId' => $topicId, 'topicInternalId' => $topic->getInternalId(), 'targetId' => $targetId, @@ -1669,7 +1675,12 @@ App::post('/v1/messaging/topics/:topicId/subscribers') $response ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); + ->dynamic( + $subscriber + ->setAttribute('userId', $user->getId()) + ->setAttribute('userName', $user->getAttribute('name')), + Response::MODEL_SUBSCRIBER + ); }); App::get('/v1/messaging/topics/:topicId/subscribers') @@ -1713,9 +1724,20 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $cursor->setValue($cursorDocument); } + $subscribers = $dbForProject->find('subscribers', $queries); + + $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject) { + return function () use ($subscriber, $dbForProject) { + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); + + return $subscriber + ->setAttribute('userName', $user->getAttribute('name')); + }; + }, $subscribers)); + $response ->dynamic(new Document([ - 'subscribers' => $dbForProject->find('subscribers', $queries), + 'subscribers' => $subscribers, 'total' => $dbForProject->count('subscribers', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_SUBSCRIBER_LIST); }); @@ -1832,8 +1854,14 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); + $response - ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); + ->dynamic( + $subscriber + ->setAttribute('userName', $user->getAttribute('name')), + Response::MODEL_SUBSCRIBER + ); }); App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index 65bbd38f0e..71e6fedff3 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -34,6 +34,18 @@ class Subscriber extends Model 'default' => '', 'example' => '259125845563242502', ]) + ->addRule('userId', [ + 'type' => self::TYPE_STRING, + 'description' => 'User ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('userName', [ + 'type' => self::TYPE_STRING, + 'description' => 'User Name.', + 'default' => '', + 'example' => 'Aegon Targaryen', + ]) ->addRule('topicId', [ 'type' => self::TYPE_STRING, 'description' => 'Topic ID.', diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 707905892c..8655395dc2 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -2044,6 +2044,7 @@ trait Base return 'mutation createSubscriber($subscriberId: String!, $targetId: String!, $topicId: String!) { messagingCreateSubscriber(subscriberId: $subscriberId, targetId: $targetId, topicId: $topicId) { _id + userId targetId topicId } @@ -2054,6 +2055,7 @@ trait Base total subscribers { _id + userId targetId topicId } @@ -2063,6 +2065,7 @@ trait Base return 'query getSubscriber($topicId: String!, $subscriberId: String!) { messagingGetSubscriber(topicId: $topicId, subscriberId: $subscriberId) { _id + userId targetId topicId } diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 112e9e5633..27b2b52cd3 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -428,20 +428,23 @@ class MessagingTest extends Scope ], $this->getHeaders()), $graphQLPayload); $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['topicId'], $topicId); + $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['targetId'], $targetId); + $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['userId'], $userId); return $response['body']['data']['messagingCreateSubscriber']; } /** - * @depends testUpdateTopic + * @depends testCreateSubscriber */ - public function testListSubscribers(string $topicId) + public function testListSubscribers(array $subscriber) { $query = $this->getQuery(self::$LIST_SUBSCRIBERS); $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'topicId' => $topicId, + 'topicId' => $subscriber['topicId'], ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -451,6 +454,9 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['topicId'], $subscriber['topicId']); + $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['targetId'], $subscriber['targetId']); + $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['userId'], $subscriber['userId']); $this->assertEquals(1, \count($response['body']['data']['messagingListSubscribers']['subscribers'])); } @@ -479,6 +485,9 @@ class MessagingTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($subscriberId, $response['body']['data']['messagingGetSubscriber']['_id']); + $this->assertEquals($topicId, $response['body']['data']['messagingGetSubscriber']['topicId']); + $this->assertEquals($subscriber['targetId'], $response['body']['data']['messagingGetSubscriber']['targetId']); + $this->assertEquals($subscriber['userId'], $response['body']['data']['messagingGetSubscriber']['userId']); } /** diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index daafd52e8f..1f09d95522 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -321,6 +321,7 @@ trait MessagingBase 'providerId' => $provider['body']['$id'], 'identifier' => 'my-token', ]); + $this->assertEquals(201, $target['headers']['status-code']); $response = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['$id'] . '/subscribers', \array_merge([ @@ -330,13 +331,16 @@ trait MessagingBase 'subscriberId' => ID::unique(), 'targetId' => $target['body']['$id'], ]); + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertEquals($target['body']['userId'], $response['body']['userId']); $topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]); + $this->assertEquals(200, $topic['headers']['status-code']); $this->assertEquals('android-app', $topic['body']['name']); $this->assertEquals('updated-description', $topic['body']['description']); @@ -345,6 +349,7 @@ trait MessagingBase return [ 'topicId' => $topic['body']['$id'], 'targetId' => $target['body']['$id'], + 'userId' => $target['body']['userId'], 'subscriberId' => $response['body']['$id'] ]; } @@ -359,9 +364,11 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ])); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($data['topicId'], $response['body']['topicId']); $this->assertEquals($data['targetId'], $response['body']['targetId']); + $this->assertEquals($data['userId'], $response['body']['userId']); } /** @@ -377,6 +384,7 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); + $this->assertEquals($data['userId'], $response['body']['subscribers'][0]['userId']); $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); return $data; From b1eaf978063c0d2c518f34de633dab3ea9e52b04 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 20 Nov 2023 16:21:06 +0530 Subject: [PATCH 175/196] review changes --- app/controllers/api/messaging.php | 17 ++++++----------- .../Utopia/Response/Model/Subscriber.php | 2 +- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index d6b3571508..35ba97c1af 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1673,14 +1673,11 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->setParam('topicId', $topic->getId()) ->setParam('subscriberId', $subscriber->getId()); + $subscriber->setAttribute('userName', $user->getAttribute('name')); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic( - $subscriber - ->setAttribute('userId', $user->getId()) - ->setAttribute('userName', $user->getAttribute('name')), - Response::MODEL_SUBSCRIBER - ); + ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); }); App::get('/v1/messaging/topics/:topicId/subscribers') @@ -1856,12 +1853,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); + $subscriber->setAttribute('userName', $user->getAttribute('name')); + $response - ->dynamic( - $subscriber - ->setAttribute('userName', $user->getAttribute('name')), - Response::MODEL_SUBSCRIBER - ); + ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); }); App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index 71e6fedff3..5080b44333 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -38,7 +38,7 @@ class Subscriber extends Model 'type' => self::TYPE_STRING, 'description' => 'User ID.', 'default' => '', - 'example' => '259125845563242502', + 'example' => '5e5ea5c16897e', ]) ->addRule('userName', [ 'type' => self::TYPE_STRING, From 520d19e3352fc75cb651fc5d846af3cc4711aecc Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 21 Nov 2023 12:35:36 +0530 Subject: [PATCH 176/196] changes TextMagic to Textmagic in all places and uses email validator --- CHANGES.md | 2 +- app/config/variables.php | 2 +- app/controllers/api/messaging.php | 12 ++++++------ src/Appwrite/Platform/Workers/Messaging.php | 4 ++-- tests/e2e/Services/GraphQL/Base.php | 8 ++++---- tests/e2e/Services/GraphQL/MessagingTest.php | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 889f65e1e7..fbe1e548db 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -466,7 +466,7 @@ ## Features - Added Phone Authentication by @TorstenDittmann in https://github.com/appwrite/appwrite/pull/3357 - Added Twilio Support - - Added TextMagic Support + - Added Textmagic Support - Added Telesign Support - Added Endpoint to create Phone Session (`POST:/v1/account/sessions/phone`) - Added Endpoint to confirm Phone Session (`PUT:/v1/account/sessions/phone`) diff --git a/app/config/variables.php b/app/config/variables.php index 6f49d4a5da..c9329f6d55 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -440,7 +440,7 @@ return [ 'variables' => [ [ 'name' => '_APP_SMS_PROVIDER', - 'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'.\n\nEnsure `[USER]` and `[SECRET]` are URL encoded if they contain any non-alphanumeric characters.\n\nAvailable providers are twilio, textmagic, telesign, msg91, and vonage.", + 'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'.\n\nEnsure `[USER]` and `[SECRET]` are URL encoded if they contain any non-alphanumeric characters.\n\nAvailable providers are twilio, Textmagic, telesign, msg91, and vonage.", 'introduction' => '0.15.0', 'default' => '', 'required' => false, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 35ba97c1af..536ebaf408 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -256,7 +256,7 @@ App::post('/v1/messaging/providers/telesign') }); App::post('/v1/messaging/providers/textmagic') - ->desc('Create TextMagic provider') + ->desc('Create Textmagic provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') ->label('audits.resource', 'provider/{response.$id}') @@ -264,7 +264,7 @@ App::post('/v1/messaging/providers/textmagic') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createTextMagicProvider') + ->label('sdk.method', 'createTextmagicProvider') ->label('sdk.description', '/docs/references/messaging/create-textmagic-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -689,7 +689,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) - ->param('from', '', new Text(256), 'Sender email address.', true) + ->param('from', '', new Email(), 'Sender email address.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('queueForEvents') @@ -764,7 +764,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) - ->param('from', '', new Text(256), 'Sender email address.', true) + ->param('from', '', new Email(), 'Sender email address.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -950,7 +950,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId') }); App::patch('/v1/messaging/providers/textmagic/:providerId') - ->desc('Update TextMagic provider') + ->desc('Update Textmagic provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') ->label('audits.resource', 'provider/{response.$id}') @@ -958,7 +958,7 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateTextMagicProvider') + ->label('sdk.method', 'updateTextmagicProvider') ->label('sdk.description', '/docs/references/messaging/update-textmagic-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 299ef4526f..0862f0b8fa 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -17,7 +17,7 @@ use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Adapters\SMS\Mock; use Utopia\Messaging\Adapters\SMS\Msg91; use Utopia\Messaging\Adapters\SMS\Telesign; -use Utopia\Messaging\Adapters\SMS\TextMagic; +use Utopia\Messaging\Adapters\SMS\Textmagic; use Utopia\Messaging\Adapters\SMS\Twilio; use Utopia\Messaging\Adapters\SMS\Vonage; use Utopia\Messaging\Adapters\Push as PushAdapter; @@ -303,7 +303,7 @@ class Messaging extends Action return match ($provider->getAttribute('provider')) { 'mock' => new Mock('username', 'password'), 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), - 'textmagic' => new TextMagic($credentials['username'], $credentials['apiKey']), + 'textmagic' => new Textmagic($credentials['username'], $credentials['apiKey']), 'telesign' => new Telesign($credentials['username'], $credentials['password']), 'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']), 'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']), diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 8655395dc2..3777d67b73 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1830,8 +1830,8 @@ trait Base } }'; case self::$CREATE_TEXTMAGIC_PROVIDER: - return 'mutation createTextMagicProvider($providerId: String!, $name: String!, $from: String!, $username: String!, $apiKey: String!) { - messagingCreateTextMagicProvider(providerId: $providerId, name: $name, from: $from, username: $username, apiKey: $apiKey) { + return 'mutation createTextmagicProvider($providerId: String!, $name: String!, $from: String!, $username: String!, $apiKey: String!) { + messagingCreateTextmagicProvider(providerId: $providerId, name: $name, from: $from, username: $username, apiKey: $apiKey) { _id name provider @@ -1944,8 +1944,8 @@ trait Base } }'; case self::$UPDATE_TEXTMAGIC_PROVIDER: - return 'mutation updateTextMagicProvider($providerId: String!, $name: String!, $username: String!, $apiKey: String!) { - messagingUpdateTextMagicProvider(providerId: $providerId, name: $name, username: $username, apiKey: $apiKey) { + return 'mutation updateTextmagicProvider($providerId: String!, $name: String!, $username: String!, $apiKey: String!) { + messagingUpdateTextmagicProvider(providerId: $providerId, name: $name, username: $username, apiKey: $apiKey) { _id name provider diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 27b2b52cd3..e5a4ca3a72 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -47,7 +47,7 @@ class MessagingTest extends Scope 'password' => 'my-password', 'from' => '+123456789', ], - 'TextMagic' => [ + 'Textmagic' => [ 'providerId' => ID::unique(), 'name' => 'Textmagic1', 'username' => 'my-username', @@ -134,7 +134,7 @@ class MessagingTest extends Scope 'username' => 'my-username', 'password' => 'my-password', ], - 'TextMagic' => [ + 'Textmagic' => [ 'providerId' => $providers[4]['_id'], 'name' => 'Textmagic2', 'username' => 'my-username', From 3394218cb0164585094f21d922f8ee1ebc084728 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 21 Nov 2023 15:00:02 +0530 Subject: [PATCH 177/196] adds validation for phone and email identifier --- app/config/errors.php | 10 ++++++++++ app/controllers/api/users.php | 25 +++++++++++++++++++++++++ src/Appwrite/Extend/Exception.php | 2 ++ 3 files changed, 37 insertions(+) diff --git a/app/config/errors.php b/app/config/errors.php index f7c9e8e55f..3c0b67c76a 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -103,6 +103,16 @@ return [ 'description' => 'This method was not fully implemented yet. If you believe this is a mistake, please upgrade your Appwrite server version.', 'code' => 405, ], + Exception::GENERAL_INVALID_EMAIL => [ + 'name' => Exception::GENERAL_INVALID_EMAIL, + 'description' => 'Value must be a valid email address.', + 'code' => 400, + ], + Exception::GENERAL_INVALID_PHONE => [ + 'name' => Exception::GENERAL_INVALID_PHONE, + 'description' => 'Value must be a valid phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', + 'code' => 400, + ], /** User Errors */ Exception::USER_COUNT_EXCEEDED => [ diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index d9968c83a7..992a28ba8e 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -415,6 +415,18 @@ App::post('/v1/users/:userId/targets') } } + if ($providerType === 'email') { + $validator = new Email(); + if (!$validator->isValid($identifier)) { + throw new Exception(Exception::GENERAL_INVALID_EMAIL); + } + } elseif ($providerType === 'sms') { + $validator = new Phone(); + if (!$validator->isValid($identifier)) { + throw new Exception(Exception::GENERAL_INVALID_PHONE); + } + } + $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1270,6 +1282,19 @@ App::patch('/v1/users/:userId/targets/:targetId') } if ($identifier) { + $providerType = $target->getAttribute('providerType'); + if ($providerType === 'email') { + $emailValidator = new Email(); + if (!$emailValidator->isValid($identifier)) { + throw new Exception(Exception::GENERAL_INVALID_EMAIL); + } + } elseif ($providerType === 'sms') { + $phoneValidator = new Phone(); + if (!$phoneValidator->isValid($identifier)) { + throw new Exception(Exception::GENERAL_INVALID_PHONE); + } + } + $target->setAttribute('identifier', $identifier); } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 3869444752..61ea597941 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -55,6 +55,8 @@ class Exception extends \Exception public const GENERAL_CODES_DISABLED = 'general_codes_disabled'; public const GENERAL_USAGE_DISABLED = 'general_usage_disabled'; public const GENERAL_NOT_IMPLEMENTED = 'general_not_implemented'; + public const GENERAL_INVALID_EMAIL = 'general_invalid_email'; + public const GENERAL_INVALID_PHONE = 'general_invalid_phone'; /** Users */ public const USER_COUNT_EXCEEDED = 'user_count_exceeded'; From 88f228c106889805aa91f7087edfdb7a3a69ed5d Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 21 Nov 2023 15:11:09 +0530 Subject: [PATCH 178/196] review changes --- app/controllers/api/users.php | 51 +++++++++++-------- tests/e2e/Services/GraphQL/MessagingTest.php | 4 +- .../e2e/Services/Messaging/MessagingBase.php | 2 +- tests/e2e/Services/Users/UsersBase.php | 8 +-- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 992a28ba8e..c339b77fed 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -415,16 +415,21 @@ App::post('/v1/users/:userId/targets') } } - if ($providerType === 'email') { - $validator = new Email(); - if (!$validator->isValid($identifier)) { - throw new Exception(Exception::GENERAL_INVALID_EMAIL); - } - } elseif ($providerType === 'sms') { - $validator = new Phone(); - if (!$validator->isValid($identifier)) { - throw new Exception(Exception::GENERAL_INVALID_PHONE); - } + switch ($providerType) { + case 'email': + $validator = new Email(); + if (!$validator->isValid($identifier)) { + throw new Exception(Exception::GENERAL_INVALID_EMAIL); + } + break; + case 'sms': + $validator = new Phone(); + if (!$validator->isValid($identifier)) { + throw new Exception(Exception::GENERAL_INVALID_PHONE); + } + break; + default: + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } $user = $dbForProject->getDocument('users', $userId); @@ -1283,16 +1288,22 @@ App::patch('/v1/users/:userId/targets/:targetId') if ($identifier) { $providerType = $target->getAttribute('providerType'); - if ($providerType === 'email') { - $emailValidator = new Email(); - if (!$emailValidator->isValid($identifier)) { - throw new Exception(Exception::GENERAL_INVALID_EMAIL); - } - } elseif ($providerType === 'sms') { - $phoneValidator = new Phone(); - if (!$phoneValidator->isValid($identifier)) { - throw new Exception(Exception::GENERAL_INVALID_PHONE); - } + + switch ($providerType) { + case 'email': + $validator = new Email(); + if (!$validator->isValid($identifier)) { + throw new Exception(Exception::GENERAL_INVALID_EMAIL); + } + break; + case 'sms': + $validator = new Phone(); + if (!$validator->isValid($identifier)) { + throw new Exception(Exception::GENERAL_INVALID_PHONE); + } + break; + default: + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } $target->setAttribute('identifier', $identifier); diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index e5a4ca3a72..e3ca99f2ac 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -398,7 +398,7 @@ class MessagingTest extends Scope 'providerType' => 'email', 'userId' => $userId, 'providerId' => $providerId, - 'identifier' => 'token', + 'identifier' => 'random-email@mail.org', ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -409,7 +409,7 @@ class MessagingTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($userId, $response['body']['data']['usersCreateTarget']['userId']); - $this->assertEquals('token', $response['body']['data']['usersCreateTarget']['identifier']); + $this->assertEquals('random-email@mail.org', $response['body']['data']['usersCreateTarget']['identifier']); $targetId = $response['body']['data']['usersCreateTarget']['_id']; diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 1f09d95522..37a581b088 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -319,7 +319,7 @@ trait MessagingBase 'targetId' => ID::unique(), 'providerType' => 'email', 'providerId' => $provider['body']['$id'], - 'identifier' => 'my-token', + 'identifier' => 'random-email@mail.org', ]); $this->assertEquals(201, $target['headers']['status-code']); diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index c9cb17d7b5..70230b8c8a 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -1245,11 +1245,11 @@ trait UsersBase 'targetId' => ID::unique(), 'providerId' => $provider['body']['$id'], 'providerType' => 'email', - 'identifier' => 'my-token', + 'identifier' => 'random-email@mail.org', ]); $this->assertEquals(201, $response['headers']['status-code']); $this->assertEquals($provider['body']['$id'], $response['body']['providerId']); - $this->assertEquals('my-token', $response['body']['identifier']); + $this->assertEquals('random-email@mail.org', $response['body']['identifier']); return $response['body']; } @@ -1262,10 +1262,10 @@ trait UsersBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'identifier' => 'my-updated-token', + 'identifier' => 'random-email1@mail.org', ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('my-updated-token', $response['body']['identifier']); + $this->assertEquals('random-email1@mail.org', $response['body']['identifier']); return $response['body']; } From 9c6cd8512faf52438b2186f494b03d83f1976ffc Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 21 Nov 2023 15:19:19 +0530 Subject: [PATCH 179/196] review changes --- app/controllers/api/users.php | 4 ++++ tests/e2e/Services/GraphQL/UsersTest.php | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index c339b77fed..0c1edb6a96 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -428,6 +428,8 @@ App::post('/v1/users/:userId/targets') throw new Exception(Exception::GENERAL_INVALID_PHONE); } break; + case 'push': + break; default: throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } @@ -1302,6 +1304,8 @@ App::patch('/v1/users/:userId/targets/:targetId') throw new Exception(Exception::GENERAL_INVALID_PHONE); } break; + case 'push': + break; default: throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); } diff --git a/tests/e2e/Services/GraphQL/UsersTest.php b/tests/e2e/Services/GraphQL/UsersTest.php index 59c0c4a805..3b49337a63 100644 --- a/tests/e2e/Services/GraphQL/UsersTest.php +++ b/tests/e2e/Services/GraphQL/UsersTest.php @@ -80,7 +80,7 @@ class UsersTest extends Scope 'userId' => $user['_id'], 'providerType' => 'email', 'providerId' => $providerId, - 'identifier' => 'identifier', + 'identifier' => 'random-email@mail.org', ] ]; @@ -90,7 +90,7 @@ class UsersTest extends Scope ], $this->getHeaders()), $graphQLPayload); $this->assertEquals(200, $target['headers']['status-code']); - $this->assertEquals('identifier', $target['body']['data']['usersCreateTarget']['identifier']); + $this->assertEquals('random-email@mail.org', $target['body']['data']['usersCreateTarget']['identifier']); return $target['body']['data']['usersCreateTarget']; } @@ -271,7 +271,7 @@ class UsersTest extends Scope ], $this->getHeaders()), $graphQLPayload); $this->assertEquals(200, $target['headers']['status-code']); - $this->assertEquals('identifier', $target['body']['data']['usersGetTarget']['identifier']); + $this->assertEquals('random-email@mail.org', $target['body']['data']['usersGetTarget']['identifier']); } public function testUpdateUserStatus() @@ -470,7 +470,7 @@ class UsersTest extends Scope 'variables' => [ 'userId' => $target['userId'], 'targetId' => $target['_id'], - 'identifier' => 'newidentifier', + 'identifier' => 'random-email1@mail.org', ], ]; @@ -480,7 +480,7 @@ class UsersTest extends Scope ], $this->getHeaders()), $graphQLPayload); $this->assertEquals(200, $target['headers']['status-code']); - $this->assertEquals('newidentifier', $target['body']['data']['usersUpdateTarget']['identifier']); + $this->assertEquals('random-email1@mail.org', $target['body']['data']['usersUpdateTarget']['identifier']); } public function testDeleteUserSessions() From d9826cdce8ff8f943a1c9866aca99223b656c814 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 23 Nov 2023 00:39:55 +0530 Subject: [PATCH 180/196] makes provider creation fields optional and adds target info in subscriber model --- app/controllers/api/messaging.php | 583 +++++++++++++----- src/Appwrite/Platform/Workers/Messaging.php | 6 +- .../Utopia/Response/Model/Subscriber.php | 12 + .../e2e/Services/Messaging/MessagingBase.php | 8 +- 4 files changed, 466 insertions(+), 143 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 536ebaf408..282cb32108 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -54,31 +54,57 @@ App::post('/v1/messaging/providers/mailgun') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Email(), 'Sender email address.') - ->param('apiKey', '', new Text(0), 'Mailgun API Key.') - ->param('domain', '', new Text(0), 'Mailgun Domain.') - ->param('isEuRegion', false, new Boolean(), 'Set as EU region.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Email(), 'Sender email address.', true) + ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) + ->param('domain', '', new Text(0), 'Mailgun Domain.', true) + ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $apiKey, string $domain, bool $isEuRegion, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, string $domain, ?bool $isEuRegion, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if ($isEuRegion === true || $isEuRegion === false) { + $credentials['isEuRegion'] = $isEuRegion; + } + + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + if (!empty($domain)) { + $credentials['domain'] = $domain; + } + + if ( + $enabled === true && + \array_key_exists('isEuRegion', $credentials) && + \array_key_exists('apiKey', $credentials) && + \array_key_exists('domain', $credentials) && + \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'mailgun', 'type' => 'email', 'enabled' => $enabled, - 'credentials' => [ - 'apiKey' => $apiKey, - 'domain' => $domain, - 'isEuRegion' => $isEuRegion, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -111,26 +137,45 @@ App::post('/v1/messaging/providers/sendgrid') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Email(), 'Sender email address.') - ->param('apiKey', '', new Text(0), 'Sendgrid API key.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Email(), 'Sender email address.', true) + ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $apiKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + if ( + $enabled === true + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'sendgrid', 'type' => 'email', 'enabled' => $enabled, - 'credentials' => [ - 'apiKey' => $apiKey, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -163,28 +208,51 @@ App::post('/v1/messaging/providers/msg91') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') - ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) + ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $senderId, string $authKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $senderId, string $authKey, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($senderId)) { + $credentials['senderId'] = $senderId; + } + + if (!empty($authKey)) { + $credentials['authKey'] = $authKey; + } + + if ( + $enabled === true + && \array_key_exists('senderId', $credentials) + && \array_key_exists('authKey', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'msg91', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'senderId' => $senderId, - 'authKey' => $authKey, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -217,28 +285,51 @@ App::post('/v1/messaging/providers/telesign') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('username', '', new Text(0), 'Telesign username.') - ->param('password', '', new Text(0), 'Telesign password.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('username', '', new Text(0), 'Telesign username.', true) + ->param('password', '', new Text(0), 'Telesign password.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $username, string $password, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $username, string $password, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($username)) { + $credentials['username'] = $username; + } + + if (!empty($password)) { + $credentials['password'] = $password; + } + + if ( + $enabled === true + && \array_key_exists('username', $credentials) + && \array_key_exists('password', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'telesign', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'username' => $username, - 'password' => $password, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -271,28 +362,51 @@ App::post('/v1/messaging/providers/textmagic') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('username', '', new Text(0), 'Textmagic username.') - ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('username', '', new Text(0), 'Textmagic username.', true) + ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $username, string $apiKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $username, string $apiKey, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($username)) { + $credentials['username'] = $username; + } + + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + if ( + $enabled === true + && \array_key_exists('username', $credentials) + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'textmagic', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'username' => $username, - 'apiKey' => $apiKey, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -325,28 +439,51 @@ App::post('/v1/messaging/providers/twilio') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') - ->param('authToken', '', new Text(0), 'Twilio authentication token.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('accountSid', '', new Text(0), 'Twilio account secret ID.', true) + ->param('authToken', '', new Text(0), 'Twilio authentication token.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $accountSid, string $authToken, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $accountSid, string $authToken, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($accountSid)) { + $credentials['accountSid'] = $accountSid; + } + + if (!empty($authToken)) { + $credentials['authToken'] = $authToken; + } + + if ( + $enabled === true + && \array_key_exists('accountSid', $credentials) + && \array_key_exists('authToken', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'twilio', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $from, ]); try { @@ -379,28 +516,51 @@ App::post('/v1/messaging/providers/vonage') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('apiKey', '', new Text(0), 'Vonage API key.') - ->param('apiSecret', '', new Text(0), 'Vonage API secret.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('apiKey', '', new Text(0), 'Vonage API key.', true) + ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $apiKey, string $apiSecret, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, string $apiSecret, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + if (!empty($apiSecret)) { + $credentials['apiSecret'] = $apiSecret; + } + + if ( + $enabled === true + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('apiSecret', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'vonage', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -433,22 +593,33 @@ App::post('/v1/messaging/providers/fcm') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('serverKey', '', new Text(0), 'FCM server key.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('serverKey', '', new Text(0), 'FCM server key.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $serverKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $serverKey, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $credentials = []; + + if (!empty($serverKey)) { + $credentials['serverKey'] = $serverKey; + } + + if ($enabled === true && \array_key_exists('serverKey', $credentials)) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'fcm', 'type' => 'push', 'enabled' => $enabled, - 'credentials' => [ - 'serverKey' => $serverKey, - ], + 'credentials' => $credentials ]); try { @@ -481,30 +652,60 @@ App::post('/v1/messaging/providers/apns') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('authKey', '', new Text(0), 'APNS authentication key.') - ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') - ->param('teamId', '', new Text(0), 'APNS team ID.') - ->param('bundleId', '', new Text(0), 'APNS bundle ID.') - ->param('endpoint', '', new Text(0), 'APNS endpoint.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('authKey', '', new Text(0), 'APNS authentication key.', true) + ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) + ->param('teamId', '', new Text(0), 'APNS team ID.', true) + ->param('bundleId', '', new Text(0), 'APNS bundle ID.', true) + ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $credentials = []; + + if (!empty($authKey)) { + $credentials['authKey'] = $authKey; + } + + if (!empty($authKeyId)) { + $credentials['authKeyId'] = $authKeyId; + } + + if (!empty($teamId)) { + $credentials['teamId'] = $teamId; + } + + if (!empty($bundleId)) { + $credentials['bundleId'] = $bundleId; + } + + if (!empty($endpoint)) { + $credentials['endpoint'] = $endpoint; + } + + if ( + $enabled === true + && \array_key_exists('authKey', $credentials) + && \array_key_exists('authKeyId', $credentials) + && \array_key_exists('teamId', $credentials) + && \array_key_exists('bundleId', $credentials) + && \array_key_exists('endpoint', $credentials) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'apns', 'type' => 'push', 'enabled' => $enabled, - 'credentials' => [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ], + 'credentials' => $credentials, ]); try { @@ -717,10 +918,6 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if ($isEuRegion === true || $isEuRegion === false) { @@ -737,6 +934,21 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true && + \array_key_exists('isEuRegion', $credentials) && + \array_key_exists('apiKey', $credentials) && + \array_key_exists('domain', $credentials) && + \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -790,16 +1002,25 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if (!empty($apiKey)) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, ]); } + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('apiKey', $provider->getAttribute('credentials')) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -854,10 +1075,6 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($senderId)) { @@ -870,6 +1087,20 @@ App::patch('/v1/messaging/providers/msg91/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('senderId', $credentials) + && \array_key_exists('authKey', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -924,10 +1155,6 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -940,6 +1167,21 @@ App::patch('/v1/messaging/providers/telesign/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('username', $credentials) + && \array_key_exists('password', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -994,10 +1236,6 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -1010,6 +1248,21 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('username', $credentials) + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1064,10 +1317,6 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($accountSid)) { @@ -1080,6 +1329,21 @@ App::patch('/v1/messaging/providers/twilio/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('accountSid', $credentials) + && \array_key_exists('authToken', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1134,10 +1398,6 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($apiKey)) { @@ -1150,6 +1410,21 @@ App::patch('/v1/messaging/providers/vonage/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('apiSecret', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1196,14 +1471,20 @@ App::patch('/v1/messaging/providers/fcm/:providerId') $provider->setAttribute('name', $name); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if (!empty($serverKey)) { $provider->setAttribute('credentials', ['serverKey' => $serverKey]); } + if ($enabled === true || $enabled === false) { + if ($enabled === true && \array_key_exists('serverKey', $provider->getAttribute('credentials'))) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1255,10 +1536,6 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider->setAttribute('name', $name); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($authKey)) { @@ -1283,6 +1560,23 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('authKey', $credentials) + && \array_key_exists('authKeyId', $credentials) + && \array_key_exists('teamId', $credentials) + && \array_key_exists('bundleId', $credentials) + && \array_key_exists('endpoint', $credentials) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1726,8 +2020,11 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject) { return function () use ($subscriber, $dbForProject) { $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); return $subscriber + ->setAttribute('identifier', $target->getAttribute('identifier')) + ->setAttribute('providerType', $target->getAttribute('providerType')) ->setAttribute('userName', $user->getAttribute('name')); }; }, $subscribers)); @@ -1852,8 +2149,12 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') } $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); - $subscriber->setAttribute('userName', $user->getAttribute('name')); + $subscriber + ->setAttribute('identifier', $target->getAttribute('identifier')) + ->setAttribute('providerType', $target->getAttribute('providerType')) + ->setAttribute('userName', $user->getAttribute('name')); $response ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 0862f0b8fa..8488d8a9e4 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -144,7 +144,11 @@ class Messaging extends Action if ($internalProvider->getId() === $providerId) { $provider = $internalProvider; } else { - $provider = $dbForProject->getDocument('providers', $providerId); + $provider = $dbForProject->getDocument('providers', $providerId, [Query::equal('enabled', [true])]); + + if ($provider->isEmpty()) { + $provider = $internalProvider; + } } $providers[] = $provider; diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index 5080b44333..dfacc0e46e 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -34,6 +34,18 @@ class Subscriber extends Model 'default' => '', 'example' => '259125845563242502', ]) + ->addRule('providerType', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target\'s provider type.', + 'default' => '', + 'example' => 'email', + ]) + ->addRule('identifier', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target identifier.', + 'default' => '', + 'example' => 'random-email@mail.org', + ]) ->addRule('userId', [ 'type' => self::TYPE_STRING, 'description' => 'User ID.', diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 37a581b088..1bd91d9222 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -350,7 +350,9 @@ trait MessagingBase 'topicId' => $topic['body']['$id'], 'targetId' => $target['body']['$id'], 'userId' => $target['body']['userId'], - 'subscriberId' => $response['body']['$id'] + 'subscriberId' => $response['body']['$id'], + 'identifier' => $target['body']['identifier'], + 'providerType' => $target['body']['providerType'], ]; } @@ -369,6 +371,8 @@ trait MessagingBase $this->assertEquals($data['topicId'], $response['body']['topicId']); $this->assertEquals($data['targetId'], $response['body']['targetId']); $this->assertEquals($data['userId'], $response['body']['userId']); + $this->assertEquals($data['providerType'], $response['body']['providerType']); + $this->assertEquals($data['identifier'], $response['body']['identifier']); } /** @@ -385,6 +389,8 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); $this->assertEquals($data['userId'], $response['body']['subscribers'][0]['userId']); + $this->assertEquals($data['providerType'], $response['body']['subscribers'][0]['providerType']); + $this->assertEquals($data['identifier'], $response['body']['subscribers'][0]['identifier']); $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); return $data; From 858175fe0025716c72ced2b5c7aae45ead9e30ea Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 23 Nov 2023 14:35:16 +0530 Subject: [PATCH 181/196] adds target object in subscriber model --- app/config/collections.php | 36 ------------------- app/controllers/api/messaging.php | 18 +++++----- .../Utopia/Response/Model/Subscriber.php | 31 ++++++++-------- .../e2e/Services/Messaging/MessagingBase.php | 15 ++++---- 4 files changed, 30 insertions(+), 70 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index f310c91211..7e715baa2c 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1722,28 +1722,6 @@ $commonCollections = [ '$id' => ID::custom('subscribers'), 'name' => 'Subscribers', 'attributes' => [ - [ - '$id' => ID::custom('userId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('userInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('targetId'), 'type' => Database::VAR_STRING, @@ -1790,20 +1768,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_userId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userId'], - 'lengths' => [], - 'orders' => [], - ], - [ - '$id' => ID::custom('_key_userInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userInternalId'], - 'lengths' => [], - 'orders' => [], - ], [ '$id' => ID::custom('_key_targetId'), 'type' => Database::INDEX_KEY, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 282cb32108..f13b037b02 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1946,10 +1946,8 @@ App::post('/v1/messaging/topics/:topicId/subscribers') '$id' => $subscriberId, '$permissions' => [ Permission::read(Role::user($user->getId())), - Permission::delete(Role::user($target->getAttribute('userId'))), + Permission::delete(Role::user($user->getId())), ], - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), 'topicId' => $topicId, 'topicInternalId' => $topic->getInternalId(), 'targetId' => $targetId, @@ -1967,7 +1965,9 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->setParam('topicId', $topic->getId()) ->setParam('subscriberId', $subscriber->getId()); - $subscriber->setAttribute('userName', $user->getAttribute('name')); + $subscriber + ->setAttribute('target', $target) + ->setAttribute('userName', $user->getAttribute('name')); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -2019,12 +2019,11 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject) { return function () use ($subscriber, $dbForProject) { - $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); return $subscriber - ->setAttribute('identifier', $target->getAttribute('identifier')) - ->setAttribute('providerType', $target->getAttribute('providerType')) + ->setAttribute('target', $target) ->setAttribute('userName', $user->getAttribute('name')); }; }, $subscribers)); @@ -2148,12 +2147,11 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } - $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); $subscriber - ->setAttribute('identifier', $target->getAttribute('identifier')) - ->setAttribute('providerType', $target->getAttribute('providerType')) + ->setAttribute('target', $target) ->setAttribute('userName', $user->getAttribute('name')); $response diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index dfacc0e46e..e699df876c 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -34,23 +34,20 @@ class Subscriber extends Model 'default' => '', 'example' => '259125845563242502', ]) - ->addRule('providerType', [ - 'type' => self::TYPE_STRING, - 'description' => 'Target\'s provider type.', - 'default' => '', - 'example' => 'email', - ]) - ->addRule('identifier', [ - 'type' => self::TYPE_STRING, - 'description' => 'Target identifier.', - 'default' => '', - 'example' => 'random-email@mail.org', - ]) - ->addRule('userId', [ - 'type' => self::TYPE_STRING, - 'description' => 'User ID.', - 'default' => '', - 'example' => '5e5ea5c16897e', + ->addRule('target', [ + 'type' => Response::MODEL_TARGET, + 'description' => 'Target.', + 'default' => [], + 'example' => [ + '$id' => '259125845563242502', + '$createdAt' => self::TYPE_DATETIME_EXAMPLE, + '$updatedAt' => self::TYPE_DATETIME_EXAMPLE, + 'providerType' => 'email', + 'providerId' => '259125845563242502', + 'name' => 'ageon-app-email', + 'identifier' => 'random-mail@email.org', + 'userId' => '5e5ea5c16897e', + ], ]) ->addRule('userName', [ 'type' => self::TYPE_STRING, diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 1bd91d9222..690e503e77 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -333,7 +333,8 @@ trait MessagingBase ]); $this->assertEquals(201, $response['headers']['status-code']); - $this->assertEquals($target['body']['userId'], $response['body']['userId']); + $this->assertEquals($target['body']['userId'], $response['body']['target']['userId']); + $this->assertEquals($target['body']['providerType'], $response['body']['target']['providerType']); $topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['$id'], [ 'content-type' => 'application/json', @@ -370,9 +371,9 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($data['topicId'], $response['body']['topicId']); $this->assertEquals($data['targetId'], $response['body']['targetId']); - $this->assertEquals($data['userId'], $response['body']['userId']); - $this->assertEquals($data['providerType'], $response['body']['providerType']); - $this->assertEquals($data['identifier'], $response['body']['identifier']); + $this->assertEquals($data['userId'], $response['body']['target']['userId']); + $this->assertEquals($data['providerType'], $response['body']['target']['providerType']); + $this->assertEquals($data['identifier'], $response['body']['target']['identifier']); } /** @@ -388,9 +389,9 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); - $this->assertEquals($data['userId'], $response['body']['subscribers'][0]['userId']); - $this->assertEquals($data['providerType'], $response['body']['subscribers'][0]['providerType']); - $this->assertEquals($data['identifier'], $response['body']['subscribers'][0]['identifier']); + $this->assertEquals($data['userId'], $response['body']['subscribers'][0]['target']['userId']); + $this->assertEquals($data['providerType'], $response['body']['subscribers'][0]['target']['providerType']); + $this->assertEquals($data['identifier'], $response['body']['subscribers'][0]['target']['identifier']); $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); return $data; From e3f60f4c78023858f8dabcad86bdb2518d229ca5 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 23 Nov 2023 23:14:02 +0530 Subject: [PATCH 182/196] fix tests --- .env | 2 +- src/Appwrite/Utopia/Response/Model/Target.php | 6 +++++ tests/e2e/Services/GraphQL/Base.php | 27 ++++++++++++++++--- tests/e2e/Services/GraphQL/MessagingTest.php | 10 +++---- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/.env b/.env index 6ea21eed9d..f77083a035 100644 --- a/.env +++ b/.env @@ -87,7 +87,7 @@ _APP_LOGGING_PROVIDER= _APP_LOGGING_CONFIG= _APP_GRAPHQL_MAX_BATCH_SIZE=10 _APP_GRAPHQL_MAX_COMPLEXITY=250 -_APP_GRAPHQL_MAX_DEPTH=3 +_APP_GRAPHQL_MAX_DEPTH=4 _APP_DOCKER_HUB_USERNAME= _APP_DOCKER_HUB_PASSWORD= _APP_VCS_GITHUB_APP_NAME= diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php index f6346f409a..a92d1b34ca 100644 --- a/src/Appwrite/Utopia/Response/Model/Target.php +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -28,6 +28,12 @@ class Target extends Model 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target Name.', + 'default' => '', + 'example' => 'Aegon apple token', + ]) ->addRule('userId', [ 'type' => self::TYPE_STRING, 'description' => 'User ID.', diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 3777d67b73..6939e6a9b5 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -2044,9 +2044,16 @@ trait Base return 'mutation createSubscriber($subscriberId: String!, $targetId: String!, $topicId: String!) { messagingCreateSubscriber(subscriberId: $subscriberId, targetId: $targetId, topicId: $topicId) { _id - userId targetId topicId + userName + target { + _id + userId + name + providerType + identifier + } } }'; case self::$LIST_SUBSCRIBERS: @@ -2055,9 +2062,16 @@ trait Base total subscribers { _id - userId targetId topicId + userName + target { + _id + userId + name + providerType + identifier + } } } }'; @@ -2065,9 +2079,16 @@ trait Base return 'query getSubscriber($topicId: String!, $subscriberId: String!) { messagingGetSubscriber(topicId: $topicId, subscriberId: $subscriberId) { _id - userId targetId topicId + userName + target { + _id + userId + name + providerType + identifier + } } }'; case self::$DELETE_SUBSCRIBER: diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index e3ca99f2ac..d1a084cfc1 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -430,7 +430,7 @@ class MessagingTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['topicId'], $topicId); $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['targetId'], $targetId); - $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['userId'], $userId); + $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['target']['userId'], $userId); return $response['body']['data']['messagingCreateSubscriber']; } @@ -454,9 +454,9 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['topicId'], $subscriber['topicId']); - $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['targetId'], $subscriber['targetId']); - $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['userId'], $subscriber['userId']); + $this->assertEquals($subscriber['topicId'], $response['body']['data']['messagingListSubscribers']['subscribers'][0]['topicId']); + $this->assertEquals($subscriber['targetId'], $response['body']['data']['messagingListSubscribers']['subscribers'][0]['targetId']); + $this->assertEquals($subscriber['target']['userId'], $response['body']['data']['messagingListSubscribers']['subscribers'][0]['target']['userId']); $this->assertEquals(1, \count($response['body']['data']['messagingListSubscribers']['subscribers'])); } @@ -487,7 +487,7 @@ class MessagingTest extends Scope $this->assertEquals($subscriberId, $response['body']['data']['messagingGetSubscriber']['_id']); $this->assertEquals($topicId, $response['body']['data']['messagingGetSubscriber']['topicId']); $this->assertEquals($subscriber['targetId'], $response['body']['data']['messagingGetSubscriber']['targetId']); - $this->assertEquals($subscriber['userId'], $response['body']['data']['messagingGetSubscriber']['userId']); + $this->assertEquals($subscriber['target']['userId'], $response['body']['data']['messagingGetSubscriber']['target']['userId']); } /** From ee4c2d0e0dfcb9115f595458ab381dce49478572 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 28 Nov 2023 18:42:34 +0530 Subject: [PATCH 183/196] adds target when creating user via server endpoint --- app/controllers/api/account.php | 89 +++++++++++++-------- app/controllers/api/users.php | 89 ++++++++++++++++++++- src/Appwrite/Platform/Workers/Messaging.php | 24 +++--- tests/e2e/Services/GraphQL/UsersTest.php | 2 +- tests/e2e/Services/Users/UsersBase.php | 5 +- 5 files changed, 156 insertions(+), 53 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index eda29656fe..7034c93912 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -149,18 +149,20 @@ App::post('/v1/account') ]); $user->removeAttribute('$internalId'); $user = Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); - $target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::user($userId)), - Permission::delete(Role::user($userId)), - ], - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), - 'providerType' => 'email', - 'identifier' => $email, - ]))); - $user->setAttribute('targets', [$target]); + try { + $target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([ + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerType' => 'email', + 'identifier' => $email, + ]))); + $user->setAttribute('targets', [...$user->getAttribute('targets', []), $target]); + } catch (Duplicate) { + $existingTarget = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$email]), + ]); + $user->setAttribute('targets', [...$user->getAttribute('targets', []), $existingTarget]); + } $dbForProject->deleteCachedDocument('users', $user->getId()); } catch (Duplicate) { throw new Exception(Exception::USER_ALREADY_EXISTS); @@ -1309,6 +1311,21 @@ App::post('/v1/account/sessions/phone') $user->removeAttribute('$internalId'); Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); + try { + $target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([ + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerType' => 'sms', + 'identifier' => $phone, + ]))); + $user->setAttribute('targets', [...$user->getAttribute('targets', []), $target]); + } catch (Duplicate) { + $existingTarget = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$phone]), + ]); + $user->setAttribute('targets', [...$user->getAttribute('targets', []), $existingTarget]); + } + $dbForProject->deleteCachedDocument('users', $user->getId()); } $secret = Auth::codeGenerator(); @@ -2102,25 +2119,25 @@ App::patch('/v1/account/email') ->setAttribute('passwordUpdate', DateTime::now()); } - $target = $dbForProject->findOne('targets', [ + $target = Authorization::skip(fn () => $dbForProject->findOne('targets', [ Query::equal('identifier', [$email]), - ]); + ])); - if ($target && !$target->isEmpty()) { + if ($target instanceof Document && !$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } - /** - * @var Document $oldTarget - */ - $oldTarget = $user->find('identifier', $oldEmail, 'targets'); - - if ($oldTarget !== false && !$oldTarget->isEmpty()) { - $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)); - } - try { $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); + /** + * @var Document $oldTarget + */ + $oldTarget = $user->find('identifier', $oldEmail, 'targets'); + + if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { + Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email))); + } + $dbForProject->deleteCachedDocument('users', $user->getId()); } catch (Duplicate) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -2165,18 +2182,15 @@ App::patch('/v1/account/phone') throw new Exception(Exception::USER_INVALID_CREDENTIALS); } - $target = $dbForProject->findOne('targets', [ + $target = Authorization::skip(fn () => $dbForProject->findOne('targets', [ Query::equal('identifier', [$phone]), - ]); + ])); - if ($target && !$target->isEmpty()) { + if ($target instanceof Document && !$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } - /** - * @var Document $oldTarget - */ - $oldTarget = $user->find('identifier', $user->getAttribute('phone'), 'targets'); + $oldPhone = $user->getAttribute('phone'); $user ->setAttribute('phone', $phone) @@ -2191,12 +2205,17 @@ App::patch('/v1/account/phone') ->setAttribute('passwordUpdate', DateTime::now()); } - if ($oldTarget !== false && !$oldTarget->isEmpty()) { - $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone)); - } - try { $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); + /** + * @var Document $oldTarget + */ + $oldTarget = $user->find('identifier', $oldPhone, 'targets'); + + if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { + Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone))); + } + $dbForProject->deleteCachedDocument('users', $user->getId()); } catch (Duplicate $th) { throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS); } diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 0c1edb6a96..0b099cb8d3 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -99,6 +99,42 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'memberships' => null, 'search' => implode(' ', [$userId, $email, $phone, $name]), ])); + + if ($email) { + try { + $target = $dbForProject->createDocument('targets', new Document([ + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerType' => 'email', + 'identifier' => $email, + ])); + $user->setAttribute('targets', [...$user->getAttribute('targets', []), $target]); + } catch (Duplicate) { + $existingTarget = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$email]), + ]); + $user->setAttribute('targets', [...$user->getAttribute('targets', []), $existingTarget]); + } + } + + if ($phone) { + try { + $target = $dbForProject->createDocument('targets', new Document([ + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerType' => 'sms', + 'identifier' => $phone, + ])); + $user->setAttribute('targets', [...$user->getAttribute('targets', []), $target]); + } catch (Duplicate) { + $existingTarget = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$phone]), + ]); + $user->setAttribute('targets', [...$user->getAttribute('targets', []), $existingTarget]); + } + } + + $dbForProject->deleteCachedDocument('users', $user->getId()); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); } @@ -399,10 +435,11 @@ App::post('/v1/users/:userId/targets') ->param('providerType', '', new WhiteList(['email', 'sms', 'push']), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) + ->param('name', '', new Text(128), 'Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.', true) ->inject('queueForEvents') ->inject('response') ->inject('dbForProject') - ->action(function (string $targetId, string $userId, string $providerType, string $identifier, string $providerId, Event $queueForEvents, Response $response, Database $dbForProject) { + ->action(function (string $targetId, string $userId, string $providerType, string $identifier, string $providerId, string $name, Event $queueForEvents, Response $response, Database $dbForProject) { $targetId = $targetId == 'unique()' ? ID::unique() : $targetId; $provider = new Document(); @@ -455,6 +492,7 @@ App::post('/v1/users/:userId/targets') 'userId' => $userId, 'userInternalId' => $user->getInternalId(), 'identifier' => $identifier, + 'name' => ($name !== '') ? $name : null, ])); } catch (Duplicate) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); @@ -801,7 +839,7 @@ App::get('/v1/users/:userId/targets') if ($cursor) { $targetId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); + $cursorDocument = $dbForProject->getDocument('targets', $targetId); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Target '{$targetId}' for the 'cursor' value not found."); @@ -1119,6 +1157,16 @@ App::patch('/v1/users/:userId/email') throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } + $target = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$email]), + ]); + + if ($target && !$target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + + $oldEmail = $user->getAttribute('email'); + $user ->setAttribute('email', $email) ->setAttribute('emailVerification', false) @@ -1127,6 +1175,15 @@ App::patch('/v1/users/:userId/email') try { $user = $dbForProject->updateDocument('users', $user->getId(), $user); + /** + * @var Document $oldTarget + */ + $oldTarget = $user->find('identifier', $oldEmail, 'targets'); + + if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { + $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)); + } + $dbForProject->deleteCachedDocument('users', $user->getId()); } catch (Duplicate $th) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -1164,13 +1221,32 @@ App::patch('/v1/users/:userId/phone') throw new Exception(Exception::USER_NOT_FOUND); } + $oldPhone = $user->getAttribute('phone'); + $user ->setAttribute('phone', $number) ->setAttribute('phoneVerification', false) ; + $target = $dbForProject->findOne('targets', [ + Query::equal('identifier', [$number]), + ]); + + if ($target && !$target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); + } + try { $user = $dbForProject->updateDocument('users', $user->getId(), $user); + /** + * @var Document $oldTarget + */ + $oldTarget = $user->find('identifier', $oldPhone, 'targets'); + + if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) { + $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $number)); + } + $dbForProject->deleteCachedDocument('users', $user->getId()); } catch (Duplicate $th) { throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS); } @@ -1266,12 +1342,13 @@ App::patch('/v1/users/:userId/targets/:targetId') ->label('sdk.response.model', Response::MODEL_TARGET) ->param('userId', '', new UID(), 'User ID.') ->param('targetId', '', new UID(), 'Target ID.') - ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true) + ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) + ->param('name', '', new Text(128), 'Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.', true) ->inject('queueForEvents') ->inject('response') ->inject('dbForProject') - ->action(function (string $userId, string $targetId, string $providerId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) { + ->action(function (string $userId, string $targetId, string $identifier, string $providerId, string $name, Event $queueForEvents, Response $response, Database $dbForProject) { $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { @@ -1324,6 +1401,10 @@ App::patch('/v1/users/:userId/targets/:targetId') $target->setAttribute('providerInternalId', $provider->getInternalId()); } + if ($name) { + $target->setAttribute('name', $name); + } + $target = $dbForProject->updateDocument('targets', $target->getId(), $target); $dbForProject->deleteCachedDocument('users', $user->getId()); diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 8488d8a9e4..0414bbaf59 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -107,7 +107,7 @@ class Messaging extends Action $recipients = \array_merge($recipients, $targets); } - $internalProvider = $dbForProject->findOne('providers', [ + $primaryProvider = $dbForProject->findOne('providers', [ Query::equal('enabled', [true]), Query::equal('type', [$recipients[0]->getAttribute('providerType')]), ]); @@ -124,30 +124,32 @@ class Messaging extends Action foreach ($recipients as $recipient) { $providerId = $recipient->getAttribute('providerId'); - if (!$providerId) { - $providerId = $internalProvider->getId(); + if (!$providerId && $primaryProvider instanceof Document && !$primaryProvider->isEmpty()) { + $providerId = $primaryProvider->getId(); } - if (!isset($identifiersByProviderId[$providerId])) { - $identifiersByProviderId[$providerId] = []; + if ($providerId) { + if (!isset($identifiersByProviderId[$providerId])) { + $identifiersByProviderId[$providerId] = []; + } + $identifiersByProviderId[$providerId][] = $recipient->getAttribute('identifier'); } - $identifiersByProviderId[$providerId][] = $recipient->getAttribute('identifier'); } /** * @var array[] $results */ - $results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $internalProvider, $message, $dbForProject) { - return function () use ($providerId, $identifiersByProviderId, $providers, $internalProvider, $message, $dbForProject) { + $results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $primaryProvider, $message, $dbForProject) { + return function () use ($providerId, $identifiersByProviderId, $providers, $primaryProvider, $message, $dbForProject) { $provider = new Document(); - if ($internalProvider->getId() === $providerId) { - $provider = $internalProvider; + if ($primaryProvider->getId() === $providerId) { + $provider = $primaryProvider; } else { $provider = $dbForProject->getDocument('providers', $providerId, [Query::equal('enabled', [true])]); if ($provider->isEmpty()) { - $provider = $internalProvider; + $provider = $primaryProvider; } } diff --git a/tests/e2e/Services/GraphQL/UsersTest.php b/tests/e2e/Services/GraphQL/UsersTest.php index 3b49337a63..1dac9123a9 100644 --- a/tests/e2e/Services/GraphQL/UsersTest.php +++ b/tests/e2e/Services/GraphQL/UsersTest.php @@ -247,7 +247,7 @@ class UsersTest extends Scope $this->assertEquals(200, $targets['headers']['status-code']); $this->assertIsArray($targets['body']['data']['usersListTargets']); - $this->assertCount(1, $targets['body']['data']['usersListTargets']['targets']); + $this->assertCount(2, $targets['body']['data']['usersListTargets']['targets']); } /** diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index 70230b8c8a..7d22f23251 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -23,6 +23,7 @@ trait UsersBase 'password' => 'password', 'name' => 'Cristiano Ronaldo', ], false); + $this->assertEquals($user['headers']['status-code'], 201); // Test empty prefs is object not array $bodyString = $user['body']; @@ -1279,7 +1280,7 @@ trait UsersBase 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(1, \count($response['body']['targets'])); + $this->assertEquals(2, \count($response['body']['targets'])); } /** @@ -1313,7 +1314,7 @@ trait UsersBase ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(0, $response['body']['total']); + $this->assertEquals(1, $response['body']['total']); } /** From 4bc23afc6586ab94a9733ea0e2816efc1e9fa856 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 29 Nov 2023 17:05:37 +1300 Subject: [PATCH 184/196] Add constants for message types --- app/controllers/api/account.php | 6 +++--- app/controllers/api/users.php | 12 ++++++------ app/init.php | 10 +++++++--- src/Appwrite/Platform/Workers/Messaging.php | 16 ++++++++-------- src/Appwrite/Utopia/Response/Model/Provider.php | 2 +- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index eda29656fe..6a06e2a09e 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -157,7 +157,7 @@ App::post('/v1/account') ], 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), - 'providerType' => 'email', + 'providerType' => MESSAGE_TYPE_EMAIL, 'identifier' => $email, ]))); $user->setAttribute('targets', [$target]); @@ -678,7 +678,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ], 'userId' => $userDoc->getId(), 'userInternalId' => $userDoc->getInternalId(), - 'providerType' => 'email', + 'providerType' => MESSAGE_TYPE_EMAIL, 'identifier' => $email, ])); } catch (Duplicate) { @@ -1732,7 +1732,7 @@ App::post('/v1/account/targets/push') ], 'providerId' => $providerId ?? null, 'providerInternalId' => $provider->getInternalId() ?? null, - 'providerType' => 'push', + 'providerType' => MESSAGE_TYPE_PUSH, 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), 'identifier' => $identifier, diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 0c1edb6a96..92af97f950 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -396,7 +396,7 @@ App::post('/v1/users/:userId/targets') ->label('sdk.response.model', Response::MODEL_TARGET) ->param('targetId', '', new CustomId(), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('userId', '', new UID(), 'User ID.') - ->param('providerType', '', new WhiteList(['email', 'sms', 'push']), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.') + ->param('providerType', '', new WhiteList([MESSAGE_TYPE_EMAIL, MESSAGE_TYPE_SMS, MESSAGE_TYPE_PUSH]), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.') ->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)') ->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true) ->inject('queueForEvents') @@ -407,7 +407,7 @@ App::post('/v1/users/:userId/targets') $provider = new Document(); - if ($providerType === 'push') { + if ($providerType === MESSAGE_TYPE_PUSH) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -422,13 +422,13 @@ App::post('/v1/users/:userId/targets') throw new Exception(Exception::GENERAL_INVALID_EMAIL); } break; - case 'sms': + case MESSAGE_TYPE_SMS: $validator = new Phone(); if (!$validator->isValid($identifier)) { throw new Exception(Exception::GENERAL_INVALID_PHONE); } break; - case 'push': + case MESSAGE_TYPE_PUSH: break; default: throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); @@ -1298,13 +1298,13 @@ App::patch('/v1/users/:userId/targets/:targetId') throw new Exception(Exception::GENERAL_INVALID_EMAIL); } break; - case 'sms': + case MESSAGE_TYPE_SMS: $validator = new Phone(); if (!$validator->isValid($identifier)) { throw new Exception(Exception::GENERAL_INVALID_PHONE); } break; - case 'push': + case MESSAGE_TYPE_PUSH: break; default: throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); diff --git a/app/init.php b/app/init.php index 6f61b955f3..800b32fdd0 100644 --- a/app/init.php +++ b/app/init.php @@ -190,6 +190,10 @@ const MAX_OUTPUT_CHUNK_SIZE = 2 * 1024 * 1024; // 2MB // Function headers const FUNCTION_ALLOWLIST_HEADERS_REQUEST = ['content-type', 'agent', 'content-length', 'host']; const FUNCTION_ALLOWLIST_HEADERS_RESPONSE = ['content-type', 'content-length']; +// Message types +const MESSAGE_TYPE_EMAIL = 'email'; +const MESSAGE_TYPE_SMS = 'sms'; +const MESSAGE_TYPE_PUSH = 'push'; // Usage metrics const METRIC_TEAMS = 'teams'; const METRIC_USERS = 'users'; @@ -607,11 +611,11 @@ Database::addFilter( $data = \json_decode($message->getAttribute('data', []), true); if (\array_key_exists('subject', $data)) { - $searchValues = \array_merge($searchValues, [$data['subject'], 'email']); + $searchValues = \array_merge($searchValues, [$data['subject'], MESSAGE_TYPE_EMAIL]); } elseif (\array_key_exists('content', $data)) { - $searchValues = \array_merge($searchValues, [$data['content'], 'sms']); + $searchValues = \array_merge($searchValues, [$data['content'], MESSAGE_TYPE_SMS]); } else { - $searchValues = \array_merge($searchValues, [$data['title'], 'push']); + $searchValues = \array_merge($searchValues, [$data['title'], MESSAGE_TYPE_PUSH]); } $search = \implode(' ', \array_filter($searchValues)); diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 8488d8a9e4..200bb06212 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -67,7 +67,7 @@ class Messaging extends Action } if (!\is_null($payload['message']) && !\is_null($payload['recipients'])) { - if ($payload['providerType'] === 'SMS') { + if ($payload['providerType'] === MESSAGE_TYPE_SMS) { $this->processInternalSMSMessage(new Document($payload['message']), $payload['recipients']); } } else { @@ -155,9 +155,9 @@ class Messaging extends Action $identifiers = $identifiersByProviderId[$providerId]; $adapter = match ($provider->getAttribute('type')) { - 'sms' => $this->sms($provider), - 'push' => $this->push($provider), - 'email' => $this->email($provider), + MESSAGE_TYPE_SMS => $this->sms($provider), + MESSAGE_TYPE_PUSH => $this->push($provider), + MESSAGE_TYPE_EMAIL => $this->email($provider), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; @@ -173,9 +173,9 @@ class Messaging extends Action $messageData->setAttribute('to', $batch); $data = match ($provider->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($messageData, $provider), - 'push' => $this->buildPushMessage($messageData), - 'email' => $this->buildEmailMessage($messageData, $provider), + MESSAGE_TYPE_SMS => $this->buildSMSMessage($messageData, $provider), + MESSAGE_TYPE_PUSH => $this->buildPushMessage($messageData), + MESSAGE_TYPE_EMAIL => $this->buildEmailMessage($messageData, $provider), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; @@ -245,7 +245,7 @@ class Messaging extends Action $provider = new Document([ '$id' => ID::unique(), 'provider' => $host, - 'type' => 'sms', + 'type' => MESSAGE_TYPE_SMS, 'name' => 'Internal SMS', 'enabled' => true, 'credentials' => match ($host) { diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index f8a0514020..d3de061aab 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -50,7 +50,7 @@ class Provider extends Model 'type' => self::TYPE_STRING, 'description' => 'Type of provider.', 'default' => '', - 'example' => 'sms', + 'example' => MESSAGE_TYPE_SMS, ]) ->addRule('credentials', [ 'type' => self::TYPE_JSON, From 82c86c0ae2e9a0d44a1c18cd6c4e8252023544b9 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 29 Nov 2023 17:08:25 +1300 Subject: [PATCH 185/196] `deliveryTime` -> `scheduledAt` --- app/config/collections.php | 2 +- app/controllers/api/messaging.php | 68 +++++++++++++++---------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 7e715baa2c..d1db57c426 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1572,7 +1572,7 @@ $commonCollections = [ 'filters' => [], ], [ - '$id' => ID::custom('deliveryTime'), + '$id' => ID::custom('scheduledAt'), 'type' => Database::VAR_DATETIME, 'format' => '', 'size' => 0, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index f13b037b02..85be4242c9 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -101,7 +101,7 @@ App::post('/v1/messaging/providers/mailgun') '$id' => $providerId, 'name' => $name, 'provider' => 'mailgun', - 'type' => 'email', + 'type' => MESSAGE_TYPE_EMAIL, 'enabled' => $enabled, 'credentials' => $credentials, 'options' => $options, @@ -172,7 +172,7 @@ App::post('/v1/messaging/providers/sendgrid') '$id' => $providerId, 'name' => $name, 'provider' => 'sendgrid', - 'type' => 'email', + 'type' => MESSAGE_TYPE_EMAIL, 'enabled' => $enabled, 'credentials' => $credentials, 'options' => $options, @@ -249,7 +249,7 @@ App::post('/v1/messaging/providers/msg91') '$id' => $providerId, 'name' => $name, 'provider' => 'msg91', - 'type' => 'sms', + 'type' => MESSAGE_TYPE_SMS, 'enabled' => $enabled, 'credentials' => $credentials, 'options' => $options, @@ -326,7 +326,7 @@ App::post('/v1/messaging/providers/telesign') '$id' => $providerId, 'name' => $name, 'provider' => 'telesign', - 'type' => 'sms', + 'type' => MESSAGE_TYPE_SMS, 'enabled' => $enabled, 'credentials' => $credentials, 'options' => $options, @@ -403,7 +403,7 @@ App::post('/v1/messaging/providers/textmagic') '$id' => $providerId, 'name' => $name, 'provider' => 'textmagic', - 'type' => 'sms', + 'type' => MESSAGE_TYPE_SMS, 'enabled' => $enabled, 'credentials' => $credentials, 'options' => $options, @@ -480,7 +480,7 @@ App::post('/v1/messaging/providers/twilio') '$id' => $providerId, 'name' => $name, 'provider' => 'twilio', - 'type' => 'sms', + 'type' => MESSAGE_TYPE_SMS, 'enabled' => $enabled, 'credentials' => $credentials, 'options' => $from, @@ -557,7 +557,7 @@ App::post('/v1/messaging/providers/vonage') '$id' => $providerId, 'name' => $name, 'provider' => 'vonage', - 'type' => 'sms', + 'type' => MESSAGE_TYPE_SMS, 'enabled' => $enabled, 'credentials' => $credentials, 'options' => $options, @@ -617,7 +617,7 @@ App::post('/v1/messaging/providers/fcm') '$id' => $providerId, 'name' => $name, 'provider' => 'fcm', - 'type' => 'push', + 'type' => MESSAGE_TYPE_PUSH, 'enabled' => $enabled, 'credentials' => $credentials ]); @@ -703,7 +703,7 @@ App::post('/v1/messaging/providers/apns') '$id' => $providerId, 'name' => $name, 'provider' => 'apns', - 'type' => 'push', + 'type' => MESSAGE_TYPE_PUSH, 'enabled' => $enabled, 'credentials' => $credentials, ]); @@ -2211,7 +2211,7 @@ App::post('/v1/messaging/messages/email') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createEmail') + ->label('sdk.method', 'createEmailMessage') ->label('sdk.description', '/docs/references/messaging/create-email.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -2225,13 +2225,13 @@ App::post('/v1/messaging/messages/email') ->param('description', '', new Text(256), 'Description for message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, string $status, bool $html, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { @@ -2276,7 +2276,7 @@ App::post('/v1/messaging/messages/sms') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createSMS') + ->label('sdk.method', 'createSMSMessage') ->label('sdk.description', '/docs/references/messaging/create-sms.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -2288,13 +2288,13 @@ App::post('/v1/messaging/messages/sms') ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { @@ -2337,7 +2337,7 @@ App::post('/v1/messaging/messages/push') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createPushNotification') + ->label('sdk.method', 'createPushMessage') ->label('sdk.description', '/docs/references/messaging/create-push-notification.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -2357,13 +2357,13 @@ App::post('/v1/messaging/messages/push') ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { @@ -2409,7 +2409,7 @@ App::post('/v1/messaging/messages/push') 'users' => $users, 'targets' => $targets, 'description' => $description, - 'deliveryTime' => $deliveryTime, + 'scheduledAt' => $scheduledAt, 'data' => $pushData, 'status' => $status, ])); @@ -2603,13 +2603,13 @@ App::patch('/v1/messaging/messages/email/:messageId') ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2620,7 +2620,7 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('deliveryTime')) && $message->getAttribute('deliveryTime') < new \DateTime()) { + if (!is_null($message->getAttribute('scheduledAt')) && $message->getAttribute('scheduledAt') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } @@ -2660,8 +2660,8 @@ App::patch('/v1/messaging/messages/email/:messageId') $message->setAttribute('status', $status); } - if (!is_null($deliveryTime)) { - $message->setAttribute('deliveryTime', $deliveryTime); + if (!is_null($scheduledAt)) { + $message->setAttribute('scheduledAt', $scheduledAt); } $message = $dbForProject->updateDocument('messages', $message->getId(), $message); @@ -2701,13 +2701,13 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $content, string $status, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $content, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2718,7 +2718,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('deliveryTime')) && $message->getAttribute('deliveryTime') < new \DateTime()) { + if (!is_null($message->getAttribute('scheduledAt')) && $message->getAttribute('scheduledAt') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } @@ -2750,8 +2750,8 @@ App::patch('/v1/messaging/messages/sms/:messageId') $message->setAttribute('description', $description); } - if (!is_null($deliveryTime)) { - $message->setAttribute('deliveryTime', $deliveryTime); + if (!is_null($scheduledAt)) { + $message->setAttribute('scheduledAt', $scheduledAt); } $message = $dbForProject->updateDocument('messages', $message->getId(), $message); @@ -2798,13 +2798,13 @@ App::patch('/v1/messaging/messages/push/:messageId') ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) - ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) + ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2815,7 +2815,7 @@ App::patch('/v1/messaging/messages/push/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('deliveryTime')) && $message->getAttribute('deliveryTime') < new \DateTime()) { + if (!is_null($message->getAttribute('scheduledAt')) && $message->getAttribute('scheduledAt') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } @@ -2879,8 +2879,8 @@ App::patch('/v1/messaging/messages/push/:messageId') $message->setAttribute('description', $description); } - if (!is_null($deliveryTime)) { - $message->setAttribute('deliveryTime', $deliveryTime); + if (!is_null($scheduledAt)) { + $message->setAttribute('scheduledAt', $scheduledAt); } $message = $dbForProject->updateDocument('messages', $message->getId(), $message); From 4b58d08fd8f0b6609c7d6292018cdd50bb494755 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 29 Nov 2023 17:09:44 +1300 Subject: [PATCH 186/196] Add `providerType` to `Message` --- app/config/collections.php | 11 +++++ app/controllers/api/messaging.php | 38 ++++------------ src/Appwrite/Event/Messaging.php | 14 +++--- .../Utopia/Response/Model/Message.php | 8 +++- tests/e2e/Services/GraphQL/Base.php | 44 ++++++++++--------- 5 files changed, 57 insertions(+), 58 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index d1db57c426..cbaed36f71 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1505,6 +1505,17 @@ $commonCollections = [ '$id' => ID::custom('messages'), 'name' => 'Messages', 'attributes' => [ + [ + '$id' => ID::custom('providerType'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('description'), 'type' => Database::VAR_STRING, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 85be4242c9..411243d7b3 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -2240,6 +2240,7 @@ App::post('/v1/messaging/messages/email') $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, + 'providerType' => MESSAGE_TYPE_EMAIL, 'topics' => $topics, 'users' => $users, 'targets' => $targets, @@ -2303,6 +2304,7 @@ App::post('/v1/messaging/messages/sms') $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, + 'providerType' => MESSAGE_TYPE_SMS, 'topics' => $topics, 'users' => $users, 'targets' => $targets, @@ -2370,41 +2372,19 @@ App::post('/v1/messaging/messages/push') throw new Exception(Exception::MESSAGE_MISSING_TARGET); } - $pushData = [ - 'title' => $title, - 'body' => $body, - ]; + $pushData = []; - if (!is_null($data)) { - $pushData['data'] = $data; - } + $keys = ['title', 'body', 'data', 'action', 'icon', 'sound', 'color', 'tag', 'badge']; - if ($action) { - $pushData['action'] = $action; - } - - if ($icon) { - $pushData['icon'] = $icon; - } - - if ($sound) { - $pushData['sound'] = $sound; - } - - if ($color) { - $pushData['color'] = $color; - } - - if ($tag) { - $pushData['tag'] = $tag; - } - - if ($badge) { - $pushData['badge'] = $badge; + foreach ($keys as $key) { + if (!empty($$key)) { + $pushData[$key] = $$key; + } } $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, + 'providerType' => MESSAGE_TYPE_PUSH, 'topics' => $topics, 'users' => $users, 'targets' => $targets, diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index 62d41f8c3b..9201799355 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -11,7 +11,7 @@ class Messaging extends Event protected ?string $messageId = null; protected ?Document $message = null; protected ?array $recipients = null; - protected ?string $deliveryTime = null; + protected ?string $scheduledAt = null; protected ?string $providerType = null; @@ -117,14 +117,14 @@ class Messaging extends Event } /** - * Sets Delivery time for the messaging event. + * Sets Scheduled delivery time for the messaging event. * - * @param string $deliveryTime + * @param string $scheduledAt * @return self */ - public function setDeliveryTime(string $deliveryTime): self + public function setScheduledAt(string $scheduledAt): self { - $this->deliveryTime = $deliveryTime; + $this->scheduledAt = $scheduledAt; return $this; } @@ -134,9 +134,9 @@ class Messaging extends Event * * @return string */ - public function getDeliveryTime(): string + public function getScheduledAt(): string { - return $this->deliveryTime; + return $this->scheduledAt; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 27c70d7073..32c67b6936 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -29,6 +29,12 @@ class Message extends Any 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) + ->addRule('providerType', [ + 'type' => self::TYPE_STRING, + 'description' => 'Message provider type.', + 'default' => '', + 'example' => MESSAGE_TYPE_EMAIL, + ]) ->addRule('topics', [ 'type' => self::TYPE_STRING, 'description' => 'Topic IDs set as recipients.', @@ -50,7 +56,7 @@ class Message extends Any 'array' => true, 'example' => ['5e5ea5c16897e'], ]) - ->addRule('deliveryTime', [ + ->addRule('scheduledAt', [ 'type' => self::TYPE_DATETIME, 'description' => 'The scheduled time for message.', 'required' => false, diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 6939e6a9b5..2854d0bf42 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -2098,13 +2098,13 @@ trait Base } }'; case self::$CREATE_EMAIL: - return 'mutation createEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { - messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + return 'mutation createEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $scheduledAt: String) { + messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, scheduledAt: $scheduledAt) { _id topics users targets - deliveryTime + scheduledAt deliveredAt deliveryErrors deliveredTotal @@ -2113,13 +2113,13 @@ trait Base } }'; case self::$CREATE_SMS: - return 'mutation createSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String!, $status: String, $description: String, $deliveryTime: String) { - messagingCreateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation createSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String!, $status: String, $description: String, $scheduledAt: String) { + messagingCreateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, scheduledAt: $scheduledAt) { _id topics users targets - deliveryTime + scheduledAt deliveredAt deliveryErrors deliveredTotal @@ -2128,13 +2128,13 @@ trait Base } }'; case self::$CREATE_PUSH_NOTIFICATION: - return 'mutation createPushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { - messagingCreatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation createPushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $scheduledAt: String) { + messagingCreatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, scheduledAt: $scheduledAt) { _id topics users targets - deliveryTime + scheduledAt deliveredAt deliveryErrors deliveredTotal @@ -2148,10 +2148,11 @@ trait Base total messages { _id + providerType topics users targets - deliveryTime + scheduledAt deliveredAt deliveryErrors deliveredTotal @@ -2164,10 +2165,11 @@ trait Base return 'query getMessage($messageId: String!) { messagingGetMessage(messageId: $messageId) { _id + providerType topics users targets - deliveryTime + scheduledAt deliveredAt deliveryErrors deliveredTotal @@ -2176,13 +2178,13 @@ trait Base } }'; case self::$UPDATE_EMAIL: - return 'mutation updateEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { - messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + return 'mutation updateEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $scheduledAt: String) { + messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, scheduledAt: $scheduledAt) { _id topics users targets - deliveryTime + scheduledAt deliveredAt deliveryErrors deliveredTotal @@ -2191,13 +2193,13 @@ trait Base } }'; case self::$UPDATE_SMS: - return 'mutation updateSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String, $status: String, $description: String, $deliveryTime: String) { - messagingUpdateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation updateSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String, $status: String, $description: String, $scheduledAt: String) { + messagingUpdateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, scheduledAt: $scheduledAt) { _id topics users targets - deliveryTime + scheduledAt deliveredAt deliveryErrors deliveredTotal @@ -2206,13 +2208,13 @@ trait Base } }'; case self::$UPDATE_PUSH_NOTIFICATION: - return 'mutation updatePushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { - messagingUpdatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation updatePushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $scheduledAt: String) { + messagingUpdatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, scheduledAt: $scheduledAt) { _id topics users targets - deliveryTime + scheduledAt deliveredAt deliveryErrors deliveredTotal @@ -2472,7 +2474,7 @@ trait Base protected string $stdout = ''; protected string $stderr = ''; - protected function packageCode($folder) + protected function packageCode($folder): void { Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr); } From 042c1a725f7a7add6e77afcc381729e4c46a92c9 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 29 Nov 2023 17:10:53 +1300 Subject: [PATCH 187/196] `Message` extends `Model` instead of `Any` so rules are applied since `data` is not hoisted --- src/Appwrite/Utopia/Response/Model/Message.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 32c67b6936..bd9c8c6c55 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -5,8 +5,9 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\DateTime; +use Utopia\Database\Document as DatabaseDocument; -class Message extends Any +class Message extends Model { public function __construct() { From 43b8fc2c31ebe4645ec954a8d574637708988e87 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 29 Nov 2023 13:47:44 +0530 Subject: [PATCH 188/196] review changes --- app/controllers/api/users.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 0b099cb8d3..1cbb3e9632 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1161,7 +1161,7 @@ App::patch('/v1/users/:userId/email') Query::equal('identifier', [$email]), ]); - if ($target && !$target->isEmpty()) { + if ($target instanceof Document && !$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } @@ -1232,7 +1232,7 @@ App::patch('/v1/users/:userId/phone') Query::equal('identifier', [$number]), ]); - if ($target && !$target->isEmpty()) { + if ($target instanceof Document && !$target->isEmpty()) { throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS); } From 739cc36fdc88a032f6f6d66d090fd85dae79fca7 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 29 Nov 2023 15:22:26 +0530 Subject: [PATCH 189/196] updated providerType wherever left to update --- app/controllers/api/account.php | 6 +-- app/init.php | 5 ++- composer.lock | 75 +++++++++++++++++---------------- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index c80d2d4387..68e3261a8d 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1315,7 +1315,7 @@ App::post('/v1/account/sessions/phone') $target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([ 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), - 'providerType' => 'sms', + 'providerType' => MESSAGE_TYPE_SMS, 'identifier' => $phone, ]))); $user->setAttribute('targets', [...$user->getAttribute('targets', []), $target]); @@ -1374,7 +1374,7 @@ App::post('/v1/account/sessions/phone') $queueForMessaging ->setMessage($messageDoc) ->setRecipients([$phone]) - ->setProviderType('SMS') + ->setProviderType(MESSAGE_TYPE_SMS) ->setProject($project) ->trigger(); @@ -3100,7 +3100,7 @@ App::post('/v1/account/verification/phone') $queueForMessaging ->setMessage($messageDoc) ->setRecipients([$user->getAttribute('phone')]) - ->setProviderType('SMS') + ->setProviderType(MESSAGE_TYPE_SMS) ->setProject($project) ->trigger(); diff --git a/app/init.php b/app/init.php index 800b32fdd0..4dfdcaf108 100644 --- a/app/init.php +++ b/app/init.php @@ -609,10 +609,11 @@ Database::addFilter( ]; $data = \json_decode($message->getAttribute('data', []), true); + $providerType = $message->getAttribute('providerType', ''); - if (\array_key_exists('subject', $data)) { + if ($providerType === MESSAGE_TYPE_EMAIL) { $searchValues = \array_merge($searchValues, [$data['subject'], MESSAGE_TYPE_EMAIL]); - } elseif (\array_key_exists('content', $data)) { + } elseif ($providerType === MESSAGE_TYPE_SMS) { $searchValues = \array_merge($searchValues, [$data['content'], MESSAGE_TYPE_SMS]); } else { $searchValues = \array_merge($searchValues, [$data['title'], MESSAGE_TYPE_PUSH]); diff --git a/composer.lock b/composer.lock index afa71aaf2b..16f44a6357 100644 --- a/composer.lock +++ b/composer.lock @@ -156,11 +156,11 @@ }, { "name": "appwrite/php-runtimes", - "version": "0.13.1", + "version": "0.13.2", "source": { "type": "git", "url": "https://github.com/appwrite/runtimes.git", - "reference": "b584d19cdcd82737d0ee5c34d23de791f5ed3610" + "reference": "214a37c2c66e0f2bc9c30fdfde66955d9fd084a1" }, "require": { "php": ">=8.0", @@ -195,7 +195,7 @@ "php", "runtimes" ], - "time": "2023-10-16T15:39:53+00:00" + "time": "2023-11-22T15:36:00+00:00" }, { "name": "chillerlan/php-qrcode", @@ -1465,7 +1465,7 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.3.0", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -1512,7 +1512,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" }, "funding": [ { @@ -2217,16 +2217,16 @@ }, { "name": "utopia-php/logger", - "version": "0.3.1", + "version": "0.3.2", "source": { "type": "git", "url": "https://github.com/utopia-php/logger.git", - "reference": "de623f1ec1c672c795d113dd25c5bf212f7ef4fc" + "reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/logger/zipball/de623f1ec1c672c795d113dd25c5bf212f7ef4fc", - "reference": "de623f1ec1c672c795d113dd25c5bf212f7ef4fc", + "url": "https://api.github.com/repos/utopia-php/logger/zipball/ba763c10688fe2ed715ad2bed3f13d18dfec6253", + "reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253", "shasum": "" }, "require": { @@ -2264,9 +2264,9 @@ ], "support": { "issues": "https://github.com/utopia-php/logger/issues", - "source": "https://github.com/utopia-php/logger/tree/0.3.1" + "source": "https://github.com/utopia-php/logger/tree/0.3.2" }, - "time": "2023-02-10T15:52:50+00:00" + "time": "2023-11-22T14:45:43+00:00" }, { "name": "utopia-php/messaging", @@ -3136,16 +3136,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.35.2", + "version": "0.35.3", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "2dfe0430a64ffd2a07078d83b20144b871acac3b" + "reference": "4c431d5324a8f8cd2cab9a5515c170a5b427d44c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/2dfe0430a64ffd2a07078d83b20144b871acac3b", - "reference": "2dfe0430a64ffd2a07078d83b20144b871acac3b", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/4c431d5324a8f8cd2cab9a5515c170a5b427d44c", + "reference": "4c431d5324a8f8cd2cab9a5515c170a5b427d44c", "shasum": "" }, "require": { @@ -3181,9 +3181,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.35.2" + "source": "https://github.com/appwrite/sdk-generator/tree/0.35.3" }, - "time": "2023-09-14T14:59:50+00:00" + "time": "2023-11-12T05:56:27+00:00" }, { "name": "doctrine/deprecations", @@ -3890,16 +3890,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.2", + "version": "1.24.4", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "bcad8d995980440892759db0c32acae7c8e79442" + "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442", - "reference": "bcad8d995980440892759db0c32acae7c8e79442", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6bd0c26f3786cd9b7c359675cb789e35a8e07496", + "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496", "shasum": "" }, "require": { @@ -3931,9 +3931,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.24.2" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.4" }, - "time": "2023-09-26T12:28:12+00:00" + "time": "2023-11-26T18:29:22+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5676,16 +5676,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", "shasum": "" }, "require": { @@ -5714,7 +5714,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.2" }, "funding": [ { @@ -5722,30 +5722,31 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2023-11-20T00:12:19+00:00" }, { "name": "twig/twig", - "version": "v3.7.1", + "version": "v3.8.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" + "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", + "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3" + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php80": "^1.22" }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3" + "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0" }, "type": "library", "autoload": { @@ -5781,7 +5782,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.7.1" + "source": "https://github.com/twigphp/Twig/tree/v3.8.0" }, "funding": [ { @@ -5793,7 +5794,7 @@ "type": "tidelift" } ], - "time": "2023-08-28T11:09:02+00:00" + "time": "2023-11-21T18:54:41+00:00" } ], "aliases": [], From 6ead6f80943797a0910eeb6dbf74aecd07aa8f17 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 1 Dec 2023 03:39:43 +0530 Subject: [PATCH 190/196] misc changes allow filtering by providerType, userId in subscribers. Adds cancelled status for message status. Validate targets when creating message. delete all targets when user is deleted. fix twilio bug. add db env vars in messaging worker compose.phtml --- app/config/collections.php | 47 +++++++++ app/config/errors.php | 15 +++ app/controllers/api/messaging.php | 95 +++++++++++++++++-- app/controllers/api/users.php | 4 + app/views/install/compose.phtml | 10 +- src/Appwrite/Extend/Exception.php | 4 + src/Appwrite/Platform/Workers/Deletes.php | 5 + src/Appwrite/Platform/Workers/Messaging.php | 6 +- .../Validator/Queries/Subscribers.php | 4 +- .../Utopia/Response/Model/Message.php | 2 +- .../Utopia/Response/Model/Subscriber.php | 12 +++ src/Appwrite/Utopia/Response/Model/Target.php | 2 +- 12 files changed, 192 insertions(+), 14 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index cbaed36f71..77e2be68ba 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1755,6 +1755,28 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('userId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('topicId'), 'type' => Database::VAR_STRING, @@ -1777,6 +1799,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('providerType'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ @@ -1793,6 +1826,20 @@ $commonCollections = [ 'lengths' => [], 'orders' => [], ], + [ + '$id' => ID::custom('_key_userId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['_key_userId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_userInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userInternalId'], + 'lengths' => [], + 'orders' => [], + ], [ '$id' => ID::custom('_key_topicId'), 'type' => Database::INDEX_KEY, diff --git a/app/config/errors.php b/app/config/errors.php index 3c0b67c76a..64143dc538 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -847,5 +847,20 @@ return [ 'description' => 'Message with the requested ID has already been scheduled for delivery.', 'code' => 400, ], + Exception::MESSAGE_TARGET_NOT_EMAIL => [ + 'name' => Exception::MESSAGE_TARGET_NOT_EMAIL, + 'description' => 'Message with the target ID is not an Email target:', + 'code' => 400, + ], + Exception::MESSAGE_TARGET_NOT_SMS => [ + 'name' => Exception::MESSAGE_TARGET_NOT_SMS, + 'description' => 'Message with the target ID is not an SMS target:', + 'code' => 400, + ], + Exception::MESSAGE_TARGET_NOT_PUSH => [ + 'name' => Exception::MESSAGE_TARGET_NOT_PUSH, + 'description' => 'Message with the target ID is not a Push target:', + 'code' => 400, + ], ]; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 411243d7b3..682da9995e 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -483,7 +483,7 @@ App::post('/v1/messaging/providers/twilio') 'type' => MESSAGE_TYPE_SMS, 'enabled' => $enabled, 'credentials' => $credentials, - 'options' => $from, + 'options' => $options, ]); try { @@ -1952,6 +1952,9 @@ App::post('/v1/messaging/topics/:topicId/subscribers') 'topicInternalId' => $topic->getInternalId(), 'targetId' => $targetId, 'targetInternalId' => $target->getInternalId(), + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), + 'providerType' => $target->getAttribute('providerType'), ]); try { @@ -1987,11 +1990,16 @@ App::get('/v1/messaging/topics/:topicId/subscribers') ->label('sdk.response.model', Response::MODEL_SUBSCRIBER_LIST) ->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.') ->param('queries', [], new Subscribers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') ->inject('response') ->action(function (string $topicId, array $queries, Database $dbForProject, Response $response) { $queries = Query::parseQueries($queries); + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + $topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId)); if ($topic->isEmpty()) { @@ -2223,7 +2231,7 @@ App::post('/v1/messaging/messages/email') ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for message.', true) - ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') @@ -2238,6 +2246,18 @@ App::post('/v1/messaging/messages/email') throw new Exception(Exception::MESSAGE_MISSING_TARGET); } + foreach ($targets as $target) { + $targetDocument = $dbForProject->getDocument('targets', $target); + + if ($targetDocument->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_EMAIL) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL . ' ' . $targetDocument->getId()); + } + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, 'providerType' => MESSAGE_TYPE_EMAIL, @@ -2288,7 +2308,7 @@ App::post('/v1/messaging/messages/sms') ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) - ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') @@ -2302,6 +2322,18 @@ App::post('/v1/messaging/messages/sms') throw new Exception(Exception::MESSAGE_MISSING_TARGET); } + foreach ($targets as $target) { + $targetDocument = $dbForProject->getDocument('targets', $target); + + if ($targetDocument->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_SMS) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_SMS . ' ' . $targetDocument->getId()); + } + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, 'providerType' => MESSAGE_TYPE_SMS, @@ -2358,7 +2390,7 @@ App::post('/v1/messaging/messages/push') ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) - ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') @@ -2372,6 +2404,18 @@ App::post('/v1/messaging/messages/push') throw new Exception(Exception::MESSAGE_MISSING_TARGET); } + foreach ($targets as $target) { + $targetDocument = $dbForProject->getDocument('targets', $target); + + if ($targetDocument->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_PUSH) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_PUSH . ' ' . $targetDocument->getId()); + } + } + $pushData = []; $keys = ['title', 'body', 'data', 'action', 'icon', 'sound', 'color', 'tag', 'badge']; @@ -2581,7 +2625,7 @@ App::patch('/v1/messaging/messages/email/:messageId') ->param('subject', '', new Text(998), 'Email Subject.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) - ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('status', '', new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') @@ -2613,6 +2657,18 @@ App::patch('/v1/messaging/messages/email/:messageId') } if (!\is_null($targets)) { + foreach ($targets as $target) { + $targetDocument = $dbForProject->getDocument('targets', $target); + + if ($targetDocument->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_EMAIL) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL . ' ' . $targetDocument->getId()); + } + } + $message->setAttribute('targets', $targets); } @@ -2680,7 +2736,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->param('targets', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) - ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('status', '', new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') @@ -2711,6 +2767,18 @@ App::patch('/v1/messaging/messages/sms/:messageId') } if (!\is_null($targets)) { + foreach ($targets as $target) { + $targetDocument = $dbForProject->getDocument('targets', $target); + + if ($targetDocument->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_SMS) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_SMS . ' ' . $targetDocument->getId()); + } + } + $message->setAttribute('targets', $targets); } @@ -2777,7 +2845,8 @@ App::patch('/v1/messaging/messages/push/:messageId') ->param('sound', '', new Text(256), 'Sound for push notification. Available only for Android and IOS Platform.', true) ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) - ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) + ->param('status', '', new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') @@ -2808,6 +2877,18 @@ App::patch('/v1/messaging/messages/push/:messageId') } if (!\is_null($targets)) { + foreach ($targets as $target) { + $targetDocument = $dbForProject->getDocument('targets', $target); + + if ($targetDocument->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } + + if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_PUSH) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_PUSH . ' ' . $targetDocument->getId()); + } + } + $message->setAttribute('targets', $targets); } diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 4312ac13da..8a71f33d8b 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1397,6 +1397,10 @@ App::patch('/v1/users/:userId/targets/:targetId') throw new Exception(Exception::PROVIDER_NOT_FOUND); } + if ($provider->getAttribute('type') !== $target->getAttribute('providerType')) { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); + } + $target->setAttribute('providerId', $provider->getId()); $target->setAttribute('providerInternalId', $provider->getInternalId()); } diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 898b46b3a5..252b5b6bd7 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -521,14 +521,20 @@ services: environment: - _APP_ENV - _APP_WORKER_PER_CORE + - _APP_OPENSSL_KEY_V1 - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_SMS_PROVIDER - - _APP_SMS_FROM + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG + - _APP_SMS_FROM + - _APP_SMS_PROVIDER appwrite-worker-migrations: image: /: diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 61ea597941..5c928569aa 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -256,6 +256,10 @@ class Exception extends \Exception public const MESSAGE_MISSING_TARGET = 'message_missing_target'; public const MESSAGE_ALREADY_SENT = 'message_already_sent'; public const MESSAGE_ALREADY_SCHEDULED = 'message_already_scheduled'; + public const MESSAGE_TARGET_NOT_EMAIL = 'message_target_not_email'; + public const MESSAGE_TARGET_NOT_SMS = 'message_target_not_sms'; + public const MESSAGE_TARGET_NOT_PUSH = 'message_target_not_push'; + protected string $type = ''; protected array $errors = []; diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 74365bad86..9a9e965f37 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -556,6 +556,11 @@ class Deletes extends Action $this->deleteByGroup('identities', [ Query::equal('userInternalId', [$userInternalId]) ], $dbForProject); + + // Delete targets + $this->deleteByGroup('targets', [ + Query::equal('userInternalId', [$userInternalId]) + ], $dbForProject); } /** diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 36647e9b7a..8f945e947f 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -91,14 +91,16 @@ class Messaging extends Action if (\count($topicsId) > 0) { $topics = $dbForProject->find('topics', [Query::equal('$id', $topicsId)]); foreach ($topics as $topic) { - $recipients = \array_merge($recipients, $topic->getAttribute('targets')); + $targets = \array_filter($topic->getAttribute('targets'), fn (Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType')); + $recipients = \array_merge($recipients, $targets); } } if (\count($usersId) > 0) { $users = $dbForProject->find('users', [Query::equal('$id', $usersId)]); foreach ($users as $user) { - $recipients = \array_merge($recipients, $user->getAttribute('targets')); + $targets = \array_filter($user->getAttribute('targets'), fn (Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType')); + $recipients = \array_merge($recipients, $targets); } } diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php index 55bb455903..05e08a75a7 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Subscribers.php @@ -6,7 +6,9 @@ class Subscribers extends Base { public const ALLOWED_ATTRIBUTES = [ 'targetId', - 'topicId' + 'topicId', + 'userId', + 'providerType' ]; /** diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index bd9c8c6c55..791c87933f 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -98,7 +98,7 @@ class Message extends Model 'type' => self::TYPE_STRING, 'description' => 'Status of delivery.', 'default' => 'processing', - 'example' => 'Message status can be one of the following: processing, sent, failed.', + 'example' => 'Message status can be one of the following: processing, sent, cancelled, failed.', ]) ->addRule('description', [ 'type' => self::TYPE_STRING, diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index e699df876c..8c3a4c7a49 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -49,6 +49,12 @@ class Subscriber extends Model 'userId' => '5e5ea5c16897e', ], ]) + ->addRule('userId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Topic ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) ->addRule('userName', [ 'type' => self::TYPE_STRING, 'description' => 'User Name.', @@ -60,6 +66,12 @@ class Subscriber extends Model 'description' => 'Topic ID.', 'default' => '', 'example' => '259125845563242502', + ]) + ->addRule('providerType', [ + 'type' => self::TYPE_STRING, + 'description' => 'The target provider type. Can be one of the following: `email`, `sms` or `push`.', + 'default' => '', + 'example' => MESSAGE_TYPE_EMAIL, ]); } diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php index a92d1b34ca..d180b6c4c4 100644 --- a/src/Appwrite/Utopia/Response/Model/Target.php +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -51,7 +51,7 @@ class Target extends Model 'type' => self::TYPE_STRING, 'description' => 'The target provider type. Can be one of the following: `email`, `sms` or `push`.', 'default' => '', - 'example' => 'email', + 'example' => MESSAGE_TYPE_EMAIL, ]) ->addRule('identifier', [ 'type' => self::TYPE_STRING, From 81ec4ff9bc1b2f3029d4d753b8abca5439eb5147 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 1 Dec 2023 03:51:03 +0530 Subject: [PATCH 191/196] fix typo in userId index in targets --- app/config/collections.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/collections.php b/app/config/collections.php index 77e2be68ba..b3e3417555 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1829,7 +1829,7 @@ $commonCollections = [ [ '$id' => ID::custom('_key_userId'), 'type' => Database::INDEX_KEY, - 'attributes' => ['_key_userId'], + 'attributes' => ['userId'], 'lengths' => [], 'orders' => [], ], From 5ed8bdae35f9e59acee18b58b30aee9132c12cbf Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 1 Dec 2023 03:55:29 +0530 Subject: [PATCH 192/196] fix search param in list subscribers endpoint --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 682da9995e..867f55ec0c 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1993,7 +1993,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $topicId, array $queries, Database $dbForProject, Response $response) { + ->action(function (string $topicId, array $queries, string $search, Database $dbForProject, Response $response) { $queries = Query::parseQueries($queries); if (!empty($search)) { From f9dd40120ecd19e4370a9a83100c16cdb5d41f26 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Mon, 4 Dec 2023 15:48:37 +0100 Subject: [PATCH 193/196] resolve update twilio provider --- app/controllers/api/messaging.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 867f55ec0c..33c85857d0 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1289,8 +1289,8 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) - ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) + ->param('accountSid', '', new Text(0), 'Twilio account secret ID.', true) + ->param('authToken', '', new Text(0), 'Twilio authentication token.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('queueForEvents') ->inject('dbForProject') From 54f574906cafe6b7ac7cc316be74b67b70a45c03 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 5 Dec 2023 12:22:32 +0100 Subject: [PATCH 194/196] review changes --- app/config/errors.php | 4 ++-- app/controllers/api/messaging.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 64143dc538..4c811dd53e 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -849,7 +849,7 @@ return [ ], Exception::MESSAGE_TARGET_NOT_EMAIL => [ 'name' => Exception::MESSAGE_TARGET_NOT_EMAIL, - 'description' => 'Message with the target ID is not an Email target:', + 'description' => 'Message with the target ID is not an email target:', 'code' => 400, ], Exception::MESSAGE_TARGET_NOT_SMS => [ @@ -859,7 +859,7 @@ return [ ], Exception::MESSAGE_TARGET_NOT_PUSH => [ 'name' => Exception::MESSAGE_TARGET_NOT_PUSH, - 'description' => 'Message with the target ID is not a Push target:', + 'description' => 'Message with the target ID is not a push target:', 'code' => 400, ], diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 33c85857d0..f0cb4dd966 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -2231,7 +2231,7 @@ App::post('/v1/messaging/messages/email') ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for message.', true) - ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) + ->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') @@ -2308,7 +2308,7 @@ App::post('/v1/messaging/messages/sms') ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) - ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) + ->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') @@ -2390,7 +2390,7 @@ App::post('/v1/messaging/messages/push') ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) - ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) + ->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') From 944e474ec4ce42d171dd664053683fe86fe85bca Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 15 Dec 2023 02:30:44 +1300 Subject: [PATCH 195/196] Fix max array size 1 --- app/controllers/api/messaging.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index f0cb4dd966..124bc2d219 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -2227,9 +2227,9 @@ App::post('/v1/messaging/messages/email') ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('subject', '', new Text(998), 'Email Subject.') ->param('content', '', new Text(64230), 'Email Content.') - ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) - ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) - ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for message.', true) ->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) @@ -2304,9 +2304,9 @@ App::post('/v1/messaging/messages/sms') ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('content', '', new Text(64230), 'SMS Content.') - ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) - ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) - ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) @@ -2379,9 +2379,9 @@ App::post('/v1/messaging/messages/push') ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('title', '', new Text(256), 'Title for push notification.') ->param('body', '', new Text(64230), 'Body for push notification.') - ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) - ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) - ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true) ->param('action', '', new Text(256), 'Action for push notification.', true) From 554e9f93b6ad3721d3e0721fb956d5a1742e28a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 2 Jan 2024 10:59:35 +0000 Subject: [PATCH 196/196] Implement max password length --- app/controllers/api/account.php | 6 +- composer.lock | 120 +++++++++--------- src/Appwrite/Auth/Validator/Password.php | 6 +- .../Auth/Validator/PasswordDictionary.php | 2 +- tests/e2e/Services/Account/AccountBase.php | 30 +++++ .../Auth/Validator/PasswordDictionaryTest.php | 11 ++ 6 files changed, 110 insertions(+), 65 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 68e3261a8d..4057634f5e 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -69,7 +69,7 @@ App::post('/v1/account') ->label('abuse-limit', 10) ->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('email', '', new Email(), 'User email.') - ->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be at least 8 chars.', false, ['project', 'passwordsDictionary']) + ->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be between 8 and 256 chars.', false, ['project', 'passwordsDictionary']) ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) ->inject('request') ->inject('response') @@ -2724,8 +2724,8 @@ App::put('/v1/account/recovery') ->label('abuse-key', 'url:{url},userId:{param-userId}') ->param('userId', '', new UID(), 'User ID.') ->param('secret', '', new Text(256), 'Valid reset token.') - ->param('password', '', new Password(), 'New user password. Must be at least 8 chars.') - ->param('passwordAgain', '', new Password(), 'Repeat new user password. Must be at least 8 chars.') + ->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be between 8 and 256 chars.', false, ['project', 'passwordsDictionary']) + ->param('passwordAgain', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'Repeat new user password. Must be between 8 and 256 chars.', false, ['project', 'passwordsDictionary']) ->inject('response') ->inject('user') ->inject('dbForProject') diff --git a/composer.lock b/composer.lock index 9f8e84e023..acd65d61a1 100644 --- a/composer.lock +++ b/composer.lock @@ -1906,16 +1906,16 @@ }, { "name": "utopia-php/database", - "version": "0.45.2", + "version": "0.45.3", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "dc789f2c1fd8b5ee07ff883e11c9ad7970824788" + "reference": "33b4e9a4a6c29f6bb7e108e134b283d585955789" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/dc789f2c1fd8b5ee07ff883e11c9ad7970824788", - "reference": "dc789f2c1fd8b5ee07ff883e11c9ad7970824788", + "url": "https://api.github.com/repos/utopia-php/database/zipball/33b4e9a4a6c29f6bb7e108e134b283d585955789", + "reference": "33b4e9a4a6c29f6bb7e108e134b283d585955789", "shasum": "" }, "require": { @@ -1956,9 +1956,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.45.2" + "source": "https://github.com/utopia-php/database/tree/0.45.3" }, - "time": "2023-11-15T03:38:47+00:00" + "time": "2023-12-28T11:12:26+00:00" }, { "name": "utopia-php/domains", @@ -2476,16 +2476,16 @@ }, { "name": "utopia-php/platform", - "version": "0.5.0", + "version": "0.5.1", "source": { "type": "git", "url": "https://github.com/utopia-php/platform.git", - "reference": "229a7b1fa1f39afd1532f7a515326a6afc222a26" + "reference": "3eceef0b6593fe0f7d2efd36d40402a395a4c285" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/platform/zipball/229a7b1fa1f39afd1532f7a515326a6afc222a26", - "reference": "229a7b1fa1f39afd1532f7a515326a6afc222a26", + "url": "https://api.github.com/repos/utopia-php/platform/zipball/3eceef0b6593fe0f7d2efd36d40402a395a4c285", + "reference": "3eceef0b6593fe0f7d2efd36d40402a395a4c285", "shasum": "" }, "require": { @@ -2493,7 +2493,7 @@ "ext-redis": "*", "php": ">=8.0", "utopia-php/cli": "0.15.*", - "utopia-php/framework": "0.31.*" + "utopia-php/framework": "0.*.*" }, "require-dev": { "laravel/pint": "1.2.*", @@ -2519,9 +2519,9 @@ ], "support": { "issues": "https://github.com/utopia-php/platform/issues", - "source": "https://github.com/utopia-php/platform/tree/0.5.0" + "source": "https://github.com/utopia-php/platform/tree/0.5.1" }, - "time": "2023-10-16T20:28:49+00:00" + "time": "2023-12-26T16:14:41+00:00" }, { "name": "utopia-php/pools", @@ -2742,16 +2742,16 @@ }, { "name": "utopia-php/storage", - "version": "0.18.1", + "version": "0.18.3", "source": { "type": "git", "url": "https://github.com/utopia-php/storage.git", - "reference": "983e6dee137012f9f57f126d3c79aab54e4e8824" + "reference": "faa0279519ac14f3501e8b138e0865ad9d12bff6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/storage/zipball/983e6dee137012f9f57f126d3c79aab54e4e8824", - "reference": "983e6dee137012f9f57f126d3c79aab54e4e8824", + "url": "https://api.github.com/repos/utopia-php/storage/zipball/faa0279519ac14f3501e8b138e0865ad9d12bff6", + "reference": "faa0279519ac14f3501e8b138e0865ad9d12bff6", "shasum": "" }, "require": { @@ -2791,9 +2791,9 @@ ], "support": { "issues": "https://github.com/utopia-php/storage/issues", - "source": "https://github.com/utopia-php/storage/tree/0.18.1" + "source": "https://github.com/utopia-php/storage/tree/0.18.3" }, - "time": "2023-10-24T14:44:19+00:00" + "time": "2023-12-31T11:45:12+00:00" }, { "name": "utopia-php/swoole", @@ -2904,23 +2904,23 @@ }, { "name": "utopia-php/vcs", - "version": "0.6.2", + "version": "0.6.4", "source": { "type": "git", "url": "https://github.com/utopia-php/vcs.git", - "reference": "f135291b87cb45335fc6608722e7f89894bc33ee" + "reference": "b2595a50a4897a8c88319240810055b7a96efd6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/vcs/zipball/f135291b87cb45335fc6608722e7f89894bc33ee", - "reference": "f135291b87cb45335fc6608722e7f89894bc33ee", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/b2595a50a4897a8c88319240810055b7a96efd6d", + "reference": "b2595a50a4897a8c88319240810055b7a96efd6d", "shasum": "" }, "require": { "adhocore/jwt": "^1.1", "php": ">=8.0", "utopia-php/cache": "^0.8.0", - "utopia-php/framework": "0.31.*" + "utopia-php/framework": "0.*.*" }, "require-dev": { "laravel/pint": "1.2.*", @@ -2947,9 +2947,9 @@ ], "support": { "issues": "https://github.com/utopia-php/vcs/issues", - "source": "https://github.com/utopia-php/vcs/tree/0.6.2" + "source": "https://github.com/utopia-php/vcs/tree/0.6.4" }, - "time": "2023-11-08T15:36:03+00:00" + "time": "2023-12-26T15:38:19+00:00" }, { "name": "utopia-php/websocket", @@ -3487,16 +3487,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "shasum": "" }, "require": { @@ -3537,9 +3537,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2023-12-10T21:03:43+00:00" }, { "name": "phar-io/manifest", @@ -3891,16 +3891,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.4", + "version": "1.24.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496" + "reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6bd0c26f3786cd9b7c359675cb789e35a8e07496", - "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fedf211ff14ec8381c9bf5714e33a7a552dd1acc", + "reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc", "shasum": "" }, "require": { @@ -3932,29 +3932,29 @@ "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.24.4" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.5" }, - "time": "2023-11-26T18:29:22+00:00" + "time": "2023-12-16T09:33:33+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "version": "9.2.30", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -4004,7 +4004,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" }, "funding": [ { @@ -4012,7 +4012,7 @@ "type": "github" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2023-12-22T06:47:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4651,20 +4651,20 @@ }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -4696,7 +4696,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -4704,7 +4704,7 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", @@ -4978,20 +4978,20 @@ }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -5023,7 +5023,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -5031,7 +5031,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", @@ -5847,5 +5847,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/src/Appwrite/Auth/Validator/Password.php b/src/Appwrite/Auth/Validator/Password.php index 93a9f74114..ffb72467e5 100644 --- a/src/Appwrite/Auth/Validator/Password.php +++ b/src/Appwrite/Auth/Validator/Password.php @@ -20,7 +20,7 @@ class Password extends Validator */ public function getDescription(): string { - return 'Password must be at least 8 characters'; + return 'Password must be between 8 and 256 characters long.'; } /** @@ -40,6 +40,10 @@ class Password extends Validator return false; } + if (\strlen($value) > 256) { + return false; + } + return true; } diff --git a/src/Appwrite/Auth/Validator/PasswordDictionary.php b/src/Appwrite/Auth/Validator/PasswordDictionary.php index 003d68bc73..e128f497f5 100644 --- a/src/Appwrite/Auth/Validator/PasswordDictionary.php +++ b/src/Appwrite/Auth/Validator/PasswordDictionary.php @@ -27,7 +27,7 @@ class PasswordDictionary extends Password */ public function getDescription(): string { - return 'Password must be at least 8 characters and should not be one of the commonly used password.'; + return 'Password must be between 8 and 265 characters long, and should not be one of the commonly used password.'; } /** diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index e6f5feaa84..fe9983d9b8 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -94,6 +94,36 @@ trait AccountBase $this->assertEquals($response['headers']['status-code'], 400); + $shortPassword = 'short'; + $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]), [ + 'userId' => ID::unique(), + 'email' => 'shortpass@appwrite.io', + 'password' => $shortPassword + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $longPassword = ''; + for ($i = 0; $i < 257; $i++) { // 256 is the limit + $longPassword .= 'p'; + } + + $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]), [ + 'userId' => ID::unique(), + 'email' => 'longpass@appwrite.io', + 'password' => $longPassword, + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + return [ 'id' => $id, 'email' => $email, diff --git a/tests/unit/Auth/Validator/PasswordDictionaryTest.php b/tests/unit/Auth/Validator/PasswordDictionaryTest.php index fd7f51ff16..5c8d47923c 100644 --- a/tests/unit/Auth/Validator/PasswordDictionaryTest.php +++ b/tests/unit/Auth/Validator/PasswordDictionaryTest.php @@ -24,5 +24,16 @@ class PasswordDictionaryTest extends TestCase $this->assertEquals($this->object->isValid('123456'), false); $this->assertEquals($this->object->isValid('password'), false); $this->assertEquals($this->object->isValid('myPasswordIsRight'), true); + + $pass = ''; // 256 chars + for ($i = 0; $i < 256; $i++) { + $pass .= 'p'; + } + + $this->assertEquals($this->object->isValid($pass), true); + + $pass .= 'p'; // 257 chars + + $this->assertEquals($this->object->isValid($pass), false); } }